Blog: Latest Entries (15):


VSCode: PHP Debugging

Es war ein harter Kampf.. aber ich war siegreich. Nachdem ich durch den Wechsel meines Arbeitgebers auch den Zugriff auf Intellij + PHP-Plugin einbüßen musste, bin ich jetzt vollständig auf VSCode gewechselt.

Wie ich XDebug + VSCode + Docker zum Laufen bekommen habe.

Dockerfile (nur der wichtige Teil):

RUN pecl install xdebug-2.8.0 && docker-php-ext-enable xdebug
RUN echo 'zend_extension="/usr/local/lib/php/extensions/no-debug-non-zts-20151012/xdebug.so"' >> /usr/local/etc/php/php.ini
RUN echo 'xdebug.remote_port=9000' >> /usr/local/etc/php/php.ini
RUN echo 'xdebug.remote_enable=1' >> /usr/local/etc/php/php.ini
RUN echo 'xdebug.remote_host=host.docker.internal' >> /usr/local/etc/php/php.ini


Lokale php.ini (ich habe 2.8.0 herunter geladen und als php_xdebug.dll gespeichert):

zend_extension=c:\php\ext\php_xdebug.dll

#.....

[XDebug]
xdebug.remote_enable = 1
xdebug.remote_autostart = 1


Dann habe ich dieses Plugin in VSCode installiert. Mit Hilfe dieses Boilerplate-Projekts habe ich mir eine passende .vscode/launch.json gebaut.


{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9000,
"pathMappings": {
"/var/www/html": "${workspaceFolder}/"
},
"xdebugSettings": {
"max_data": 65535,
"show_hidden": 1,
"max_children": 100,
"max_depth": 5
}
}
]
}


Dann VSCode neugeladen. Docker gestartet und in die Debug-Ansicht von VSCode gewechselt.

bbcode-image


Dort das ""Listen for XDebug" Profile starten und es sollte funktionieren.

bbcode-image


PHPStorm/Intellij ist da viel einfacher, weil man nicht selbst noch JSON-Dateien anlegen und editieren muss. Aber es läuft!


Shopware 6: Ein einfaches Beispiel-Plugin

Plugins für Shopware 6 zu schreiben ist an sich garnicht so unterschiedlich zu dem selben Vorgang für Shopware 5. Was nur anders geworden ist, dass Shopware eigene XMLs und Enlight-Components durch den Composer und Symfony abgelöst wurden. Man kann nun wirklich Namespaces definieren, die unabhängig vom Plugin-Namen sind und es ist kein Problem mehr den Composer mit Plugins zu verwenden, sondern es ist jetzt der zu gehende Weg.

Setup

Wie gehabt kann man sein Plugin unter custom/plugins anlegen.


custom/plugins/HPrOrderExample


Zu erst sollte man mit der composer.json anfangen.


{
"name": "hpr/order-example",
"description": "Order Example",
"version": "v1.0.1",
"license": "MIT",
"authors": [
{
"name": "Hannes Pries"
}
],
"require": {
"shopware/platform": "dev-master"
},
"type": "shopware-platform-plugin",
"autoload": {
"psr-4": {
"HPr\\OrderExample": "src/"
}
},
"extra": {
"shopware-plugin-class": "HPr\\OrderExample\\OrderExample",
"copyright": "(c) by Hannes Pries",
"label": {
"de-DE": "Order-Beispiel für SW6",
"en-GB": "Order-Example for SW6"
}
}
}


Wichtig in der composer.json ist einmal der PSR-4 Namespace den man auf das src/ Verzeichnis setzt und der "extra" Teil. Dort wird alles definiert, was mit Shopware zu tun hat. Hier wird auch die zentrale Plugin-Class angegeben, die nicht mehr wie in Shopware 5 den selben Namen des Verzeichnisses des Plugins haben muss. Auch sieht man hier dass der Namespace-Name nichts mehr mit dem Verzeichniss-Namen zu tun hat.


Wir könnten durch die composer.json das Plugin auch komplett außerhalb der Shopware-Installation entwickeln, weil die gesamte Plattform als Dependency eingebunden ist. Deswegen müssen wir auch einmal den Composer ausführen.


php composer install


Plugin programmieren
Nun fangen wir mit dem Schreiben des Plugins an.

Die Plugin-Klasse enthält erst einmal keine weitere Logik:


<?php
namespace HPr\OrderExample;

use Shopware\Core\Framework\Plugin;

class OrderExample extends Plugin{

}


Wir wollen auf ein Event reagieren. Dafür benutzen wir eine Subscriber-Klasse. Während man diese in Shopware 5 nicht unbedingt brauchte und alles in der Plugin-Klasse erldedigen konnte, muss man nun eine extra Klasse nutzen und diese auch in der services.xml eintragen. Die Id des Services ist der fullqualified-classname des Subscribers

src/Resources/services.xml

<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="HPr\OrderExample\Subscribers\OnOrderSaved">
<tag name="kernel.event_subscriber"/>
</service>
</services>
</container>

Resources ist vordefiniert, kann aber in der Plugin-Klasse angepasst werden, so dass diese Dateien auch in einem anderen Package liegen könnten.

src/Subscribers/OnOrderSaved

<?php
namespace HPr\OrderExample\Subscribers;

use Shopware\Core\Checkout\Order\OrderEvents;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class OnOrderSaved implements EventSubscriberInterface {
/**
* @return array The event names to listen to
*/
public static function getSubscribedEvents()
{
return [
OrderEvents::ORDER_WRITTEN_EVENT => ['dumpOrderData']
];
}

public function dumpOrderData(EntityWrittenEvent $event) {
file_put_contents('/var/test/orderdump.json', json_encode($event->getContext()));
}
}

Hier sieht man, dass nur noch Symfony benutzt wird und keine Shopware eigenen Events.

Wir schreiben einfach die Order-Entity, die gespeichert wurde in eine Datei. Dort können wir UUID und ähnliches der Order finden.

Das ganze kann man dann weiter ausbauen und auf andere Order-Events (die man alle in der OrderEvents.php finden kann) reagieren.

Installieren

Damit ist das Plugin auch schon soweit fertig. Den Composer haben wir schon ausgeführt (ansonsten müssen wir es spätestens jetzt machen).

Nun geht es über die UI oder die Console weiter. Dort wird das Plugin installiert und und aktiviert.

bbcode-image


bbcode-image


Wenn man nun eine Bestellung ausführt wird, deren Entity in die oben angegebene Datei geschrieben.

Alexa und das Küchen Licht

Heute wurde die Küche Tradfridi- und Alexarisiert. Beim Einrichten der Routinen kam es aber zu dem Problem, das "Alexa, Küchenlicht an" nur dazu führte, dass Alexa das nur damit quittierte "Das Gerät Küchenlicht konnte nicht gefunden werden". Das war seltsam denn z.B. "Alexa, Schlafzimmer Licht an" ohne Probleme funktionierte. "Küche Licht an" klingt aber doof. Vielleicht kommen einige jetzt schon auf die Lösung. "Alexa, Küchen Licht an" funktioniert. Also wenn man das Problem hat, einfach mal versuchen Worte auseinander zu schreiben.

bbcode-image


Über die Kämpfe mit dem Ikea Tradfri-System schreibe ich ein anders mal. Spoiler: Meine Nerven haben es nur knapp überlebt.

EasyComponent.JS: Framework Beispiel

Frameworks gelten ganz ganz oft als etwas sehr kompliziertes und mächtiges Werkzeug, das nur von wenigen auserwählten entwickelt und designed wird. Wenn ein Framework etwas nicht kann wird es meistens so hingenommen und darauf gehofft, dass es vielleicht doch noch irgendwann mal eingebaut wird. Meistens würde man sich nie trauen, sich dabei einzubringen oder einzumischen.

Man selbst ist ja einfacher "Anwender" und wie die eigenen Anwender, die das eigene Programm nutzen, das wieder das Framework nutzt, sollte man sich nicht die Dinge einmischen, von denen man keine Ahnung hat.

Ich habe über die Jahre doch ein paar Frameworks gebaut. Gute, schlechte, noch schlechtere und auch welche, die durch die allgemeine Frameworks ersetzt wurden. Auch mal ein Bugfix für ein vorhandenes Framework war dabei.

Wichtig ist dabei, dass man sich klar wird, dass Frameworks im Kern meistens alles andere als hoch komplex sind. Das würde schon dem
Zweck des Frameworks widersprechen, das ja für möglichst viele Anwendungszwecke funktionieren soll. Der Core ist meistens sehr einfach und klar strukturiert. Komplexität kommt meistens über Zusatzfunkionen rein, die wieder rum nur die Kernfunktionen bedienen. Wenn diese Kernfunktionen gemischt werden und kann es am Anfang sehr unübersichtlich erscheinen, weil teilweise nicht ganz klar ist, was wofür da ist.

Bei React mit Hooks kann selbst das Mischen von useState und useEffect teilweise kompliziert sein, weil aus der Sicht des Entwicklers vielleicht, von diesen Funktionen was anderes Erwartet wird, als im Framework-Kern damit wirklich erreicht wird.

Frameworks machen keine Zauberrei aber dafür sehr viel Referenz-Verwaltung. Meiner Erfahrung nach beschäftigt man sich im Framework-Kern zu 75% allein damit Instanzen und Referenzen zu erzeugen und zu verwalten.

Um das ganze etwas zu verdeutlichen habe ich mich einmal hingesetzt und in unter einer Stunde (hatte ich mir auch so vorgegeben) ein kleines Framework gebaut, das useState und useEffect reimplementiert und zeigt, wie man das Verhalten dieser Funktionen nutzt, aber auch, welche Funktion für das Framework wirklich dahinter steckt. Weil am Ende kommt man zu meist immer zu selben Strukturen, die bei allen Frameworks immer nur etwas anders benannt und implementiert sind.

Github - EasyComponent.JS Code & Präsentation
https://github.com/annonyme/easycomponents_presentation

Docker: sFTP-Server für schnelle Tests

Manchmal muss den Upload von Dateien testen. Nicht immer nutzt man etwas wie S3 sondern oft auch noch ganz klassische Umgebungen mit SCP oder sFTP. Wenn man schnell und unkompliziert den Upload auf einen sFTP-Server testen will, kann sich so einen ganz schnell und einfach mit Docker erzeugen.


docker run -p 2222:22 -d atmoz/sftp foo:pass:::upload

https://github.com/fixate/docker-sftp

man kann sich dann auf localhost:2222 mit dem Benutzer foo und dem Passwort pass verbinden. Für Dateien steht das Upload-Verzeichnis bereit. Wenn man ihn nicht mehr braucht, wirft man den Container einfach weg und kann das nächste mal sauber mit einem neuen starten.

Wann ist eine Software "unwartbar"?

Jeder kennt Software, die man nicht mehr anfassen möchte. Man sagt, die Software wäre nicht mehr wartbar. Aber was bedeutet das überhaupt?


Die Definition von Wahnsinn ist, immer wieder das Gleiche zu tun und andere Ergebnisse zu erwarten.

von irgendwem.. vielleicht Einstein

Wenn eine Software unwartbar wird, gilt etwas sehr ähnliches.


Die Definition von unwartbar ist, an zwei augenscheinlich gleich funktionierenden Stellen etwas zu ändern und bei beiden das selbe Ergebnis zu erwarten... das es dann aber nicht ist!

von Hannes Pries... nach einen entsprechenden Tag

Oft ist solche Software organisch gewachsen. Organisch gewachsen bedeutet in diesem Fall, dass man nie das grundlegende System erweitert und verbessert hat, sondern einfach neue Funktionen drum herum gebaut hat. Auch wird oft Code kopiert und im Laufe der Zeit immer nur die einzelnen Code-Blöcke angepasst, wo es nötig ist und die anderen so belassen. Besser wäre es gewesen, den Code auszulagern, so dass an allen Stellen die Änderungen greifen.

Oft sind es gar nicht die ganz alten Code-Teile der aller ersten Version, die die Probleme machen, weil diese noch einem Konzept folgten. Mit der Zeit ist das Konzept verloren gegangen und die damaligen Entwickler sind oft schon lange nicht mehr dabei. Es gibt natürlich keine Doku, Namespaces und eine besonders übersichtliche Sortierung von Klassen sind meistens nicht vorhanden, gab es zu der Zeit einfach nicht oder wurden durch die ganzen Erweiterungen selbst zerstört.
Mit der Zeit setzt sich die Annahme durch, dass der damalige Code einfach schlecht war und man es erneuern sollte, wenn man etwas neues programmiert. Das führt dazu, dass jeder das auch macht und plötzlich 3-4 Implementierungen für ein und das selbe gibt.
Dumm nur, dass auch alle diese Implementierungen auch immer verwendet werden und so sich niemand traut eine der Implementierungen abzuschalten, weil es nicht der eigene Code ist und man sich nicht sicher ist, ob es wirklich 100%ig den selben Funktionsumfang hat.

Aber irgendwann muss man daran und dann baut man einfach etwas wieder ran und entfernt nicht einfach die Implementierung und nutzt die aktuellste.

Lustig ist auch, dass man oft gegen Ende der Lebenszeit einer Software, wenn man die Strukturen für einen Rewrite analysiert, feststellt, was das grundlegende alte Framework schon alles konnte und vieles was man später mit viel Aufwand eingebaut hat, schon lange da war. Oft auch sogar in einer gar nicht so schlechten Implementierung.

Jeder hat bei so etwas genau so mitgemacht, oder? Zeitdruck... neu bauen und nicht alten Code lesen. Wirklich mal mysqli-Funktionen gegen PDO ersetzen? Wäre toll, aber wer will sich wirklich die Arbeit machen, weil es ja doch alles irgendwie funktioniert. Das System verwendet viele PHP-Dateien und keine zentrale index.php? Kann man ja schnell bauen.. macht man aber nie und muss in vielen Dateien oft die selben Dinge ändern.

Was ist die Lösung? Sich klar werden, dass es nichts mehr bringt und das System sauber neu schreiben. Nicht für sich (naja.. doch irgendwie schon), sondern für andere Entwickler. Es muss ein System sein, wo man von ausgeht, dass es für jeden Fall eine Lösung mitbringt. Das System wird den selben Weg gehen und man muss versuchen schon ganz am Anfang anfangen gegen zu steuern auch noch kein anderer daran mit arbeitet.


Keep it simple! Keep it clean!

hat das schon mal wer anderes gesagt? Bestimmt!

Wenig Code, klare Interfaces mit 100%ig aussagekräftige Namen. Die Codevervollständigung ist die Suche nach der richtigen Klasse, also müssen alle Klassen richtig benannt sein.

Es ist alle schwerer als man denkt, aber Frameworks und Standards wie PSR bei PHP helfen da sehr. Sich einfach auf den Stil und die Konventionen des Frameworks einlassen und sich aneignen. Dann klappt es schon. Auch wenn es schwer ist.

Spring Boot mit HTTPS: schnelle Lösung

Gerade wenn man Apps (PWAs) entwickelt, die zwingend HTTPS brauchen, weil man auf Dinge wie die interne Kamera des Geräts zugreifen möchte, kommt man zu dem Problem auch die Middleware mit HTTPS betreiben zu müssen. Kein Browser mag Mixed-Content. Wenn die Middleware mit Spring Boot geschrieben ist, kommt man aber auch da ziemlich schnell und einfach zu einer Lösung.
Das funktioniert sogar ohne komplexe Keystore Aktionen und irgendwelchen Signieren von gebauten Artefakten.

Die einfachste Lösung ist sich ein PKCS#12-Certificate (als das als Datei, PKCS#11 ist das von den Smartcards) zu erzeugen und direkt als Keystore zu nutzen.


keytool -genkeypair -alias pkcs12test -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore pkcs12test.p12 -validity 3650


Neben dem Alias sollte man auch den Dateinamen der p12-Datei anpassen. Danach muss man viele Daten angeben (die man sonst in openssl in der Conf-Datei ablegen würde). Die p12-Datei kann man nun einfach im resources-Bereich im Default-Package ablegen (bzw. auch in jedem anderen Package, wo es per getResource erreichbar ist).

Danach muss man die Daten nur noch in der application.properties eintragen.


server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:pkcs12test.p12
server.ssl.key-store-password=your_password
server.ssl.key-alias=pkcs12test


Danach sollte Spring Boot wie vorher auf dem konfigurierten Port starten, aber ab jetzt nur noch per HTTPS erreichbar sein.

Das Certificate ist natürlich nur self-signed und eignet sich nur für Dev-Umgebungen. Bevor die PWA auf die Middleware zu greifen kann, muss man mit dem Browser die Middleware einmal aufrufen und den Zugriff für den Browser erlauben. Danach sollte es dann gehen.

Die ausführlichere Anleitung findet man hier:
https://www.baeldung.com/spring-boot-https-self-signed-certificate

HDMI Capturen mit Blackmagic Intensity Pro

Über die Jahre hatte ich schon mit vielen Videokarten zu tun. Von den klassischen Fast Karten wie der Movie Machine 2 oder dem AV.master zu an sich fast allen Miro/Pinnacle Karten wie DC10, DC20 und DC30. Auch so exotische Teile wie die Iomega Buz (mit integrierten SCSI-Controller).

bbcode-image


Dann kam lange Zeit nichts mehr weil CAmcorder Firewire hatten oder man alte schon digitalisierte Video nur noch immer wieder hin und her codiert hat. Dann kam aber die Idee auf mal Mario Kart von der Switch auf Twitch zu streamen. Bevor ich mich weiter mit einem kleinen Konzept beschäftigen wollte, dass mit abends mal spontan einfiel, wollte ich wissen, ob so etwas überhaupt vernünftig geht.

Mein erster Versuch war noch rein PC-basiert und ich wollte Testen ob ich ein Spiel (Ion Fury) und eine Webcam (Dogcam) streamen kann ohne dass mein doch schon relativ alter PC dabei in die Knie geht. Hardwarebeschleunigung beim Encodieren mit meiner Radeon HD 7990 wollte ich dann auch gleich testen. Obwohl ich nur sehr langsame CPUs habe, lief alles erstaunlich gut und ich habe gelernt den Studio-Modus von OBS zu nutzen.

bbcode-image


Da alles gut lief, ging es nun darum eine HDMI-Quelle an den PC anzuschließen. Was nutzt man da, wenn man nicht gleich viel Geld ausgeben will? AVerMedia ist teuer, Elgato auch, eine China No-Name Karte wollte ich dann aber auch nicht riskieren.
Also habe ich mich für eine günstige Lösung der Marke Blackmagic entschieden. Die Blackmagic Intensity Pro in der nicht-4K Edition. Der Vorteil ist auch, dass ich mir noch eine Kabelpeitsche dazu kaufen könnte und dann wieder in der Lage wäre Analoge Quellen (z.B. einen SNES) anzuschließen.

bbcode-image


Nach dem die Karte in einem PCIe Slot nicht funktionieren wollte, funktionierte sie in einem anderen. Der war direkt unter der Grafikkarte und der Aufkleber auf der Karte bog sich bei Wärme (z.B. durch Spiele) nach oben und machte unschöne Geräusche im Lüfter der Grafikkarte. Naja.. also Aufkleber entfernt und es lief dann alles.

bbcode-image


Die Latenz ist wirklich gering. Gering.. aber SNES Mini spielen geht so nicht weil doch so 500ms Verzögerung im Bild ist. Deswegen sollte man auf jeden Fall an den HDMI-Out einen weiteren Monitor anschließen, der ohne Latenz funktioniert. Aber ich finde die Karte für so eine günstige Lösung echt gut und sie bietet viele Möglichkeiten.

Das Experiment und die Planung kann also weiter gehen!

Kurz Review: Nextcloud

Nicht jeder will für Clouddienste wie OneDrive oder Dropbox bezahlen oder hat eine so schnelle Internet Anbindung (im Upload) um sich mit einem QNAP-NAS eine eigene Lösung zu basteln. Auch sind Dropbox und OneDrive sehr eingeschränkt und erlauben kaum etwas außen dem Austausch von Dateien. Gerade als Firma oder Familie möchte man aber nicht nur Dateien tauschen, sondern auch Termine, Kontakte und Kanban-Boards teilen. Auch ist es sehr praktisch wenn man hochgeladene Text- oder Spreadsheet-Dateien direkt bearbeiten kann. Emails sind dann noch das letzte um eine wirklich vollständige Cloudlösung auch für Teams zu haben.

Wenn etwas Webspace oder einen Webserver hat, kann sich dafür einfach Nextcloud installieren. Die Collabora-Office-Integration habe ich nicht zum Laufen bekommen, aber dafür das App-Bundle für Groupware-Lösungen. Ich finde es Lösungen wie Tine 2.0 oder eGroupware überlegen und bedient sich auch einfach moderner.

bbcode-image


bbcode-image


bbcode-image


bbcode-image


bbcode-image


Gerade für kleine Firmen eine gute Alternative zu Office365, einem QNAP-NAS (mit DynDNS oder VPN) und anderen zu bezahlenden Lösungen.

React: Internals

Ich vertrete ja die Meinung, dass React erst mit der Einführung der Hooks wirklich nutzbar wurde. Vorher war alles zu aufwendig beim Prüfen des States und dem beachten der Lifecycles. Durch useState und useEffect geht jetzt alles einfacher und schneller. Wer sich schon immer gefragt hat, wo der Unterschied in useState und useReducer liegt, wird sicher diesen Artikel Under the hood of React’s hooks system sehr interessant finden und lernen, das useState einfach nur ein anderes Interface für useReducer ist.

T3N - 6 Gründe Python zu lernen: Naja...

Ich habe mir diesen Artikel durch gelesen, warum man bis 2020 Python lernen sollte. Aber irgendwie überzeugen mich diese Gründe so gar nicht. Ich hab schon mal ein paar Dinge mit Python gemacht und am Ende, war es eine Sprache wie jede andere. Viel weniger Boilerplate-Code als Java, aber dass ist keine Kunst und mit Lombok und ähnlichen hat sich auch bei Java viel getan. Aber mal der Reihe nach:

1. Automatisiert triviale Aufgaben
Das kann ich mit PHP (mit Symfony-CLI) auch ganz gut. Kleine Tools schreiben ohne viel Framework wie JRE + Spring + JPA + etc haben zu müssen. Aber sobald der Code Compiler wird, kommt auch da alles hinzu. Ich sehe da eher den Vorteil dass Python auf IoT-Geräten gut läuft und man sehr viel Overhead einsparen kann.

2. Schneller Einstieg und einfache Syntax
Stimmt. Das Beispiel ist zwar nicht aussagekräftig da der Boilerplate-Code mit zunehmenden Code immer geringere Anteile einnimmt und man sich viel Code heute ja auch automatisch generieren lassen kann. IDEs sei dank bringt einen diesen Code zu schreiben kaum einen zeitlichen Nachteil. Also... ja.. Python ist nicht schwer, aber auch nicht leichter als PHP oder JavaScript. Java ist an sich auch nicht schwer, man muss nur eben Classes und Packages richtig nutzen und schon ist alles sehr übersichtlich. Je weniger Struktur man braucht desto schwieriger wird es auch für die IDE bei der Codevervollständigung zu helfen. Java ist da einfach immer noch weit vorne.

3. Data Science
Geil... wenn ich Python kann, kann ich Data Science? Nein. Irgendwer hat man angefangen Python in dem Bereich zu nutzen und hat gute Libs geschrieben. Oft sind die Libs Ausschlag gebender als die Sprache an sich. Also war es wohl eher Zufall dass in dem Bereich Python hauptsächlich eingesetzt wird und nicht der Sprache an sich geschuldet. Bloss weil ich das Hauptwerkzeug für einen Berufszweig benutzen kann, kann ich auch den Beruf ausüben... ich kann mit einem Skalpell scheiden!!!!

4. Machine Learning
Ja.. auch cool. Tolles und komplexes Thema. Werkzeuge dafür zu erlernen ist hier sicher nicht die größte Herausforderung in dem Bereich.

5. Ressourcen
Wie oben schon beschrieben. Wenn die Lib mein Problem löst, nehme ich die Sprache für die es die Lib gibt. Da ist es egal ob es Python, Java oder C++ ist. Ich nehme einfach das, was mein Problem schnell und einfach löst. Also bringt es mir nichts Python zu lernen, weil es tolle Libs gibt. Wenn ich eine Lib benutzen will, dann habe ich ein Grund mir die Sprache anzueignen.. vorher nicht (außer aus Spass oder Lerndrang).

6. Community
Das gilt an sich für jede größere Programmiersprache. Stackoverflow hilft, deutsche Foren liefern nie eine Lösung. Alles wie immer.

Zusammenfassend kann ich für mich nur sagen. Es lohnt sich für mich nicht eine neue Sprache zu lernen, weil man theoretisch super tolle Dinge damit machen könnte, die ich entweder nicht beherrsche oder nicht benötige. Die Standardaufgaben können alle Sprachen fast gleich gut und da zwischen den Sprachen zu wechseln fällt auch entsprechend leicht. Mal mit einer Sprache rumspielen ist immer lustig und macht Spass, aber eine Sprache wirklich lernen ist nru nötig wenn man es benötigt. IoT-Geräte sehe ich da noch als den wahrscheinlichsten Grund, warum ich mal wieder was mit Python machen sollte.

Shopware: DevOps mit Composer-Installation

Der einfachste Weg einen Shopware Shop zuinstallieren war immer, die ZIP-Datei mit dem Webinstaller downzuloaden und diese in das gewünschte Verzeichnis zu entpacken. Dann die URL aufrufen und dem Installer folgen. Das ist für automatische Deployments nicht so toll und oft wurde dort einfach die Git-Version verwendet. Die hat den extremen Nachteil, dass diese unglaublich viele Dinge mitbringt, die in einer produktiven Umgebung nichts zu suchen haben. Buildscripte, Tests, etc bringen einen wirklich nur in der Dev-Umgebung was und sollten in der produktiven Umgebung nicht mit rumliegen, weil je mehr rumliegt, desto mehr Sicherheitslücken oder ungewollte Probleme könnten mitkommen.

Seit einiger Zeit kann man Shopware aber auch sehr einfach über den Composer installieren. Dabei wird eine eher moderne Verzeichnisstruktur angelegt und auch die Basis-Konfiguration kann einfach über Env-Variablen gesetzt werden, so dass ein automatisches Deployment für einen Server damit sehr einfach wird. Im Idealfall hat man die Datenbank schon sauber und fertig vorliegen. Dann erspart man sich fast den gesamten Installationsprozess und kann direkt loslegen.

Wenn man den Composer noch nicht installiert hat, muss man diesen kurz installieren:

curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer


Danach wechselt man in das Verzeichnis wo man die Installation ablegen möchte und führt den Composer aus:

composer create-project shopware/composer-project your_webshop --no-interaction --stability=dev


Um nun die Installation erreichen zu können muss noch ein VHost im Apache angelegt werden. Hier geben wir auch die DB-Verbindung mit an:

<Virtualhost *:80>
ServerAdmin webmaster@localhost
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

ServerName your_shop_url
ServerAlias www.your_shop_url

SetEnv DATABASE_URL "mysql://dbuser:dbuserpassword@dbhost_url:3306/your_shop_db"

DocumentRoot /var/www/your_webshop

<Directory /var/www/your_webshop>
AllowOverride All
Require all granted
</Directory>

RewriteEngine On
</Virtualhost>


Reload des Apache und schon kann es an sich losgehen. Wenn man sehen möchte wie die DATABASE_URL verarbeitet wird, kann man einen Blick in die etwas komplexer gewordene config.php werfen die man nun unter your_webshop/app/config/config.php findet.

Sollte man noch keine fertige Datenbank auf dem Server liegen haben, muss man die ./app/bin/install.sh ausführen. Gerade für mehrere automatische Deployments, würde ich aber die Datenbank einmal local auf meiner Workstation anlegen und mit Default-Werten befüllen. Diese kommt dann auf den Datebankserver und wird beim deployment, mit den spezifischen Daten wie den Shopdaten und Admin-Zugängen versehen.

Natürlich würden Updates auch über den Composer laufen, wobei sw:migration:migrate automatisch mit aufgerufen wird, um die Datenbank mit aktuell zu halten. Das Verhalten kann man über die Deaktivierung des entsprechenden Hooks in der composer.json verhindern (aber das macht an sich nur in Cluster-Umgebungen Sinn). Ein Update über das Webinstaller-Plugin würde Probleme bereiten und sollte, wenn man es dann ,z.B. weil man eine alte Installation umgezogen hat, installiert und aktiv hat mit ./bin/console sw:plugin:uninstall SwagUpdate entfernen.

Der wirkliche Vorteil liegt jetzt darin, dass man in die composer.json seine Git-Repositories von den Plugins mit eintragen kann und die Plugins direkt über den Composer installieren und updaten kann. Man muss also nicht diese erst vom Server downloaden + entpacken oder per Git clonen (wo dann wieder viel Overhead mit rüber kommen würde).

Beispiel (für Shopware < 5.5):

composer require shopwarelabs/swag-media-s3
./bin/console sw:plugin:install --activate SwagMediaS3


Bei dem Plugin werden die Config-Daten dann auch über SetEnv in der VHost-Config gesetzt.

Mit diesen Lösungen lassen sich dann automatische Deployment realisieren und auch Docker-Images kann man so relativ einfach bauen.

Referenzen:
An easy example how to switch from classic installation to composer installation
Using Composer to install Shopware
Composer template for Shopware projects

Retro-Gaming: Sega Mega Drive Mini

Ich habe mir direkt den SNES Mini gekauft. Der NES Mini hat mich weniger angesprochen. Aber für den SNES hatte ich einen wirklichen Grund ihn zu kaufen: Die Spiele als Modul einzeln zu kaufen wäre einfach unglaublich teuer gewesen. Auch war Star Fox 2 in einer offiziellen Version dabei und nicht nur als ROM mit unklarer Herkunft.
Mario-Kart + Probotecotr/Contra allein hätten sicher schon das selbe gekostet wie die kleine Konsole. Turtles in Time wäre natürlich echt super gewesen, aber auch ohne hat sich der Kauf einfach gelohnt.

Beim Mega Drive Mini sieht es anders aus. Ich werde mir die Konsole nicht kaufen, da ich die meistens Spiele schon habe oder aber für sehr wenig Geld auch so bekomme. Da kann ich mich dem Gamersglobal-Artikel voll anschließen. Ich habe die meistens Spiele wie Light Crusader, Sonic, Golden Axe und Comix Zone auch wenn ich mit für die Switch Sega Mega Drive Classics kaufe und das für unter 20 Euro.

bbcode-image


Wenn man keinen Mega Drive hat und etwas in der Optik haben will, kann sich der Kauf lohnen. Wenn man schon einen hat, dazu ein Module aus China mit > 100 Spielen und noch die Classics Collection für die Switch, lohnt es sich einfach nicht und die 3 Dinge zusammen sollte man auch zu dem Preis der Mini bekommen können.

bbcode-image

Shopware: 5.6 vs SwagPaymentPaypal vs Shopware::VERSION

Ein Update auf 5.6 ist schnell und einfach gemacht. Alle Tests liefen super und es sah nach einer 2 Minuten Aktion aus... dann kam das SwagPaymentPaypal und nutzte Shopware::VERSION. Um genau zu sein in der Bootstrap.php in Zeile 146. Das gibt es in 5.6 aber nicht mehr und deswegen lief dann auch gar nichts mehr. Das Plugin lies sich auch nicht deaktivieren.

Wer also das Plugin noch nutzt sollte es unbedingt durch SwagPaymentPayPalUnified ersetzen. Das alte muss deinstalliert werden, weil die selben Config-Namen verwendet werden.

Wer das alte noch hat und in das selbe Problem läuft, muss dann leider die Zeile 146 per Hand ändern. In etwas wie das hier:

if (false) {


Darin wird etwas für Shopware < 4.2.0 gemacht, was wir mit 5.6 eindeutig nicht mehr brauchen.

Older posts:

Möchtest Du AdSense-Werbung erlauben und mir damit helfen die laufenden Kosten des Blogs tragen zu können?