Der Bereich Shopware Labs ist die Plattform für alle Entwickler. Hier findet man technische Dokumentationen und zahlreiche Tipps und Tricks rund um das Thema Programmieren. In dieser Rubrik stellen außerdem die Entwickler der shopware AG neue und experimentelle Lösungsansätze vor. Neue Funktionen, die in dieser Rubrik bereitgestellt werden, sind teilweise auch für zukünftige Releases geplant. Die Funktionen können dann ohne Programmierkenntnisse zukünftig direkt im Shopware Backend konfiguriert werden oder werden über Plugins bereitgestellt. Informationen über neue, geplante Funktionen finden Sie in unserer Roadmap.
Bitte beachten Sie, dass die hier bereitgestellten Lösungsansätze nicht offiziell supportet werden und nur eingebaut werden sollten, sofern Sie über das entsprechende, technische Wissen verfügen.
Einführung Hook-System
0 KommentareInhaltsverzeichnis
Vorwort
In den bisherigen Teilen dieser Tutorial-Reihe haben wir uns schwerpunktmäßig mit den Events beschäftigt. Shopware bietet aber weitere Möglichkeiten, um die Standard-Funktionalität zu modifizieren. Eine davon stellt das "Hook-System" bereit - dieses ermöglicht das freie Überlagern von fast allen Core-Funktionalitäten.
Unterschied Events / Hooks
Events sind definierte Ereignisse, die im Workflow des Shops auftreten bzw. auftreten können. Dazu zählt zum Beispiel die Registrierung eines neuen Kunden, oder aber das Abschließen einer Bestellung. Jeder Seiten-Request mündet so in diversen Events, die im Shop ausgelöst werden. An jedem Event kann man so genannte Event-Listener registrieren - dies sind eigene Funktionen, die automatisch benachrichtigt werden, sobald der jeweilige Event ausgelöst wird.
Mithilfe der Events lassen sich nun natürlich nicht alle Shop-Funktionalitäten beeinflussen. Zum Beispiel enthält nicht jede Shopware-Methode zwangsläufig Events (Das wäre auch keine gute Idee...) und man ist gebunden, an ein bestimmtes Ereignis im System. Um das Plugin-System vollkommen flexibel zu machen, haben wir deshalb einen Hooklayer in das System integriert. Dieser arbeitet nach dem Proxy-Prinzip - alle Objekte in Shopware (mit wenigen Ausnahmen) können so flexibel auch mehrfach überlagert werden. Ein manuelles Extenden der Klassen ist nicht notwendig.
Die Hooks sind also am ehesten mit der normalen Vererbungsstrategie von PHP zu vergleichen - wobei der technische Part der Vererbung hierbei automatisch durch Shopware erledigt wird. Wie das genau funktioniert, schauen wir uns gleich an.
Unterschied Hookpoints / Hooks
Das Hook-System sollte nicht mit den "Hookpoints" verwechselt werden - Hookpoints sind ähnlich wie die Events, definierte Stellen in Shopware, an denen Code aus der Datenbank via "eval" ausgeführt wird. Dieses System ist mit Shopware 3.5 obsolet und als deprecated markiert. Das bedeutet, dass die Hookpoints ab Shopware 3.5.4 nicht mehr unterstützt werden und daher nicht mehr eingesetzt werden sollten.
Hook für Core-Klasse integrieren
Die Shopware Frontend-Funktionalität wird weitestgehend durch die Core-Klassen unter /engine/core/class implementiert. Jede dieser Klassen stellt diverse Methoden zur Verfügung, die man zur Integration eigener Anpassungen modifizieren kann.
Schauen wir uns beispielsweise einmal die Methode sGetArticleById aus der Klasse /engine/core/class/sArticles.php an. Diese wird im Detail-Controller aufgerufen, um alle Daten eines spezifischen Artikels aus der Datenbank abzufragen.
Wie müssen wir nun konkret vorgehen, um diese Methode anzupassen?
Legen Sie das neue Verzeichnis Shopware\Plugins\Local\Frontend\myHook an. Erstellen Sie in diesem Verzeichnis eine neue Datei Bootstrap.php
<?php class Shopware_Plugins_Frontend_myHook_Bootstrap extends Shopware_Components_Plugin_Bootstrap { public function install() { $hook = $this->createHook( 'sArticles', 'sGetArticleById', 'onArticle', Enlight_Hook_HookHandler::TypeAfter, 0 ); $this->subscribeHook($hook); return true; } static function onArticle(Enlight_Hook_HookArgs $args) { } }
Das Plugin installieren und aktivieren Sie dann über den Plugin-Manager im Backend
Beschreibung
- Mit der Methode $this->createHook des Plugin-Systems erstellen wir einen neuen Hook
- Parameter 1 = Klassenname des Objekts, welches wir überladen wollen
- Parameter 2 = Name der Methode, die wir modifizieren wollen
- Parameter 3 = Name der lokalen, statischen Methode, die unsere Änderungen beeinhaltet
- Parameter 4 = Typ:
- Enlight_Hook_HookHandler::TypeBefore - Unsere Methode wird VOR der Original-Methode aufgerufen
- Enlight_Hook_HookHandler::TypeAfter - Unsere Methode wird NACH der Original-Methode aufgerufen
- Enlight_Hook_HookHandler::TypeReplace - Unsere Methode ersetzt die Original-Methode vollständig
- Parameter 5 = Ausführungsposition (Falls mehrere Plugins einen Hook auf diese Methode gesetzt haben, kann hier rüber definiert werden, welches Plugin die Funktion in welcher Reihenfolge modifiziert)
- $this->subscribeHook($hook); - der neue Hook wird im System registriert
- static function onArticle(Enlight_Hook_HookArgs $args) - die Hook-Methoden müssen statisch sein und einen Parameter vom Typ Enlight_Hook_HookArgs akzeptieren.
Welche Methoden stellt das Objekt Enlight_Hook_HookArgs zur Verfügung?
- $args->getSubject() - Verweis auf die Original-Klasse
- $args->getMethod() - Aufruf der Original-Funktion
- $args->getArgs() - Array mit den, an die Funktion übergebenen Parametern
- $args->getName() - Name der Original-Funktion
- $args->setReturn() - Rückgabe setzen
- $args->getReturn() - Rückgabe abfangen
- $args->set(var,val); - Original-Parameter modifizieren
Da wir in unserem Beispiel einen Hook vom Typ Enlight_Hook_HookHandler::TypeAfter definiert haben, können wir also per $args->getReturn(); auf die Rückgabe der Original-Funktion zurückgreifen.
Um also nun den Preis zu modifizieren, müsste man unsere statische Methode wie folgt anpassen:
static function onArticle(Enlight_Hook_HookArgs $args) { $article = $args->getReturn(); $article["price"] = str_replace(",",".",$article["price"]); // Preis ist an dieser Stelle bereits formatiert, also Komma durch Punkt ersetzen, damit wir mit dem Ergebnis rechnen können $article["price"]*= 1.1; // Preis um 10 % erhöhen $article["price"] = $args->getSubject()->sFormatPrice($article["price"]); // Aufruf einer Methode aus der Original-Klasse, um den Preis entsprechend zu formatieren $args->setReturn($article); // Rückgabe der Methode definieren }
Wir fragen also per getReturn() das Ergebnis der Original-Methode ab, modifizieren dieses und geben dieses anschließend mit setReturn() zurück.
Im Hintergrund erzeugt Shopware automatisch die benötigten Objekte und Klassen im Verzeichnis engine/Shopware/Proxies/
In unserem Fall finden wir dort nun die Datei myArticlesProxy.php (myArticles, weil für die Klasse sArticles im Auslieferungszustand bereits eine Vererbung stattfindet)
<?php class Shopware_Proxies_myArticlesProxy extends myArticles implements Enlight_Hook_Proxy { public function excuteParent($method, $args=null) { return call_user_func_array(array($this, 'parent::'.$method), $args); } public static function getHookMethods() { return array ( 0 => 'sGetArticleById',); } public function sGetArticleById($id=0) { if(!Enlight::Instance()->Hooks()->hasHooks('myArticles', 'sGetArticleById')) { return parent::sGetArticleById($id); } $obj_args = new Enlight_Hook_HookArgs($this, 'sGetArticleById', array('id'=>$id)); return Enlight::Instance()->Hooks()->executeHooks($obj_args); } }
Diese Proxy-Klasse wird nun von Shopware statt der Original-Klasse eingebunden, somit werden alle Funktionsaufrufe abgefangen und durch die entsprechenden Hook-Objekte geschleust.
Wofür benötigen wir nun die unterschiedlichen Hook-Typen?
- TypeBefore - Wenn wir die Parameter modifizieren wollen, die an diese Funktion übergeben werden, führen wir unseren Hook vor der Original-Funktion aus
Beispiel-Code
// Die Original-Funktion hat den Parameter $id $id = $args->getArgs(); $id = $id[0]; // getArgs() liefert ein Array zurück - Key = Parameter Position $args->set('id',$id); // Setzen der ID - so kann man also beeinflussen, welche Parameter die Original-Funktion erhält
- TypeAfter - In den meisten Fällen wollen wir die Rückgabe einer Funktion verändern, also z.B. bestehende Daten modifizieren oder weitere Daten abfragen - dazu nutzen wir einen Hook vom Typ "TypeAfter"
- TypeReplace - Falls wir eine Original-Methode vollständig ersetzen wollen, können wir den Replace-Typ verwenden - das sollte aber im Idealfall vermieden werden.
Hook für Controller-Methode integrieren
Auf diese Weise können wir nun auch Controller-Methoden modifizieren - hierzu ein Beispiel:
Bootstrap.php / Install
$event = $this->createHook( 'Shopware_Controllers_Frontend_Checkout', 'finishAction', 'myFinishAction', Enlight_Hook_HookHandler::TypeAfter, 0 ); $this->subscribeHook($event);
Die Controller werden also über ihren vollen Klassennamen referenziert - anschließend muss man nur noch die Methode definieren, die man modifizieren will und den Namen der statischen Methode, die die Modifikation vornehmen soll.
Hook für Beleg-Komponente integrieren
Analog dazu, kann man auch viele weitere Shopware-Objekte modifizieren. Zum Beispiel die Beleg-Erstellung - wenn wir dort weitere Variablen im Beleg-Template zur Verfügung stellen wollen, würde man wie folgt vorgehen:
<?php class Shopware_Plugins_Frontend_DebitPDF_Bootstrap extends Shopware_Components_Plugin_Bootstrap { public function install() { $event = $this->createHook( 'Shopware_Components_Document', 'assignValues', 'onAssign', Enlight_Hook_HookHandler::TypeAfter, 0 ); $this->subscribeHook($event); return true; } static function onAssign (Enlight_Hook_HookArgs $args) { $doc = $args->getSubject(); $doc->_view->assign("payment",$doc->_order->payment); } }
Klassen "Hookable" machen
Um eigene Objekte Hookfähig zu gestalten, bzw. ggf. bestehende Shopware-Objekte mit dem Hook-Layer zu verknüpfen, müssen die Klassen einfach das Objekt Enlight_Hook implementieren.
Am Beispiel der Belegerstellung:
class Shopware_Components_Document extends Enlight_Class implements Enlight_Hook {
Damit steht diese Klasse automatisch im Hook-System zur Verfügung und kann modifiziert werden!
Artikel-PDF erstellen
Artikel bewerten
Kommentare:
Artikel kommentieren
Weitere interessante Artikel:
Bestell-Nr.: SW1495
Lieferzeit ca. 5 Tage
Preise inkl. gesetzlicher
MwSt. zzgl. Versandkosten*
Preise inkl. gesetzlicher
MwSt. + Versandkosten*
Kategorien: