Symfony 8.2 Nouveauté Publié le

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.

Notions abordées : EventDispatcher

Nouveau dans Symfony 8.2 (en développement). Pour ordonner des écouteurs, on n'avait que la priorité : un entier, choisi en lisant celles des autres. Il faut connaître le 32 de RouterListener et le 16 de LocaleListener pour écrire le 20 qui passe entre les deux, et le jour où l'on doit glisser une étape entre 20 et 10, on renumérote. Symfony 8.2 laisse dire ce que la priorité ne faisait que sous-entendre : qui passe avant qui.

before et after

#[AsEventListener(after: AppliquerCodePromoListener::class, before: CalculerTotalListener::class)]
class FraisDePortListener

Les cibles sont des identifiants de service ou des classes, seuls ou en liste. Pour ne viser qu'une méthode d'un écouteur qui en déclare plusieurs, on écrit LocaleListener::class.'::onKernelRequest'. Un abonné (EventSubscriberInterface) dit la même chose avec les clés before et after de getSubscribedEvents().

Tout se résout à la compilation du conteneur, par un tri qui ne déplace un écouteur que si une contrainte l'y oblige. Une cible absente — le bundle qui la fournit n'est pas installé — est ignorée. Un cycle, lui, est une erreur, qui nomme les écouteurs en cause.

Et la priorité ?

Elle reste, mais elle devient facultative : AsEventListener::$priority vaut désormais null par défaut, et non plus 0.

  • Sans priorité, l'écouteur est placé par ses contraintes, et reçoit la priorité que sa place exige — 0 quand c'est possible.
  • Avec une priorité, les contraintes ne font plus que départager les écouteurs de même priorité. Si elles demandaient de la franchir, le conteneur refuse de compiler et dit quelle priorité il faudrait.

À faire

La boutique a ajouté les frais de port — offerts à partir de 30 €, remise déduite. FraisDePortListener doit donc tourner après la promo et avant le total, mais il n'a pas de place : la promo est à 20, le total à 10, et le port, sans priorité, passe après le total. L'aperçu /commande le montre : le journal lit stock, promo, total, port, confirmation, et le total oublie les 4,90 € de port.

  1. Remplacez toutes les priorités des écouteurs de la commande par des before / after, de sorte que le journal devienne stock, promo, port, total, confirmation.
  2. Faites de même pour LangueDuVisiteurListener, dont le 20 n'est qu'une façon détournée de dire « après le routeur, avant LocaleListener ». Le cookie langue=en doit toujours passer la page en anglais.

D'où vient la fonctionnalité : la pull request d'origine.