New in Symfony 4.3: Simpler event dispatching
March 25, 2019 • Published by Javier Eguiluz
Warning: This post is about an unsupported Symfony version. Some of this information may be out of date. Read the most recent Symfony Docs.
In Symfony 3.3, we made the class optional for named services and started recommending to use the fully-qualified class name (FQCN) as the service ID. This makes config more intuitive and helps you avoid thinking about arbitrary strings to name services.
Following the same idea, in Symfony 4.3 we've changed the signature of the
EventDispatcherInterface::dispatch()
method:
1 2 3 4 5 6 7 8 9
// ...
$order = new Order();
$newOrderEvent = new OrderPlacedEvent($order);
// Before
$dispatcher->dispatch(OrderEvents::NEW_ORDER, $newOrderEvent);
// After
$dispatcher->dispatch($newOrderEvent, OrderEvents::NEW_ORDER);
Although this change looks minor, it helps simplify the rest of the app code. For starters, you can subscribe to events using the FQCN of the event:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
class StoreSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
// Before
return [
OrderEvents::NEW_ORDER => 'onStoreOrder',
];
// After
return [
OrderPlacedEvent::class => 'onStoreOrder',
];
}
// ...
}
Moreover, the event name is now optional in the dispatch()
method, so you
can pass just the event object:
1 2 3 4 5
// Before
$dispatcher->dispatch(OrderEvents::NEW_ORDER, $newOrderEvent);
// After
$dispatcher->dispatch($newOrderEvent);
In summary, the new dispatch()
signature allows you to develop code based on
pure PHP classes instead of inventing arbitrary strings to name events.
Updated HttpKernel event classes
In addition to the previous change, we've also updated the classes of the events that Symfony passes for its own events. The new names are much more intuitive and concise:
- Renamed
FilterControllerArgumentsEvent
toControllerArgumentsEvent
- Renamed
FilterControllerEvent
toControllerEvent
- Renamed
FilterResponseEvent
toResponseEvent
- Renamed
GetResponseEvent
toRequestEvent
- Renamed
GetResponseForControllerResultEvent
toViewEvent
- Renamed
GetResponseForExceptionEvent
toExceptionEvent
- Renamed
PostResponseEvent
toTerminateEvent
Supporting both dispatchers
Bundles and packages that want to provide forward and/or backward compatibility
with the new and old dispatch()
methods can use the new
LegacyEventDispatcherProxy
class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
class SomeService
{
public function __construct(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
}
public function someMethod()
{
// ...
// use the new way of dispatching events (with or without the event name)
// even if the provided dispatcher still implements the legacy way
$this->dispatcher->dispatch($newOrderEvent);
$this->dispatcher->dispatch($newOrderEvent, OrderEvents::NEW_ORDER);
}
}
Help the Symfony project!
As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.
Comments are closed.
To ensure that comments stay relevant, they are closed for old posts.
And if you develop some package that needs to support both methods at the same time, you can use the LegacyEventDispatcherProxy class as explained in the article.
I usually create one event class by entity with multiple constants for different events (e.g. MyEntityEvent::CREATE, MyEntityEvent::EDIT)
Will it become a bad practice in favor of having one class by event (e.g. MyEntityCreatedEvent, MyEntityEdited) ?
I don't hope so, because that would be a lot of code to duplicate...
The plan is to deprecate it in 5.1 and remove it in 6.0.
> I just wanted to be sure this optional string is not temporary and will not be removed in future release
legit question, I confirm what Javier wrote: named events will remain 1st class supported
the only change you'll need to do is to swap the order of the arguments in the dispatch() method (but only in Symfony 5.0, because in 4.3 and 4.4 will keep working) .
Thanks team.
We use this approach for the last 3 years, so I'm very happy it got into Symfony core:
https://pehapkari.cz/blog/2017/07/12/the-bulletproof-event-naming-for-symfony-event-dispatcher/