Symfony 8.2 New Published on

Listeners that position themselves relative to each other

#[AsEventListener(after: …, before: …)]: the order of listeners is stated by their names, no longer by guessed priorities.

Topics covered: EventDispatcher

New in Symfony 8.2 (in development). To order listeners, all you had was the priority: an integer, chosen by reading everybody else's. You need to know the 32 of RouterListener and the 16 of LocaleListener to write the 20 that fits between them, and the day you have to slip a step between 20 and 10, you renumber. Symfony 8.2 lets you say what the priority only implied: who goes before whom.

before and after

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

Targets are service ids or classes, alone or in a list. To target only one method of a listener that declares several, write LocaleListener::class.'::onKernelRequest'. A subscriber (EventSubscriberInterface) says the same thing with the before and after keys of getSubscribedEvents().

Everything is resolved when the container is compiled, by a sort that only moves a listener when a constraint forces it to. A missing target (the bundle that provides it isn't installed) is ignored. A cycle, however, is an error, which names the listeners involved.

And the priority?

It stays, but it becomes optional: AsEventListener::$priority now defaults to null, no longer 0.

  • Without a priority, the listener is placed by its constraints, and gets the priority its position requires (0 when possible).
  • With a priority, the constraints only break ties between listeners of the same priority. If they would need to cross it, the container refuses to compile and tells you which priority would be needed.

Your task

The shop has added shipping costs, free from €30, after the discount. FraisDePortListener must therefore run after the promo and before the total, but it has no room: the promo is at 20, the total at 10, and shipping, with no priority, comes after the total. The /order preview shows it: the log reads stock, promo, total, shipping, confirmation, and the total forgets the €4.90 of shipping.

  1. Replace all the priorities of the order listeners with before / after, so that the log becomes stock, promo, shipping, total, confirmation.
  2. Do the same for LangueDuVisiteurListener, whose 20 is just a roundabout way of saying “after the router, before LocaleListener”. The language=fr cookie must still switch the page to French.

Where the feature comes from: the original pull request.