Events and Event Listeners
Warning: You are browsing the documentation for Symfony 2.x, which is no longer maintained.
Read the updated version of this page for Symfony 7.1 (the current stable version).
During the execution of a Symfony application, lots of event notifications are triggered. Your application can listen to these notifications and respond to them by executing any piece of code.
Symfony triggers several events related to the kernel while processing the HTTP Request. Third-party bundles may also dispatch events, and you can even dispatch custom events from your own code.
All the examples shown in this article use the same KernelEvents::EXCEPTION
event for consistency purposes. In your own application, you can use any event
and 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
// src/AppBundle/EventListener/ExceptionListener.php
namespace AppBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
class ExceptionListener
{
public function onKernelException(GetResponseForExceptionEvent $event)
{
// You get the exception object from the received event
$exception = $event->getException();
$message = sprintf(
'My Error says: %s with code: %s',
$exception->getMessage(),
$exception->getCode()
);
// Customize your response object to display the exception details
$response = new Response();
$response->setContent($message);
// HttpExceptionInterface is a special type of exception that
// holds status code and header details
if ($exception instanceof HttpExceptionInterface) {
$response->setStatusCode($exception->getStatusCode());
$response->headers->replace($exception->getHeaders());
} else {
$response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
}
// sends the modified response object to the event
$event->setResponse($response);
}
}
Tip
Each event receives a slightly different type of $event
object. For
the kernel.exception
event, it is GetResponseForExceptionEvent.
Check out the Symfony events reference to see
what type of object each event provides.
Now that the class is created, you just need to register it as a service and
notify Symfony that it is a "listener" on the kernel.exception
event by
using a special "tag":
1 2 3 4 5 6
# app/config/services.yml
services:
app.exception_listener:
class: AppBundle\EventListener\ExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="app.exception_listener"
class="AppBundle\EventListener\ExceptionListener">
<tag name="kernel.event_listener" event="kernel.exception" />
</service>
</services>
</container>
1 2 3 4 5 6 7
// app/config/services.php
use AppBundle\EventListener\ExceptionListener;
$container
->register('app.exception_listener', ExceptionListener::class)
->addTag('kernel.event_listener', array('event' => 'kernel.exception'))
;
Note
There is an optional tag attribute called method
which defines which method
to execute when the event is triggered. By default the name of the method is
on
+ "camel-cased event name". If the event is kernel.exception
the
method executed by default is onKernelException()
.
The other optional tag attribute is called priority
, which defaults to
0
and it controls the order in which listeners are executed (the higher
the number the earlier a listener is executed). This is useful when you
need to guarantee that one listener is executed before another. The priorities
of the internal Symfony listeners usually range from -255
to 255
but
your own 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 class that defines one or more methods that listen to one or various events. The main difference with the event listeners is that subscribers always know which events they are listening to.
In a given subscriber, different methods can listen to the same event. The order
in which methods are executed is defined by the priority
parameter of each
method (the higher the number the earlier the method is called). To learn more
about event subscribers, read The EventDispatcher Component.
The following example shows an event subscriber that defines several methods which
listen to the same kernel.exception
event:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
// src/AppBundle/EventSubscriber/ExceptionSubscriber.php
namespace AppBundle\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class ExceptionSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
// return the subscribed events, their methods and priorities
return array(
KernelEvents::EXCEPTION => array(
array('processException', 10),
array('logException', 0),
array('notifyException', -10),
)
);
}
public function processException(GetResponseForExceptionEvent $event)
{
// ...
}
public function logException(GetResponseForExceptionEvent $event)
{
// ...
}
public function notifyException(GetResponseForExceptionEvent $event)
{
// ...
}
}
Now, you just need to register the class as a service and add the
kernel.event_subscriber
tag to tell Symfony that this is an event subscriber:
1 2 3 4 5 6
# app/config/services.yml
services:
app.exception_subscriber:
class: AppBundle\EventSubscriber\ExceptionSubscriber
tags:
- { name: kernel.event_subscriber }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="app.exception_subscriber"
class="AppBundle\EventSubscriber\ExceptionSubscriber">
<tag name="kernel.event_subscriber"/>
</service>
</services>
</container>
1 2 3 4 5 6 7
// app/config/services.php
use AppBundle\EventSubscriber\ExceptionSubscriber;
$container
->register('app.exception_subscriber', ExceptionSubscriber::class)
->addTag('kernel.event_subscriber')
;
Request Events, Checking Types
A single page can make several requests (one master request, and then multiple sub-requests - typically by How to Embed Controllers in a Template). For the core Symfony events, you might need to check to see if the event is for a "master" request or a "sub request":
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// src/AppBundle/EventListener/RequestListener.php
namespace AppBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class RequestListener
{
public function onKernelRequest(GetResponseEvent $event)
{
if (!$event->isMasterRequest()) {
// don't do anything if it's not the master request
return;
}
// ...
}
}
Certain things, like checking information on the real request, may not need to be done on the sub-request listeners.
Listeners or Subscribers
Listeners and subscribers can be used in the same application indistinctly. The decision 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 kept in the class rather than in the service definition. This is the reason why Symfony uses subscribers internally;
- Listeners are more flexible because bundles can enable or disable each of them conditionally depending on some configuration value.
Debugging Event Listeners
You can find out what listeners are registered in the event dispatcher using the console. To show all events and their listeners, run:
1
$ php app/console debug:event-dispatcher
You can get registered listeners for a particular event by specifying its name:
1
$ php app/console debug:event-dispatcher kernel.exception