EventDispatcher Symfony : écouteurs, abonnés et ordre
L'EventDispatcher de Symfony annonce un événement à tous ses écouteurs, l'un après l'autre : on ajoute un comportement sans toucher au code qui l'émet.
// Jusqu'ici : des priorités choisies en lisant celles des autres écouteurs. #[AsEventListener(priority: 20)] class AppliquerCodePromoListener { /* … */ } #[AsEventListener(priority: 10)] class CalculerTotalListener { /* … */ } // Depuis Symfony 8.2 : l'ordre se dit par les noms. #[AsEventListener(after: AppliquerCodePromoListener::class, before: CalculerTotalListener::class)] class FraisDePortListener { public function __invoke(CommandePassee $commande): void { /* … */ } }
Le noyau de Symfony émet ses propres événements à chaque requête, et une application peut dispatcher les siens. Un écouteur se déclare avec #[AsEventListener], un abonné implémente EventSubscriberInterface et liste ses événements dans getSubscribedEvents(). Le piège tient à l'ordre : il se réglait jusqu'ici par des priorités entières, qu'on choisit en lisant celles des autres écouteurs, et qu'on renumérote le jour où une étape doit se glisser entre deux. bin/console debug:event-dispatcher montre l'ordre réel.
Les exercices de cette notion portent sur Symfony 8.2 : écrire getSubscribedEvents() avec des clés nommées, puis remplacer des priorités par des contraintes before et after entre écouteurs.
2 exercices font travailler cette notion, en écrivant du code dans le navigateur.
Dans la Pratique
- Des écouteurs qui se placent les uns par rapport aux autres #[AsEventListener(after: …, before: …)] : l'ordre des écouteurs se dit par leurs noms, plus par des priorités devinées.
- Des abonnés lisibles : method et priority ['tracer', 100] devient ['method' => 'tracer', 'priority' => 100] : getSubscribedEvents() dit enfin ce que contient chaque case.