Events
Magento observers become event listeners in Symfony: a typed event class instead of a string name and a data array, with priorities and stopping propagation.
Magento · events.xml + Observer
<event name="sales_order_place_after">
<observer name="vendor_send_confirmation"
instance="Vendor\Sales\Observer\SendConfirmation"/>
</event>
class SendConfirmation implements ObserverInterface
{
public function execute(Observer $observer): void
{
$order = $observer->getEvent()->getData('order');
// ...
}
}
$this->eventManager->dispatch(
'sales_order_place_after',
['order' => $order]
);
Symfony · event class + listener
final class OrderPlaced
{
public function __construct(
public readonly int $orderId,
) {}
}
#[AsEventListener(event: OrderPlaced::class)]
final class SendOrderConfirmation
{
public function __invoke(OrderPlaced $event): void
{
// ...
}
}
$this->dispatcher->dispatch(new OrderPlaced($order->getId()));
- An event is a typed class, and the event name is its FQCN. No string keys in an array.
- There is a priority:
#[AsEventListener(priority: 10)], higher runs earlier. In Magento the order of observers is not guaranteed. $event->stopPropagation()stops the remaining listeners (the event has to extendSymfony\Contracts\EventDispatcher\Event).- Doctrine events (
prePersist,postUpdate,onFlush) go through a separate dispatcher:#[AsDoctrineListener],#[AsEntityListener]. - If the reaction is slow (an email, an ERP call), the listener puts a message into Messenger instead of doing the work itself.
Symfony · kernel listener, the equivalent of controller_action_predispatch
#[AsEventListener(event: KernelEvents::REQUEST, priority: 20)]
final class MaintenanceListener
{
public function __construct(
#[Autowire(env: 'bool:MAINTENANCE')]
private bool $maintenance,
) {}
public function __invoke(RequestEvent $event): void
{
if (!$this->maintenance || !$event->isMainRequest()) {
return;
}
$event->setResponse(new Response('Maintenance', 503));
}
}