diff --git a/cookbook/event_dispatcher/event_listener.rst b/cookbook/event_dispatcher/event_listener.rst
index 3dd9987266c..939646339a9 100644
--- a/cookbook/event_dispatcher/event_listener.rst
+++ b/cookbook/event_dispatcher/event_listener.rst
@@ -1,27 +1,36 @@
.. index::
single: Events; Create listener
+ single: Create subscriber
-How to Create an Event Listener
-===============================
+How to Create Event Listeners and Subscribers
+=============================================
-Symfony has various events and hooks that can be used to trigger custom
-behavior in your application. Those events are thrown by the HttpKernel
-component and can be viewed in the :class:`Symfony\\Component\\HttpKernel\\KernelEvents` class.
+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.
-To hook into an event and add your own custom logic, you have to create
-a service that will act as an event listener on that event. In this entry,
-you will create a service that will act as an exception listener, allowing
-you to modify how exceptions are shown by your application. The ``KernelEvents::EXCEPTION``
-event is just one of the core kernel events::
+Internal events provided by Symfony itself are defined in the
+:class:`Symfony\\Component\\HttpKernel\\KernelEvents` class. Third-party bundles
+and libraries also trigger lots of events and your own application can trigger
+:doc:`custom events `.
- // src/AppBundle/EventListener/AcmeExceptionListener.php
+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**::
+
+ // 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 AcmeExceptionListener
+ class ExceptionListener
{
public function onKernelException(GetResponseForExceptionEvent $event)
{
@@ -57,12 +66,6 @@ event is just one of the core kernel events::
the ``kernel.exception`` event, it is :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent`.
To see what type of object each event listener receives, see :class:`Symfony\\Component\\HttpKernel\\KernelEvents`.
-.. note::
-
- When setting a response for the ``kernel.request``, ``kernel.view`` or
- ``kernel.exception`` events, the propagation is stopped, so the lower
- priority listeners on that event don't get called.
-
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":
@@ -73,31 +76,145 @@ using a special "tag":
# app/config/services.yml
services:
- kernel.listener.your_listener_name:
- class: AppBundle\EventListener\AcmeExceptionListener
+ app.exception_listener:
+ class: AppBundle\EventListener\ExceptionListener
tags:
- - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
+ - { name: kernel.event_listener, event: kernel.exception }
.. code-block:: xml
-
-
-
+
+
+
+
+
+
+
+
+
+
.. code-block:: php
// app/config/services.php
$container
- ->register('kernel.listener.your_listener_name', 'AppBundle\EventListener\AcmeExceptionListener')
- ->addTag('kernel.event_listener', array('event' => 'kernel.exception', 'method' => 'onKernelException'))
+ ->register('app.exception_listener', 'AppBundle\EventListener\ExceptionListener')
+ ->addTag('kernel.event_listener', array('event' => 'kernel.exception'))
;
.. note::
- There is an additional tag option ``priority`` that is optional and defaults
- to 0. The listeners will be executed in the order of their priority (highest to lowest).
- This is useful when you need to guarantee that one listener is executed before another.
+ 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 highest
+ the priority, 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 priority the earlier the method is called). To learn more
+about event subscribers, read :doc:`/components/event_dispatcher/introduction`.
+
+The following example shows an event subscriber that defines several methods which
+listen to the same ``kernel.exception`` event::
+
+ // src/AppBundle/EventSubscriber/ExceptionSubscriber.php
+ namespace AppBundle\EventSubscriber;
+
+ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+ use Symfony\Component\HttpFoundation\Response;
+ use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
+ use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
+
+ class ExceptionSubscriber implements EventSubscriberInterface
+ {
+ public static function getSubscribedEvents()
+ {
+ // return the subscribed events, their methods and priorities
+ return array(
+ 'kernel.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:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # app/config/services.yml
+ services:
+ app.exception_subscriber:
+ class: AppBundle\EventSubscriber\ExceptionSubscriber
+ tags:
+ - { name: kernel.event_subscriber }
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ // app/config/services.php
+ $container
+ ->register(
+ 'app.exception_subscriber',
+ 'AppBundle\EventSubscriber\ExceptionSubscriber'
+ )
+ ->addTag('kernel.event_subscriber')
+ ;
Request Events, Checking Types
------------------------------
@@ -107,17 +224,18 @@ sub-requests), which is why when working with the ``KernelEvents::REQUEST``
event, you might need to check the type of the request. This can be easily
done as follow::
- // src/AppBundle/EventListener/AcmeRequestListener.php
+ // 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 AcmeRequestListener
+ class RequestListener
{
public function onKernelRequest(GetResponseEvent $event)
{
- if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) {
+ if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) {
// don't do anything if it's not the master request
return;
}
@@ -131,3 +249,16 @@ done as follow::
Two types of request are available in the :class:`Symfony\\Component\\HttpKernel\\HttpKernelInterface`
interface: ``HttpKernelInterface::MASTER_REQUEST`` and
``HttpKernelInterface::SUB_REQUEST``.
+
+Events 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.