Skip to content

Commit a42782f

Browse files
committed
first draft cookbook before/after listeners
1 parent 15595cd commit a42782f

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
.. index::
2+
single: Event Dispatcher
3+
4+
How to setup before and after filters
5+
=====================================
6+
7+
It is quite common in web applications development to need some logic to be executed just before
8+
or just after our controller actions acting as filters or hooks.
9+
10+
In Symfony1, this was achieved with the preExecute and postExecute methods, most major frameworks have similar
11+
methods but there is no such thing in Symfony2. Good news is that there is a much better way to interfere our
12+
Request -> Response process with the EventListener component.
13+
14+
Token validation example
15+
========================
16+
17+
Imagine that we need to develop an API where some controllers are public but some others are restricted
18+
to one or some clients. For this private features, we provide a token to our clients to identify themselves.
19+
20+
So, before executing our controller action, we need to check if the action is restricted or not.
21+
And if it is restricted, we need to validate the provided token.
22+
23+
.. note::
24+
25+
Please note that for simplicity in the recipe, tokens will be defined in config
26+
and neither database setup nor authentication provider via Security component will be used
27+
28+
Creating a before filter with a controller.request event
29+
========================================================
30+
31+
Basic Setup
32+
-----------
33+
34+
We can add basic tokens configuration using config.yml and parameters key
35+
36+
.. configuration-block::
37+
38+
.. code-block:: yaml
39+
40+
# app/config/config.yml
41+
parameters:
42+
tokens:
43+
client1: pass1
44+
client2: pass2
45+
46+
47+
Tag controllers to be checked
48+
-----------------------------
49+
50+
A kernel.controller listener gets executed at every request, so we need some way to identify
51+
if the controller that matches the request needs a token validation.
52+
53+
A clean and easy way is to create an empty interface and make the controllers implement it
54+
55+
.. code-block:: php
56+
57+
namespace Acme\DemoBundle\Controller;
58+
59+
interface TokenAuthenticatedController
60+
{
61+
// Nothing here
62+
}
63+
64+
class FooController implements TokenAuthenticatedController
65+
{
66+
// Your actions that need authentication
67+
}
68+
69+
Creating an Event Listener
70+
--------------------------
71+
72+
.. code-block:: php
73+
74+
namespace Acme\DemoBundle\EventListener;
75+
76+
use Acme\DemoBundle\Controller\TokenAuthenticatedController;
77+
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
78+
79+
class BeforeListener
80+
{
81+
private $tokens;
82+
public function __contruct($tokens)
83+
{
84+
$this->tokens = $tokens;
85+
}
86+
87+
public function onKernelController(FilterControllerEvent $event)
88+
{
89+
$controller = $event->getController();
90+
91+
/**
92+
* $controller passed can be either a class or a Closure. This is not usual in Symfony2 but it may happen.
93+
* If it is a class, it comes in array format
94+
*/
95+
if (!is_array($controller)) return;
96+
97+
if($controller[0] instanceof TokenAuthenticatedController) {
98+
$token = $event->getRequest()->get('token');
99+
if (!in_array($token, $this->tokens)) {
100+
throw new AccessDeniedHttpException('This action needs a valid token!');
101+
}
102+
}
103+
}
104+
}
105+
106+
Tagging the EventListener
107+
-------------------------
108+
109+
.. configuration-block::
110+
111+
.. code-block:: yaml
112+
113+
# app/config/config.yml (or inside or your services.yml)
114+
services:
115+
demo.tokens.action_listener:
116+
class: Acme\DemoBundle\EventListener\BeforeListener
117+
arguments: [ %tokens% ]
118+
tags:
119+
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
120+
121+
.. code-block:: xml
122+
123+
<service id="demo.tokens.action_listener" class="Acme\DemoBundle\EventListener\BeforeListener">
124+
<argument>%tokens%</argument>
125+
<tag name="kernel.event_listener" event="kernel.controller" method="onKernelController" />
126+
</service>
127+
128+
.. code-block:: php
129+
130+
use Symfony\Component\DependencyInjection\Definition;
131+
132+
$listener = new Definition('Acme\DemoBundle\EventListener\BeforeListener', array('%tokens%'));
133+
$listener->addTag('kernel.event_listener', array('event' => 'kernel.controller', 'method' => 'onKernelController'));
134+
$container->setDefinition('demo.tokens.action_listener', $listener);
135+

0 commit comments

Comments
 (0)