11.. index ::
22 single: Events; Create listener
3+ single: Create subscriber
34
4- How to Create an Event Listener
5- ===============================
5+ How to Create Event Listeners and Subscribers
6+ =============================================
67
7- Symfony has various events and hooks that can be used to trigger custom
8- behavior in your application. Those events are thrown by the HttpKernel
9- component and can be viewed in the :class: ` Symfony \\ Component \\ HttpKernel \\ KernelEvents ` class .
8+ During the execution of a Symfony application, lots of event notifications are
9+ triggered. Your application can listen to these notifications and respond to
10+ them by executing any piece of code .
1011
11- To hook into an event and add your own custom logic, you have to create
12- a service that will act as an event listener on that event. In this entry,
13- you will create a service that will act as an exception listener, allowing
14- you to modify how exceptions are shown by your application. The ``KernelEvents::EXCEPTION ``
15- event is just one of the core kernel events::
12+ Internal events provided by Symfony itself are defined in the
13+ :class: `Symfony\\ Component\\ HttpKernel\\ KernelEvents ` class. Third-party bundles
14+ and libraries also trigger lots of events and your own application can trigger
15+ :doc: `custom events </components/event_dispatcher/index >`.
1616
17- // src/AppBundle/EventListener/AcmeExceptionListener.php
17+ All the examples shown in this article use the same ``KernelEvents::EXCEPTION ``
18+ event for consistency purposes. In your own application, you can use any event
19+ and even mix several of them in the same subscriber.
20+
21+ Creating an Event Listener
22+ --------------------------
23+
24+ The most common way to listen to an event is to register an **event listener **::
25+
26+ // src/AppBundle/EventListener/ExceptionListener.php
1827 namespace AppBundle\EventListener;
1928
2029 use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
2130 use Symfony\Component\HttpFoundation\Response;
2231 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
2332
24- class AcmeExceptionListener
33+ class ExceptionListener
2534 {
2635 public function onKernelException(GetResponseForExceptionEvent $event)
2736 {
@@ -57,12 +66,6 @@ event is just one of the core kernel events::
5766 the ``kernel.exception `` event, it is :class: `Symfony\\ Component\\ HttpKernel\\ Event\\ GetResponseForExceptionEvent `.
5867 To see what type of object each event listener receives, see :class: `Symfony\\ Component\\ HttpKernel\\ KernelEvents `.
5968
60- .. note ::
61-
62- When setting a response for the ``kernel.request ``, ``kernel.view `` or
63- ``kernel.exception `` events, the propagation is stopped, so the lower
64- priority listeners on that event don't get called.
65-
6669Now that the class is created, you just need to register it as a service and
6770notify Symfony that it is a "listener" on the ``kernel.exception `` event by
6871using a special "tag":
@@ -73,31 +76,145 @@ using a special "tag":
7376
7477 # app/config/services.yml
7578 services :
76- kernel.listener.your_listener_name :
77- class : AppBundle\EventListener\AcmeExceptionListener
79+ app.exception_listener :
80+ class : AppBundle\EventListener\ExceptionListener
7881 tags :
79- - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
82+ - { name: kernel.event_listener, event: kernel.exception }
8083
8184 .. code-block :: xml
8285
8386 <!-- app/config/services.xml -->
84- <service id =" kernel.listener.your_listener_name" class =" AppBundle\EventListener\AcmeExceptionListener" >
85- <tag name =" kernel.event_listener" event =" kernel.exception" method =" onKernelException" />
86- </service >
87+ <?xml version =" 1.0" encoding =" UTF-8" ?>
88+ <container xmlns =" http://symfony.com/schema/dic/services"
89+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
90+ xsi : schemaLocation =" http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd" >
91+
92+ <services >
93+ <service id =" app.exception_listener"
94+ class =" AppBundle\EventListener\ExceptionListener" >
95+
96+ <tag name =" kernel.event_listener" event =" kernel.exception" />
97+ </service >
98+ </services >
99+ </container >
87100
88101 .. code-block :: php
89102
90103 // app/config/services.php
91104 $container
92- ->register('kernel.listener.your_listener_name ', 'AppBundle\EventListener\AcmeExceptionListener ')
93- ->addTag('kernel.event_listener', array('event' => 'kernel.exception', 'method' => 'onKernelException' ))
105+ ->register('app.exception_listener ', 'AppBundle\EventListener\ExceptionListener ')
106+ ->addTag('kernel.event_listener', array('event' => 'kernel.exception'))
94107 ;
95108
96109 .. note ::
97110
98- There is an additional tag option ``priority `` that is optional and defaults
99- to 0. The listeners will be executed in the order of their priority (highest to lowest).
100- This is useful when you need to guarantee that one listener is executed before another.
111+ There is an optional tag attribute called ``method `` which defines which method
112+ to execute when the event is triggered. By default the name of the method is
113+ ``on `` + "camel-cased event name". If the event is ``kernel.exception `` the
114+ method executed by default is ``onKernelException() ``.
115+
116+ The other optional tag attribute is called ``priority ``, which defaults to
117+ ``0 `` and it controls the order in which listeners are executed (the highest
118+ the priority, the earlier a listener is executed). This is useful when you
119+ need to guarantee that one listener is executed before another. The priorities
120+ of the internal Symfony listeners usually range from ``-255 `` to ``255 `` but
121+ your own listeners can use any positive or negative integer.
122+
123+ Creating an Event Subscriber
124+ ----------------------------
125+
126+ Another way to listen to events is via an **event subscriber **, which is a class
127+ that defines one or more methods that listen to one or various events. The main
128+ difference with the event listeners is that subscribers always know which events
129+ they are listening to.
130+
131+ In a given subscriber, different methods can listen to the same event. The order
132+ in which methods are executed is defined by the ``priority `` parameter of each
133+ method (the higher the priority the earlier the method is called). To learn more
134+ about event subscribers, read :doc: `/components/event_dispatcher/introduction `.
135+
136+ The following example shows an event subscriber that defines several methods which
137+ listen to the same ``kernel.exception `` event::
138+
139+ // src/AppBundle/EventSubscriber/ExceptionSubscriber.php
140+ namespace AppBundle\EventSubscriber;
141+
142+ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
143+ use Symfony\Component\HttpFoundation\Response;
144+ use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
145+ use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
146+
147+ class ExceptionSubscriber implements EventSubscriberInterface
148+ {
149+ public static function getSubscribedEvents()
150+ {
151+ // return the subscribed events, their methods and priorities
152+ return array(
153+ 'kernel.exception' => array(
154+ array('processException', 10),
155+ array('logException', 0),
156+ array('notifyException', -10),
157+ )
158+ );
159+ }
160+
161+ public function processException(GetResponseForExceptionEvent $event)
162+ {
163+ // ...
164+ }
165+
166+ public function logException(GetResponseForExceptionEvent $event)
167+ {
168+ // ...
169+ }
170+
171+ public function notifyException(GetResponseForExceptionEvent $event)
172+ {
173+ // ...
174+ }
175+ }
176+
177+ Now, you just need to register the class as a service and add the
178+ ``kernel.event_subscriber `` tag to tell Symfony that this is an event subscriber:
179+
180+ .. configuration-block ::
181+
182+ .. code-block :: yaml
183+
184+ # app/config/services.yml
185+ services :
186+ app.exception_subscriber :
187+ class : AppBundle\EventSubscriber\ExceptionSubscriber
188+ tags :
189+ - { name: kernel.event_subscriber }
190+
191+ .. code-block :: xml
192+
193+ <!-- app/config/services.xml -->
194+ <?xml version =" 1.0" encoding =" UTF-8" ?>
195+ <container xmlns =" http://symfony.com/schema/dic/services"
196+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
197+ xsi : schemaLocation =" http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd" >
198+
199+ <services >
200+ <service id =" app.exception_subscriber"
201+ class =" AppBundle\EventSubscriber\ExceptionSubscriber" >
202+
203+ <tag name =" kernel.event_subscriber" />
204+ </service >
205+ </services >
206+ </container >
207+
208+ .. code-block :: php
209+
210+ // app/config/services.php
211+ $container
212+ ->register(
213+ 'app.exception_subscriber',
214+ 'AppBundle\EventSubscriber\ExceptionSubscriber'
215+ )
216+ ->addTag('kernel.event_subscriber')
217+ ;
101218
102219 Request Events, Checking Types
103220------------------------------
@@ -107,17 +224,18 @@ sub-requests), which is why when working with the ``KernelEvents::REQUEST``
107224event, you might need to check the type of the request. This can be easily
108225done as follow::
109226
110- // src/AppBundle/EventListener/AcmeRequestListener .php
227+ // src/AppBundle/EventListener/RequestListener .php
111228 namespace AppBundle\EventListener;
112229
113230 use Symfony\Component\HttpKernel\Event\GetResponseEvent;
114231 use Symfony\Component\HttpKernel\HttpKernel;
232+ use Symfony\Component\HttpKernel\HttpKernelInterface;
115233
116- class AcmeRequestListener
234+ class RequestListener
117235 {
118236 public function onKernelRequest(GetResponseEvent $event)
119237 {
120- if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) {
238+ if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST ) {
121239 // don't do anything if it's not the master request
122240 return;
123241 }
@@ -131,3 +249,16 @@ done as follow::
131249 Two types of request are available in the :class: `Symfony\\ Component\\ HttpKernel\\ HttpKernelInterface `
132250 interface: ``HttpKernelInterface::MASTER_REQUEST `` and
133251 ``HttpKernelInterface::SUB_REQUEST ``.
252+
253+ Events or Subscribers
254+ ---------------------
255+
256+ Listeners and subscribers can be used in the same application indistinctly. The
257+ decision to use either of them is usually a matter of personal taste. However,
258+ there are some minor advantages for each of them:
259+
260+ * **Subscribers are easier to reuse ** because the knowledge of the events is kept
261+ in the class rather than in the service definition. This is the reason why
262+ Symfony uses subscribers internally;
263+ * **Listeners are more flexible ** because bundles can enable or disable each of
264+ them conditionally depending on some configuration value.
0 commit comments