Seit der letzten Version von TYPO3 bzw. von ExtBase wurde das Signal/Slot Design Pattern in ExtBase integriert bzw. von FLOW zurückportiert. Ein Feine Sache! Zusammengefasst soll es das Hook-Konzept ergänzen bzw. ersetzen. In diesem Tutorial möchte ich euch zeigen wie ihr das Pattern benutzen könnte.
Genauso wie der Hook besteht das Signal/Slot Pattern aus zwei Bausteinen. Auf der einen Seite sind die Slots (Connector, Listener) und auf der anderen Seite die Signale (Dispatcher). Beide Funktionalität sind über die Klasse „Tx_Extbase_SignalSlot_Dispatcher“ erreichbar, welche wir uns zuerst erstellen müssen. Dies geht entweder über Dependency Injection (z.B. im Controller):
/** * @var Tx_Extbase_SignalSlot_Dispatcher */ protected $signalSlotDispatcher; /** * @param Tx_Extbase_SignalSlot_Dispatcher $signalSlotDispatcher */ public function injectSignalSlotDispatcher(Tx_Extbase_SignalSlot_Dispatcher $signalSlotDispatcher) { $this->signalSlotDispatcher = $signalSlotDispatcher; } |
oder aber auch über einfaches erstellen der Instanz:
$this->signalSlotDispatcher = t3lib_div::makeInstance('Tx_Extbase_Object_Manager')->get('Tx_Extbase_SignalSlot_Dispatcher'); |
Im Anschluss verfügt ihr über ein „Tx_Extbase_SignalSlot_Dispatcher“ Objekt mit dem ihr nun Signale senden oder Slots registrieren könnte. Im Folgenden nun die beiden Sichten, welche möglich sind.
Dispatch / Signal
Beispiel: Am Ende eurer Action stellt ihr alle nötigen Variablen der View bereit. Nun befindet ihr euch an einer Stelle, welcher gern erweitert wird, weshalb ihr euch für ein „Signal“ entscheidet. Das Signal wird über den Signal/Slot-Dispatcher getriggert und kann von anderen Extensions benutzt werden, um die eigene Action zu ergänzen. Hier der Beispielcode:
$this->signalSlotDispatcher->dispatch(__CLASS__, 'beforeRenderView', array($data, $this)); |
Die Funktion hat drei Parameter „Klassenname“, „Signalname“ und „Parameter“. Der Klassennamen ist ähnlich einem Namespace zu betrachten. „__CLASS__“ macht hier meistens Sinn – möglich wäre aber auch „get_class($this)“. Achtung/Tipp: Letzteres hat einen interessanten Vererbungseffekt, sodass eine vererbte Klasse automatisch andere Signale schickt als die Klasse von der geerbt wurde. Evtl. Tricky, deshalb empfehle ich anfangs „__CLASS__“.
Der Signalname ist frei wählbar und sollte die Position und Funktion beschreiben. Bei den Parametern sollten alle nötigen Parameter übergeben werden, sodass diese von einem Externen gut verarbeitet werden können.
Connect / Slot
Beispiel: Wir haben die Action (oben) gesehen und wollen die von außen (aber auch in der selben Extension wäre es möglich!) bearbeiten. Dazu erstellen wir uns ebenfalls den Signal/Slog-Dispatcher und registrieren eine Callback-Function (Slot / Listener) für das Signal. Hierzu gibt es verschiedene Möglichkeiten:
Anonym mit einem Closure,
$this->signalSlotDispatcher->connect( 'Tx_Extension_Controller_NameController', 'beforeRenderView', function($data, $obj) { /* ... */ }, NULL, FALSE ); |
eine Methode aus dem aktuellen Objekt oder
$this->signalSlotDispatcher->connect( 'Tx_Extension_Controller_NameController', 'beforeRenderView', $this, 'addInformation', FALSE ); |
eine Methode aus einem anderen Objekt.
$this->signalSlotDispatcher->connect( 'Tx_Extension_Controller_NameController', 'beforeRenderView', 'Tx_OtherExtension_Controller_NameController', 'addOtherInformation', FALSE ); |
Wie ihr seht sind die ersten beiden Parameter identisch zu dem „Signal-Aufruf“. Diese diesen der Identifikation des Signals. Über die beiden folgenden Parameter wird die Callback-Funktion gesteuert. Der letzte Parameter (welcher hier auf FALSE steht) kann auf TRUE gesetzt werden, wenn ihr in der Slot-Klasse zusätzliche Informationen über das Signal benötigt. Diese stehen dann als erster Parameter in der Zielfunktion zur Verfügung.
Fazit
Ein wirklich schönes Pattern – sauberer und einheitlicher als die „üblichen“ Hooks. Gerade bei den Hooks war störend, das viele mit „User“-Functions benutzt werden mussten, weshalb die Klassen mit „user_“ beginnen mussten. Das neue Pattern ist leicht zu bedienen und schlank im Einsatz. Felix, Vielen Dank dafür. Weitere Informationen bekommt ihr in der API.
Vielen Dank für die Inspiration: blog.tolleiv.de und blog.foertel.com