Observer/Event-System in Magento verstehen
Observer/Event-System in Magento verstehen
~6 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026
Block 3 hat ausschließlich Zustand geschaffen: Attribute, ein Backend Model, ein Resolver-Service - aber noch keine einzige Zeile reagiert tatsächlich auf ein echtes Geschäftsereignis wie "ein Kunde hat eine Bestellung abgeschlossen". PointsCalculator (Kapitel 5) wartet seit Kapitel 5 darauf, aufgerufen zu werden. Block 4 schließt genau diese Lücke - und dieses Kapitel legt das nötige Grundwissen, bevor Kapitel 30 den ersten echten Observer dieser Serie schreibt.
Was ist ein Event?
Magento besitzt einen zentralen Event-Manager (\Magento\Framework\Event\ManagerInterface), der an unzähligen Stellen im Core - und in jedem eigenen Modul - über dispatch() aufgerufen wird, sobald etwas Bemerkenswertes passiert ist: eine Bestellung wurde platziert, ein Produkt wurde gespeichert, eine Gutschrift wurde angelegt. Der dispatchende Code kennt dabei keinen einzigen Zuhörer - klassisches Publish/Subscribe, vollständig entkoppelt.
// Irgendwo im Magento-Core, sinngemäß:
$this->eventManager->dispatch(
'sales_order_place_after',
['order' => $order]
);Einen Observer registrieren: events.xml
Ein eigenes Modul "abonniert" ein Event über etc/events.xml - wahlweise global (etc/events.xml, gilt in jeder Area) oder auf eine Area beschränkt (etc/frontend/events.xml, etc/adminhtml/events.xml, etc/webapi_rest/events.xml und so weiter - dasselbe Area-Prinzip wie bei di.xml). Das name-Attribut des <observer>-Knotens ist der Merge-Schlüssel über Module hinweg, exakt wie bei Block- und Layout-XML.
<!-- Schema-Skizze, kein reales Datei-Beispiel dieses Moduls -->
<config>
<event name="event_name_hier">
<observer name="eindeutiger_observer_name"
instance="Vendor\Modul\Observer\MeinObserver"/>
</event>
</config>ObserverInterface: die Vertrags-Seite
Jede Observer-Klasse implementiert \Magento\Framework\Event\ObserverInterface mit genau einer Methode: execute(\Magento\Framework\Event\Observer $observer): void. Der übergebene Observer kapselt die beim dispatch() übergebenen Daten - Zugriff über getEvent()->getData('order') oder, sofern Magento einen entsprechenden magischen Getter kennt, direkt getEvent()->getOrder().
declare(strict_types=1);
namespace Vendor\Modul\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
class MeinObserver implements ObserverInterface
{
public function execute(Observer $observer): void
{
$order = $observer->getEvent()->getData('order');
// ...
}
}Observer laufen synchron und blockierend
Achtung: Ein events.xml-Observer läuft synchron, im selben PHP-Prozess wie der Code, der ihn ausgelöst hat - anders als eine echte Message Queue (Magento besitzt mit Magento_MessageQueue/Magento_AsynchronousOperations ein eigenes, komplett separates Publish/Consumer-System, das in dieser Serie bewusst nicht behandelt wird). Ein langsamer oder eine Exception werfender Observer auf einem Checkout-kritischen Event verzögert oder zerstört genau diesen Request. Kapitel 30 zeigt die konkrete Konsequenz für AwardPointsOnOrderPlaced.
Welche Events gibt es überhaupt?
- Namenskonvention:
<entity>_<aktion>_<zeitpunkt>, meist_before/_after. - Jede
AbstractModel-Entität mit gesetztem$_eventPrefixfeuert automatisch<prefix>_save_before,<prefix>_save_after,<prefix>_load_after,<prefix>_delete_afterund mehr - ganz ohne eigenendispatch()-Aufruf im eigenen Code. - Welche Daten ein konkretes Event mitliefert, steht ausschließlich im jeweiligen
dispatch()-Aufruf im Core-Quellcode - nicht zuverlässig in Doku, die veralten kann.
Tipp: Statt Event-Namen und -Daten auswendig zu lernen: direkt im Vendor-Verzeichnis nachsehen. bin/cli grep -rn "eventManager->dispatch" vendor/magento/module-sales/Model/Order.php zeigt exakt, welche Events \Magento\Sales\Model\Order feuert und mit welchen Daten - zuverlässiger als jede Drittanbieter-Liste.
Mit diesem Grundwissen registriert Kapitel 30 den ersten echten Observer dieser Serie - AwardPointsOnOrderPlaced - auf sales_order_place_after und verknüpft dabei zum ersten Mal PointsCalculator (Kapitel 5), CategoryBonusResolver (Kapitel 27) und das loyalty_points_earned-Sales-Attribut (Kapitel 23) tatsächlich miteinander.