1
1
.. index ::
2
2
single: Events; Create listener
3
+ single: Create subscriber
3
4
4
- How to Create an Event Listener
5
- ===============================
5
+ How to Create Event Listeners and Subscribers
6
+ =============================================
6
7
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 .
10
11
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 >`.
16
16
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
18
27
namespace AppBundle\EventListener;
19
28
20
29
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
21
30
use Symfony\Component\HttpFoundation\Response;
22
31
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
23
32
24
- class AcmeExceptionListener
33
+ class ExceptionListener
25
34
{
26
35
public function onKernelException(GetResponseForExceptionEvent $event)
27
36
{
@@ -57,12 +66,6 @@ event is just one of the core kernel events::
57
66
the ``kernel.exception `` event, it is :class: `Symfony\\ Component\\ HttpKernel\\ Event\\ GetResponseForExceptionEvent `.
58
67
To see what type of object each event listener receives, see :class: `Symfony\\ Component\\ HttpKernel\\ KernelEvents `.
59
68
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
-
66
69
Now that the class is created, you just need to register it as a service and
67
70
notify Symfony that it is a "listener" on the ``kernel.exception `` event by
68
71
using a special "tag":
@@ -73,31 +76,145 @@ using a special "tag":
73
76
74
77
# app/config/services.yml
75
78
services :
76
- kernel.listener.your_listener_name :
77
- class : AppBundle\EventListener\AcmeExceptionListener
79
+ app.exception_listener :
80
+ class : AppBundle\EventListener\ExceptionListener
78
81
tags :
79
- - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
82
+ - { name: kernel.event_listener, event: kernel.exception }
80
83
81
84
.. code-block :: xml
82
85
83
86
<!-- 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 >
87
100
88
101
.. code-block :: php
89
102
90
103
// app/config/services.php
91
104
$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'))
94
107
;
95
108
96
109
.. note ::
97
110
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
+ ;
101
218
102
219
Request Events, Checking Types
103
220
------------------------------
@@ -107,17 +224,18 @@ sub-requests), which is why when working with the ``KernelEvents::REQUEST``
107
224
event, you might need to check the type of the request. This can be easily
108
225
done as follow::
109
226
110
- // src/AppBundle/EventListener/AcmeRequestListener .php
227
+ // src/AppBundle/EventListener/RequestListener .php
111
228
namespace AppBundle\EventListener;
112
229
113
230
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
114
231
use Symfony\Component\HttpKernel\HttpKernel;
232
+ use Symfony\Component\HttpKernel\HttpKernelInterface;
115
233
116
- class AcmeRequestListener
234
+ class RequestListener
117
235
{
118
236
public function onKernelRequest(GetResponseEvent $event)
119
237
{
120
- if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) {
238
+ if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST ) {
121
239
// don't do anything if it's not the master request
122
240
return;
123
241
}
@@ -131,3 +249,16 @@ done as follow::
131
249
Two types of request are available in the :class: `Symfony\\ Component\\ HttpKernel\\ HttpKernelInterface `
132
250
interface: ``HttpKernelInterface::MASTER_REQUEST `` and
133
251
``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