Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cf6bc3d

Browse files
committed
feature #5377 Added a cookbook section about event subscribers (beni0888, javiereguiluz)
This PR was merged into the 2.3 branch. Discussion ---------- Added a cookbook section about event subscribers | Q | A | ------------- | --- | Doc fix? | no | New docs? | yes | Applies to | all | Fixed tickets | - This PR finishes the work made by @beni0888 in #4538. Commits ------- b5a82ca Final changes ba9ec6b Reworded the introduction and other minor fixes 483f029 Added a note about the advantages/drawbacks of listeners/subscribers e56fed8 Fixed minor issues c8c8bf8 Reworded the subscriber introduction 36b1d10 Fixed the name of the services file a444951 Implemented the suggestions made by @xabbuh 9a6dab7 Completed the cookbook about the event subscriber 0184e0f Added a note about the priority meaning in event subscribers
2 parents 4c9b568 + b5a82ca commit cf6bc3d

File tree

1 file changed

+163
-32
lines changed

1 file changed

+163
-32
lines changed

cookbook/event_dispatcher/event_listener.rst

Lines changed: 163 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,36 @@
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-
6669
Now that the class is created, you just need to register it as a service and
6770
notify Symfony that it is a "listener" on the ``kernel.exception`` event by
6871
using 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``
107224
event, you might need to check the type of the request. This can be easily
108225
done 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

Comments
 (0)