Shopware Plugin Tutorial - Wir erstellen ein Plugin - Teil 2

Shopware Plugin Tutorial - Wir erstellen ein Plugin - Teil 2

Daniel Wolf 25. September 2018 0

Du möchtest mehr über die Basics der Shopware-Pluginentwicklung erfahren? Dann bist du hier genau richtig!

Willkommen zum zweiten Teil unseres Shopware 5.2 Plugin-Tutorials. Im letzten Teil haben wir ein Konzept aufgestellt und das Grundgerüst aufgebaut. Falls ihr diesen verpasst habt, solltet ihr ihn euch unbedingt hier durchlesen, weil wir im folgenden darauf aufbauen.

Lesezeit: ~18 Minuten

Am Ende stelle ich den aktuellen Stand des Plugins völlig kostenlos zur Verfügung. Ihr könnt es euch aber jetzt schon herunterladen und den Code beim Lesen des Blog-Artikels nachvollziehen.

Um den größten Lerneffekt zu erzielen, solltet ihr den Beitrag erst vollständig durchlesen und verstehen nebenbei könnt ihr euer eigenes Plugin erstellen. Danach schnappt ihr euch den Code und geht die einzelnen Funktionen nochmal durch, um zu schauen, ob ihr auch wirklich alles verstanden habt.

programmierer mac coding white

Was machen wir heute?

Wenn ihr letztes Mal gut aufgepasst habt, wisst ihr ganz genau, wo wir letztes Mal aufgehört haben und was euch heute erwartet! Als Erstes zeige ich euch, wie ihr über euer Plugin einen Cronjob erstellt. Danach richten wir für diesen einen Subscriber an. Abschließend werden wir unseren ersten Service einbauen und verwenden.

Da sich alles so spannend anhört und ihr es bestimmt genauso wenig erwarten könnt wie ich, fangen wir direkt mit dem ersten Punkt an:

Cronjob erstellen

Wir beginnen mit dem Cronjob. Falls du noch nicht weißt, was ein Cronjob ist bzw. wie sie genau funktionieren, kannst du dir diesen Blog-Beitrag durchlesen.

Mit dem neuen Plugin-System von Shopware 5.2 gibt es die Möglichkeit die Einstellungen des Cronjobs in der Datei cronjob.xml zu hinterlegen. Diese wird dann beim Installieren automatisch zu einem richtigen Cronjob verarbeitet.

Da es bis Shopware 5.3.5 allerdings einen Bug gibt, bei dem das Enddatum über diesen Weg nicht richtig gesetzt wird und wir den Cronjob daher im Backend nochmal anpassen müssten, zeige ich euch vorher noch einen anderen Weg, bei dem wir den Cronjob über die Datenbank hinzufügen.

Kleine Erinnerung: Die Basefile eines Plugins ist die Hauptdatei und trägt den selben Namen wie der Plugin-Ordner - in unserem Fall die EmzRenameImages.php

Dabei nehmen wir die Basefile aus dem ersten Teil und erweitern sie um eine uninstall() und eine install() Methode. Diese Methoden werden aufgerufen, wenn das Plugin de- oder installiert wird.

In der Datenbank des Shops werden alle Daten gespeichert. Unter anderem finden wir dort auch alle Cronjobs und ihre Konfiguration. Über die oben genannten Methoden können wir den Cronjob also bei der Installation über einen sogenannten Query in die Datenbank einfügen. Ein Query ist im Grunde ein Befehl, der auf Datenbank-Ebene ausgeführt wird, um z. B. einen Eintrag in ihr zu speichern.

Der Code dazu sieht folgendermaßen aus:

Zunächst sagen wir oben, dass wir die InstallContext und die UninstallContext-Klassen benutzen möchten. Das ist wichtig, weil wir sie bei den Parametern der un- und install-Methoden angeben.

Neuer Datenbank-Eintrag über DBAL-Service

Wir beginnen in der install() Methode, indem wir uns in der $connection-Variable über den sogenannten Service-Container einen Service holen. Ein Service ist im Grunde nur eine Ansammlung von verschiedenen Funktionen. In unserem Fall holen wir uns den DBAL-Service, mit dem wir Daten aus der Datenbank holen oder sie dort einfügen.

Shopware hat neben dem DBAL-Service eine ganze Menge anderer Services. Zum Beispiel gibt es einen Media-Service, mit dem man unter anderem Bilder löschen kann.

Der DBAL-Service hat eine insert() Funktion. Diese wird benutzt, um einen neuen Datenbank-Eintrag hinzuzufügen. Dabei geben wir verschiedene Parameter an, welche die Funktion in einen Query umwandelt und an die Datenbank schickt. In unserem Code fügen wir einen Eintrag in die s_crontab Tabelle (hier sind alle Cronjobs gespeichert) mit den vorliegenden Daten ein.

Für den Namen habe ich "Bilder umbenennen" gewählt. Die Aktion des Cronjobs ist "Shopware_CronJob_EmzRenameImages" und wird später nochmal relevant sein. Als Intervall habe ich hierbei 600 Sekunden bzw. 10 Minuten gewählt.

datenbank insert schema

In der uninstall() Methode führe ich gegensätzlich einen Query aus, der den Datenbank-Eintrag der 's_crontab'-Tabelle löscht, welcher als Aktion "Shopware_CronJob_EmzRenameImages" hinterlegt hat. Da das nur auf unseren Cronjob zutrifft, wird dieser gelöscht.

Nun sollte beim Installieren der Cronjob hinzugefügt werden. Wenn ihr euer Plugin schon installiert habt, könnt ihr es über den Plugin-Manager im Backend einfach neu installieren.

Der einfachere Weg

Wenn ihr mit einer Version ab 5.3.5 arbeitet, könnt ihr auch den einfacheren Weg nehmen. Erstellt dazu den Ordner Resources und dort die Datei cronjob.xml. In diese könnt ihr folgenden Code einsetzen:

plugin ordner uebersicht cronjob xml

Diese Datei wird automatisch beim Installieren ausgelesen und zu einem Cronjob verarbeitet. Auch hier müsst ihr das Plugin einmal neu installieren.

Subscriber für unsren Cronjob anlegen

Für den Cronjob haben wir als Aktion "Shopware_CronJob_EmzRenameImages" hinterlegt. Nun können wir einen sogenannten Subscriber anlegen. Ein Subscriber ist zunächst einmal nur eine weitere PHP-Datei. Die Besonderheit ist allerdings, dass ein Subscriber unseren Code zu bestimmten Ereignissen ausführen kann.

Für einen Subscriber müssen zwei Schritte umgesetzt werden:

  • Subscriber-Datei anlegen und mit Code füllen
  • Subscriber in der services.xml einrichten

Da wir gerade eben einen Cronjob erstellt haben, nutzten wir an dieser Stelle einen Subscriber, um eine Funktion zu definieren, welche beim Ausführen unseres Crons aufgerufen wird.

Für den Subscriber erstellen wir in unserem Plugin-Ordner den Ordner Subscriber. In diesem werden all unsere Subscriber-Dateien liegen. Dort erstellt ihr die Datei Cronjob.php. Der Name der Datei ist theoretisch egal, sollte aber thematisch zu dem Event passen. In dieser Datei befindet sich folgender Code:

plugin ordner uebersicht cronjob subscriber

Um ein Subscriber zu sein, muss die Klasse von dem SubscriberInterface erben. Außerdem ist es wichtig, dass wir eine getSubscribedEvents() Methode definieren. In dieser geben wir ein Array zurück, in dem wir Events und zugehörige Listener-Funktionen verbinden.

Ein Listener ist eine Funktion, die aufgerufen werden soll, wenn ein bestimmtes Event ausgelöst wird. Bei Cronjobs ist die Aktion auch gleichzeitig das Event. Wenn der Cronjob also ausgeführt wird, wird kurz danach die onCronjobExecute() Methode unseres Subscribers ausgeführt. In diese schreiben wir später unseren Code für das Umbenennen der Bilder.

Unseren Subscriber registrieren

Bis jetzt haben wir aber nur die Subscriber-Datei angelegt. Im nächsten Schritt müssen wir Shopware noch sagen, dass es sich hierbei um einen Subscriber handelt. Dafür erstellen wir im Resources-Ordner eine Datei mit dem Namen services.xml. In dieser registrieren wir alle Subscriber und Services, die wir in unserem Plugin verwenden möchten.

Folgenden Code packen wir in diese Datei, um den Cronjob-Subscriber zu registrieren:

plugin ordner uebersicht services xml

Aufpassen!

Wichtig ist hierbei, dass wir die richtige Klasse angeben. Außerdem dürfen wir den "tag" nicht weglassen. Durch diesen kann Shopware später bei Installation die zuvor hinterlegte getSubscribedEvents() Methode unseres Subcribers aufrufen und die jeweiligen Events mit ihren Funktionen verbinden.

Nun müssen wir das Plugin wieder neu installieren. Dadurch wird die services.xml ausgelesen und verarbeitet. Das System weiß danach, dass in unserer Cronjob.php ein Subscriber liegt, der auf das Ausführen des Cronjobs wartet.

Was passiert als Nächstes?

An dieser Stelle kommen wir und auf unser Konzept aus Teil 1 zurück. Ich habe mir überlegt, dass im Großen und Ganzen 3 Komponenten wichtig sind. In diesem Teil der Blog-Reiche kümmern wir uns erstmal nur um eine der drei.

Wir bräuchten eine Art Warteschlangen-System, welches uns eine bestimmte Anzahl an Artikel-Bildern liefert, die wir beim Ausführen des Cronjobs umbenennen können. Zusätzlich sollte man mit dieser Komponente auch die Möglichkeit haben, bereits umbenannte Bilder zu markieren, damit sie beim nächsten Durchlauf nicht wieder umbenannt werden.

Oben habt ihr bereits erfahren, dass es den DBAL-Service gibt, der sich um die Datenbank kümmert. Wir können aber auch selbst eigene Services definieren. Welche Funktionen in einem Service enthalten sind und wie dieser genau aussieht, entscheiden wir dabei selbst. Dabei ergibt es aber Sinn, nur Funktionen mit dem selben Thema in einem Service unterzubringen. In unseren Queue-Service werde ich also nur Funktionen einbauen, die sich um das Beschaffen und Markieren von Artikel-Bildern kümmert.

Wie können wir Bilder markieren?

Damit der Service die richtigen Artikel holen kann, muss es eine Möglichkeit geben, bereits umbenannte Bilder zu markieren, damit sie nicht immer wieder umbenannt werden. 

Jedes Artikelbild in Shopware hat einen zugehörigen Datensatz in der Datenbank. Dabei gibt es auch einen Identifikator (id genannt). Diese können wir nutzen und nach dem Umbenennen in eine eigene Datenbank-Tabelle eintragen. Beim Holen der nächsten Bilder kann man damit die bereits umbenannten Bilder aussortieren.

Datenbank-Tabelle über Plugin erstellen

Aber wie erstellen wir nun eine Tabelle in der Datenbank? Am einfachsten wäre es natürlich, die Tabelle einfach manuell in der Datenbank zu erstellen. Aber wir wären natürlich keine Entwickler, wenn wir es einfach mögen ;)

Shopware arbeitet mit einem Framework namens Doctrine. Ein Vorteil von Doctrine ist, dass wir PHP-Klassen aufbauen können, in denen wir mit Variablen und Funktionen eine Art Konfiguration hinterlegen. Diese Klasse kann Doctrine später auslesen und zu einer Datenbank-Tabelle umwandeln.

Fun-Fact: diese PHP-Klassen werden "Models" genannt. Ab sofort dürft ihr also behaupten, eure Freitag-Abende mit Models zu verbringen.

Unsere Model-Dateien erstellen wir in dem Ordner Models. Hier fügen wir eine neue Datei mit dem Namen RenamedImage.php hinzu.

plugin ordner uebersicht model

Ein Model besteht aus einer PHP-Klasse, mehreren Variablen und Funktionen. Auf die Funktionen werden wir erstmal nicht genauer eingehen, weil wir sie für dieses Plugin nicht brauchen.

Model mit Annotations konfigurieren

In einem Model wird mit sogenannten Annotations gearbeitet. Eine Annotation ist im Grunde Text, der zwischen einem /** und */ steht. Er dient als Konfiguration und steht z. B. über einer Variable der Klasse. 

doctrine models annotations

Die erste Annotation steht über der Model-Klasse. Hier wird unter anderem der spätere Tabellenname - in unserem Fall emz_renamed_images - definiert. Die restlichen Annotations stehen über den Variablen. Sofern die Konfiguration in den Annotations stimmt, wird jede Variable später in eine eigene Spalte umgewandelt. In der Konfiguration werden wichtige Daten wie Spaltenname, Typ usw. hinterlegt. Alle Annotations und ihre Konfigurationen werden in der Dokumentation von Doctrine nochmal genauer erklärt.

Eine Besonderheit von Doctrine ist, dass man hier auch auf andere Models verweisen kann. Bei der $articleImage-Variable sage ich z. B. die Id des Image-Models, welches für die Tabelle der Artikelbilder steht, hinterlegt werden soll. Damit wird eine Verknüpfung zwischen unserem und dem Artikel-Bilder-Model von Shopware erstellt.

So wird unsere Datenbank-Tabelle aussehen

Wie das alles genau funktioniert würde genug Inhalt für einen weiteren Blogpost liefern. An dieser Stelle ist für euch wichtig zu wissen, dass das obige Model eine Tabelle mit zwei Spalten erstellt. Neben der gewöhnlichen id-Spalte gibt es noch die article_img_id-Spalte, in der wir auf die Tabelle der Artikelbilder verweisen. Damit können wir dann später ganz leicht herausfinden, welche Artikelbilder bereits umbenannt worden sind.

Wie bekommen wir unser Model in die Datenbank?

Die Model-Datei ist nun fertig, allerdings müssen wir Shopware noch irgendwie mitteilen, dass unser Model in eine Tabelle umgewandelt werden muss. Perfekt wäre es natürlich, wenn das am Anfang bei der Installation geschieht. Daher schauen wir uns die install()/uninstall() Methode nochmal an. Bevor ihr den Code einfügt, solltet ihr das Plugin erstmal deinstallieren. Den Grund erkläre ich gleich.


Hier haben wir in der jeweiligen Methode einen Block ergänzt, der das Model beim De- und Installieren  hinzufügt oder löscht. Der Grund für das Deinstallieren war, dass der Code-Block der uninstall() Funktion versucht die Tabelle aus der Datenbank zu löschen. Wenn wir das Plugin neu installieren, findet er die Tabelle aber nicht, weil sie zu diesem Zeitpunkt noch nicht existiert. Daher wird eine Fehlermeldung ausgegeben.

Zur Lösung des Problems deinstallieren wir das Plugin vorher, fügen den neuen Code hinzu und installieren es wieder. Danach kann unsere Erweiterung allerdings auch ohne Probleme neu installiert werden, weil sich die Tabelle ab diesem Zeitpunkt in der Datenbank befindet.

Darf ich vorstellen: unser Queue-Service

Da wir nun unsere Tabelle haben, können wir uns an den Queue-Service setzen. Unsere Services werden wir in dem Ordner Components/Services ablegen.

plugin ordner uebersicht queue service

Ich gehe dabei so vor, dass ich für jeden Service nochmal einen Unterordner mit dem Namen des Ordners anlege. In diesem Fall erstellen wir dort den Queue Ordner. Hier legen wir die Dateien Queue.php und QueueInterface.php ab. Letztere wird das Interface des Services sein. Ein Interface ist einfach gesagt eine Vorlage für unsere PHP-Klasse. Hier definieren wir kurz welche Funktionen wir in der Klasse benutzen werden und welche Parameter in diesen erlaubt sind.

Unser Interface ist mit zwei Funktionen recht simpel aufgebaut. Wie oben bereits gesprochen gibt es hier einmal eine Funktion, um an die nächsten 10 Bilder zu kommen und eine Funktion, um bereits umbenannte Bilder zu markieren.

Hier der Code für den gesamten Queue-Service:

Wir finden neben den beiden Funktionen, welche wir in unserem Interface definiert haben, auch noch weitere Funktionen. Diese sind aber keine Methoden, die später über den Service von außen aufgerufen werden soll und nur im Service selbst als Helfer benutzt wird. Daher ist die Funktion auch als private gekennzeichnet.

Wie ist unser Service aufgebaut?

Wichtig ist für uns die getArticleImages() Methode, welche wir später in unserem Cronjob benutzen möchten. Diese Methode soll 10 Artikel-Bilder, welche bisher noch nicht umbenannt wurden, zurückgeben. Dabei bauen wir uns zunächst über die getArticleImagesQueryBuilder() Methode eine sogenannten QueryBuilder. Diesen kann man in Verbindung mit den Model Klassen aus Shopware ganz einfach Querys zu bauen. Falls euch dieses Thema interessiert, könnt ihr wieder in der Dokumentation von Doctrine mehr dazu lesen.

In diesem Beispiel sprechen wir das Image Model an, welche für die Artikelbilder zuständig ist. Über einen leftJoin() holen wir uns alle Einträge aus unserem RenamedImages Model, welche über die article_img_id zu einem Artikelbild zugeordnet werden können. Danach sagen wir in der where() Funktion, dass wir nur diejenigen Artikelbild-Einträge haben wollen, die keinen passenden "Partner" in unserem Model mit den markierten Artikel-Bildern haben. Dadurch stellen wir sicher, dass wir nur unmarkierte Bilder bekommen und kein Bild mehrfach umbenannt wird.

coding mac cookie

Die Bilder, welche uns dieser Query zurückgibt, geben wir wiederum das Ergebnis der Funktion zurück. Damit erhält derjenige, der die getArticleImages() Methode aufruft, die passenden 10 nächsten Bilder.

Die andere für uns interessante Funktion ist flagArticleImages(). Mit dieser Methode können wir Bilder nach dem Umbenennen markieren, damit sie beim nächsten Aufruf des Cronjobs nicht mehr bearbeitet werden.

Hierbei fragen wir zunächst ab, ob das Artikelbild bereits in unserer Tabelle vorhanden ist. Falls nicht, wird es hinzugefügt.

So registrierst du einen Service in Shopware

Damit Shopware weiß, dass es sich hierbei um einen Service handelt, müssen wir auch diesen in der services.xml registrieren. Dabei erweitern wir die Datei einfach folgendermaßen:

Auch dieses Mal ist wieder wichtig, dass der Name der Klasse stimmt. Den subscriber-tag lassen wir dieses Mal weg, weil es sich nicht um einen Subscriber handelt. Damit wäre unser Queue-Service auch schon fertig.

Wie benutzen wir unseren Service?

Um unseren Queue-Service im Cronjob-Subscriber benutzen zu können, müssen wir den Service einbinden. Das haben wir in unserem Queue-Service bereits mit dem ModelManager gemacht, allerdings bin ich noch nicht genau darauf eingegangen.

In der services.xml haben wir unserem Queue-Service eine id gegeben. Mit dieser können wir ihn in anderen Services/Subscribern verwenden. Dafür müssen wir in dem service-Eintrag des Subscribers ein "argument" mit der passenden Service-id hinzufügen.

Die services.xml sieht damit folgendermaßen aus:

Damit ist aber nur einer von zwei Schritten erledigt. In unserem Subscriber müssen wir die Klasse des Interfaces hinzufügen, hinterlegen noch die Variable und schreiben eine sogenannte __construct() Funktion. Diese wird jedes Mal aufgerufen, wenn eine neue Instanz unserer Plugin-Klasse erstellt wird. Den Parameter des Konstruktors haben wir in der services.xml definiert (unseren Queue-Service). In dem Konstruktor selbst weisen wir den Service einer Variable zu, um ihn später benutzen zu können.

In der Listener-Methode des Cronjobs können wir nun über die Service-Variable "$this->queueService" die Funktionen des Services aufrufen. Die geholten Artikel speichere ich in der Variable $articleImages;

Zum Testen des Plugins markiere ich die geholten Bilder direkt über die flagArticleImages(). Der aktuelle Stand unseres Cronjob-Subscribers sieht damit folgendermaßen aus:

Plugin testen


Um das ganze zu testen, brauchen wir natürlich einige Demo-Daten. Falls ihr so wie ich eine frische Shopware-Installation verwendet, könnt ihr euch einfach das Demo-Plugin von Shopware aus dem Community-Store herunterladen. Sucht im Plugin-Manager dafür einfach nach "Demo".

plugin manager backend demo

Nun da wir Artikel im Shop haben, können wir unsere Erweiterung gleich ausprobieren. Stellt den Cronjob so ein, dass der nächste Ausführungstermin in der Vergangenheit liegt. Außerdem muss das "Cron"-Plugin von Shopware aktiviert sein. Danach ruft ihr die URL www.mein-shop.de/backend/cron auf, wobei ihr natürlich eure URL einsetzt.

Nun sollte der Cron ausgeführt werden. Da unser Code im Backend arbeitet, solltet ihr bisher nichts sehen (außer es wird eine Fehlermeldung ausgeworfen). Um zu kontrollieren, ob alles geklappt habt, gehen wir in die Datenbank. Hier sucht ihr nach der Tabelle emz_renamed_images. Falls ihr hier 10 Einträge findet, hat alles so funktioniert, wie es soll.

Irgendwas stimmt nicht… was jetzt?

Wenn die Tabelle aber weiterhin leer ist, müsst ihr auf Fehlersuche gehen. Am Ende dieses Beitrages findet ihr den aktuellen Stand des Plugins zum Herunterladen. Ihr könnt es mit eurem vergleichen, um der Ursache des Problems auf die Spur zu kommen.

Alles Gute hat ein Ende

Das wars auch schon mit diesem Teil unserer Blog-Reihe. Im nächsten Teil erstellen wir einen weiteren Service, der für das eigentliche Umbenennen der Bilder verantwortlich ist. Ich hoffe, ihr seid nächstes Mal auch wieder am Start!

Den aktuellen Stand des Plugins findet ihr hier: Plugin-Download

Hol dir unseren kostenlosen Shopware E-Mail-Kurs:

Lerne wie du deinen eigenen Shopware 5 
Shop erstellst und verwaltest

Noch keine Kommentare vorhanden.

Was denkst du?

Shopware SEO
Guide 2018

shopware seo guide

Genug von schlechten Rankings?

mehr erfahren

Tools, die wir

verwenden

seobility

Das Shopware eBook für Einsteiger!

shopware tutorial ebook mockup
Ausführliche Schritt für Schritt Anleitungen, Tipps & Tricks für alle, die gerne am eigenen Shopware Shop basteln.
Jetzt kaufen

Hol dir 

wertvolle Tipps 
für deinen
Shopware Shop

Wir zeigen dir, wie du deinen
Shopware 5 Shop optimieren
kannst.


Trage einfach deine
E-Mail Adresse ein:

Beliebt

Was du über die Shopware 5 Theme Struktur wissen musst und wie du ein eigenes Template erstellst
Logo Größe mit Less für Shopware 5 anpassen
Die größten Fehler bei der Entwicklung eines Shopware 5 Themes
Vorsicht Shopware Update! Was du beim Updaten beachten musst
Shopware Theme: Eigenes Listing Layout erstellen
Plugin Themes überschreiben und anpassen
Staging Umgebung – Was ist das und warum brauchst du eine?
Theme Entwicklung: Hugo Boss Header zum Selbermachen
Wie du jedes Icon in Shopware 5 anpassen kannst
Shopware 5 - Wie du deine Shop Geschwindigkeit optimierst
© 2017 by 8mylez. Powered by Goltfisch GmbH.