Events and Event Listeners

During the execution of a Symfony application, lots of event notifications aretriggered. Your application can listen to these notifications and respond tothem by executing any piece of code.

Symfony triggers several events related to the kernelwhile processing the HTTP Request. Third-party bundles may also dispatch events, andyou can even dispatch custom events from yourown code.

All the examples shown in this article use the same KernelEvents::EXCEPTIONevent for consistency purposes. In your own application, you can use any eventand even mix several of them in the same subscriber.

Creating an Event Listener

The most common way to listen to an event is to register an event listener:

  1. // src/EventListener/ExceptionListener.php
  2. namespace App\EventListener;
  3.  
  4. use Symfony\Component\HttpFoundation\Response;
  5. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  6. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  7.  
  8. class ExceptionListener
  9. {
  10. public function onKernelException(ExceptionEvent $event)
  11. {
  12. // You get the exception object from the received event
  13. $exception = $event->getException();
  14. $message = sprintf(
  15. 'My Error says: %s with code: %s',
  16. $exception->getMessage(),
  17. $exception->getCode()
  18. );
  19.  
  20. // Customize your response object to display the exception details
  21. $response = new Response();
  22. $response->setContent($message);
  23.  
  24. // HttpExceptionInterface is a special type of exception that
  25. // holds status code and header details
  26. if ($exception instanceof HttpExceptionInterface) {
  27. $response->setStatusCode($exception->getStatusCode());
  28. $response->headers->replace($exception->getHeaders());
  29. } else {
  30. $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
  31. }
  32.  
  33. // sends the modified response object to the event
  34. $event->setResponse($response);
  35. }
  36. }

Tip

Each event receives a slightly different type of $event object. Forthe kernel.exception event, it is ExceptionEvent.Check out the Symfony events reference to seewhat type of object each event provides.

New in version 4.3: The ExceptionEvent class wasintroduced in Symfony 4.3. In previous versions it was calledSymfony\Component\HttpKernel\Event\GetResponseForExceptionEvent.

Now that the class is created, you need to register it as a service andnotify Symfony that it is a "listener" on the kernel.exception event byusing a special "tag":

  • YAML
  1. # config/services.yaml
  2. services:
  3. App\EventListener\ExceptionListener:
  4. tags:
  5. - { name: kernel.event_listener, event: kernel.exception }
  • XML
  1. <!-- config/services.xml -->
  2. <?xml version="1.0" encoding="UTF-8" ?>
  3. <container xmlns="http://symfony.com/schema/dic/services"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://symfony.com/schema/dic/services
  6. https://symfony.com/schema/dic/services/services-1.0.xsd">
  7.  
  8. <services>
  9. <service id="App\EventListener\ExceptionListener">
  10. <tag name="kernel.event_listener" event="kernel.exception"/>
  11. </service>
  12. </services>
  13. </container>
  • PHP
  1. // config/services.php
  2. use App\EventListener\ExceptionListener;
  3.  
  4. $container
  5. ->autowire(ExceptionListener::class)
  6. ->addTag('kernel.event_listener', ['event' => 'kernel.exception'])
  7. ;

Symfony follows this logic to decide which method to execute inside the eventlistener class:

  • If the kernel.event_listener tag defines the method attribute, that'sthe name of the method to be executed;
  • If no method attribute is defined, try to execute the method whose nameis on + "camel-cased event name" (e.g. onKernelException() method forthe kernel.exception event);
  • If that method is not defined either, try to execute the __invoke() magicmethod (which makes event listeners invokable);
  • If the _invoke() method is not defined either, throw an exception.

Note

There is an optional attribute for the kernel.event_listener tag calledpriority, which is a positive or negative integer that defaults to 0and it controls the order in which listeners are executed (the higher thenumber, the earlier a listener is executed). This is useful when you need toguarantee that one listener is executed before another. The priorities of theinternal Symfony listeners usually range from -255 to 255 but yourown listeners can use any positive or negative integer.

Creating an Event Subscriber

Another way to listen to events is via an event subscriber, which is a classthat defines one or more methods that listen to one or various events. The maindifference with the event listeners is that subscribers always know which eventsthey are listening to.

In a given subscriber, different methods can listen to the same event. The orderin which methods are executed is defined by the priority parameter of eachmethod (the higher the number the earlier the method is called). To learn moreabout event subscribers, read The EventDispatcher Component.

The following example shows an event subscriber that defines several methods whichlisten to the same kernel.exception event:

  1. // src/EventSubscriber/ExceptionSubscriber.php
  2. namespace App\EventSubscriber;
  3.  
  4. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  5. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  6. use Symfony\Component\HttpKernel\KernelEvents;
  7.  
  8. class ExceptionSubscriber implements EventSubscriberInterface
  9. {
  10. public static function getSubscribedEvents()
  11. {
  12. // return the subscribed events, their methods and priorities
  13. return [
  14. KernelEvents::EXCEPTION => [
  15. ['processException', 10],
  16. ['logException', 0],
  17. ['notifyException', -10],
  18. ],
  19. ];
  20. }
  21.  
  22. public function processException(ExceptionEvent $event)
  23. {
  24. // ...
  25. }
  26.  
  27. public function logException(ExceptionEvent $event)
  28. {
  29. // ...
  30. }
  31.  
  32. public function notifyException(ExceptionEvent $event)
  33. {
  34. // ...
  35. }
  36. }

That's it! Your services.yaml file should already be setup to load services fromthe EventSubscriber directory. Symfony takes care of the rest.

Tip

If your methods are not called when an exception is thrown, double-check thatyou're loading services fromthe EventSubscriber directory and have autoconfigureenabled. You can also manually add the kernel.event_subscriber tag.

Request Events, Checking Types

A single page can make several requests (one master request, and then multiplesub-requests - typically when embedding controllers in templates).For the core Symfony events, you might need to check to see if the event is fora "master" request or a "sub request":

  1. // src/EventListener/RequestListener.php
  2. namespace App\EventListener;
  3.  
  4. use Symfony\Component\HttpKernel\Event\RequestEvent;
  5.  
  6. class RequestListener
  7. {
  8. public function onKernelRequest(RequestEvent $event)
  9. {
  10. if (!$event->isMasterRequest()) {
  11. // don't do anything if it's not the master request
  12. return;
  13. }
  14.  
  15. // ...
  16. }
  17. }

Certain things, like checking information on the real request, may not need tobe done on the sub-request listeners.

Listeners or Subscribers

Listeners and subscribers can be used in the same application indistinctly. Thedecision to use either of them is usually a matter of personal taste. However,there are some minor advantages for each of them:

  • Subscribers are easier to reuse because the knowledge of the events is keptin the class rather than in the service definition. This is the reason whySymfony uses subscribers internally;
  • Listeners are more flexible because bundles can enable or disable each ofthem conditionally depending on some configuration value.

Debugging Event Listeners

You can find out what listeners are registered in the event dispatcherusing the console. To show all events and their listeners, run:

  1. $ php bin/console debug:event-dispatcher

You can get registered listeners for a particular event by specifyingits name:

  1. $ php bin/console debug:event-dispatcher kernel.exception

Learn more