Skip to content

Commit

Permalink
minor #88 Moving event_dispatcher/event_listener.rst -> event_dispatc…
Browse files Browse the repository at this point in the history
…her.rst (weaverryan)

This PR was merged into the 2.7 branch.

Discussion
----------

Moving event_dispatcher/event_listener.rst -> event_dispatcher.rst

Fixes part of #51

This moves event_dispatcher/event_listener.rst -> event_dispatcher.rst, without any changes.

Commits
-------

ac9e6b3 Moving event_dispatcher/event_listener.rst -> event_dispatcher.rst
  • Loading branch information
javiereguiluz committed Jul 15, 2016
2 parents f024e1b + ac9e6b3 commit 00494c1
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 292 deletions.
4 changes: 2 additions & 2 deletions _build/redirection_map
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
/cookbook/security/voters_data_permission /cookbook/security/voters
/cookbook/configuration/pdo_session_storage /cookbook/doctrine/pdo_session_storage
/cookbook/configuration/mongodb_session_storage /cookbook/doctrine/mongodb_session_storage
/cookbook/service_container/event_listener /cookbook/event_dispatcher/event_listener
/cookbook/service_container/event_listener /event_dispatcher
/create_framework/http-foundation /create_framework/http_foundation
/create_framework/front-controller /create_framework/front_controller
/create_framework/http-kernel-controller-resolver /create_framework/http_kernel_controller_resolver
Expand Down Expand Up @@ -137,7 +137,7 @@
/cookbook/email/testing /email/testing
/cookbook/event_dispatcher/before_after_filters /event_dispatcher/before_after_filters
/cookbook/event_dispatcher/class_extension /event_dispatcher/class_extension
/cookbook/event_dispatcher/event_listener /event_dispatcher/event_listener
/cookbook/event_dispatcher/event_listener /event_dispatcher
/cookbook/event_dispatcher/method_behavior /event_dispatcher/method_behavior
/cookbook/expressions /expressions/expressions
/cookbook/form/create_custom_field_type /form/create_custom_field_type
Expand Down
2 changes: 1 addition & 1 deletion controller/error_pages.rst
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ before, but also requires a thorough understanding of Symfony internals. Suppose
that your code throws specialized exceptions with a particular meaning to your
application domain.

:doc:`Writing your own event listener </event_dispatcher/event_listener>`
:doc:`Writing your own event listener </event_dispatcher>`
for the ``kernel.exception`` event allows you to have a closer look at the exception
and take different actions depending on it. Those actions might include logging
the exception, redirecting the user to another page or rendering specialized
Expand Down
285 changes: 283 additions & 2 deletions event_dispatcher.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,286 @@
Event Dispatcher
================
.. index::
single: Events; Create listener
single: Create subscriber

Events and Event Listeners
==========================

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.

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 </components/event_dispatcher>`.

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 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);
}

// Send 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 :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent`.
To see what type of object each event listener receives, see :class:`Symfony\\Component\\HttpKernel\\KernelEvents`
or the documentation about the specific event you're listening to.

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":

.. configuration-block::

.. code-block:: yaml
# app/config/services.yml
services:
app.exception_listener:
class: AppBundle\EventListener\ExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception }
.. code-block:: xml
<!-- 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>
.. code-block:: php
// app/config/services.php
$container
->register('app.exception_listener', 'AppBundle\EventListener\ExceptionListener')
->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 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`.

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\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:

.. 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
<!-- 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>
.. code-block:: php
// app/config/services.php
$container
->register(
'app.exception_subscriber',
'AppBundle\EventSubscriber\ExceptionSubscriber'
)
->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 :doc:`/templating/embedding_controllers`). For the core
Symfony events, you might need to check to see if the event is for a "master" request
or a "sub request"::

// 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.

.. _events-or-subscribers:

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
-------------------------

.. versionadded:: 2.6
The ``debug:event-dispatcher`` command was introduced in Symfony 2.6.

You can find out what listeners are registered in the event dispatcher
using the console. To show all events and their listeners, run:

.. code-block:: bash
$ php app/console debug:event-dispatcher
You can get registered listeners for a particular event by specifying
its name:

.. code-block:: bash
$ php app/console debug:event-dispatcher kernel.exception
.. toctree::
:maxdepth: 1
Expand Down
2 changes: 1 addition & 1 deletion event_dispatcher/before_after_filters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Creating an Event Listener

Next, you'll need to create an event listener, which will hold the logic
that you want executed before your controllers. If you're not familiar with
event listeners, you can learn more about them at :doc:`/event_dispatcher/event_listener`::
event listeners, you can learn more about them at :doc:`/event_dispatcher`::

// src/AppBundle/EventListener/TokenListener.php
namespace AppBundle\EventListener;
Expand Down
Loading

0 comments on commit 00494c1

Please sign in to comment.