Skip to content

Commit ab1d06b

Browse files
committed
added a guide about Symfony2 internals
1 parent a39585a commit ab1d06b

File tree

3 files changed

+364
-0
lines changed

3 files changed

+364
-0
lines changed

guides/internals/index.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Symfony2 Internals
2+
==================
3+
4+
.. toctree::
5+
:maxdepth: 2
6+
7+
overview
8+
kernel

guides/internals/kernel.rst

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
.. index::
2+
single: Internals; Kernel
3+
4+
Kernel
5+
======
6+
7+
:class:`Symfony\\Components\\HttpKernel\\HttpKernel` is the class responsible
8+
for handling client requests. Its main goal is to "convert"
9+
:class:`Symfony\\Components\\HttpFoundation\\Request` objects to
10+
:class:`Symfony\\Components\\HttpFoundation\\Response` ones.
11+
12+
All Symfony2 Kernels implement
13+
:class:`Symfony\\Components\\HttpKernel\\HttpKernelInterface`::
14+
15+
function handle(Request $request = null, $type = self::MASTER_REQUEST, $raw = false);
16+
17+
.. index::
18+
single: Internals; Controller Resolver
19+
20+
Controllers
21+
-----------
22+
23+
To convert a Request to a Response, the Kernel relies on a "Controller". A
24+
Controller can be any valid PHP callable.
25+
26+
The Kernel delegates the selection of the Controller to execute to an
27+
implementation of
28+
:class:`Symfony\\Components\\HttpKernel\\Controller\\ControllerResolverInterface`::
29+
30+
public function getController(Request $request);
31+
32+
public function getArguments(Request $request, $controller);
33+
34+
The
35+
:method:`Symfony\\Components\\HttpKernel\\Controller\\ControllerResolverInterface::getController`
36+
method returns the Controller (a PHP callable) associated with the given
37+
Request. The default implementation
38+
(:class:`Symfony\\Components\\HttpKernel\\Controller\\ControllerResolver`)
39+
looks for a ``_controller`` request attribute that represents the controller
40+
name (a "class::method" string, like
41+
``Bundle\BlogBundle\PostController:indexAction``).
42+
43+
.. tip::
44+
The default implementation uses the
45+
:class:`Symfony\\Bundle\\FrameworkBundle\\RequestListener`
46+
to define the ``_controller`` Request attribute (see below).
47+
48+
The
49+
:method:`Symfony\\Components\\HttpKernel\\Controller\\ControllerResolverInterface::getArguments`
50+
method returns an array of arguments to pass to the Controller callable. The
51+
default implementation automatically resolves the method arguments, based on
52+
the Request attributes.
53+
54+
.. sidebar:: Matching Controller method arguments from Request attributes
55+
56+
For each method argument, Symfony2 tries to get the value of a Request
57+
attribute with the same name. If it is not defined, the argument default
58+
value is used if defined::
59+
60+
// Symfony will look for an 'id' attribute (mandatory)
61+
// and an 'admin' one (optional)
62+
public function showAction($id, $admin = true)
63+
{
64+
// ...
65+
}
66+
67+
.. index::
68+
single: Internals; Request Handling
69+
70+
Handling Requests
71+
-----------------
72+
73+
The ``handle()`` method takes a Request and *always* returns a Response. To
74+
convert the Request, ``handle()`` relies on the Resolver and an ordered chain
75+
of Event notifications (see the next section for more information about each
76+
Event):
77+
78+
1. Before doing anything else, the ``core.request`` event is notified -- if
79+
one of the listener returns a Response, it jumps to step 8 directly;
80+
81+
2. The Resolver is called to determine the Controller to execute;
82+
83+
3. Listeners of the ``core.controller`` event can now manipulate the
84+
Controller callable the way they want (change it, wrap it, ...);
85+
86+
4. The Kernel checks that the Controller is actually a valid PHP callable;
87+
88+
5. The Resolver is called to determine the arguments to pass to the
89+
Controller;
90+
91+
6. The Kernel calls the Controller;
92+
93+
7. Listeners of the ``core.view`` event can change the Controller return value
94+
(to convert it to a Response for instance);
95+
96+
8. Listeners of the ``core.response`` event can manipulate the Response
97+
(content and headers);
98+
99+
9. The Response is returned.
100+
101+
If an Exception is thrown during processing, the ``core.exception`` is
102+
notified and listeners are given a change to convert the Exception to a
103+
Response. If that works, the ``core.response`` event is notified; if not the
104+
Exception is re-thrown.
105+
106+
If you don't want Exceptions to be caught (for embedded requests for
107+
instance), disable the ``core.exception`` event by passing ``true`` as the
108+
third argument to the ``handle()`` method.
109+
110+
.. index::
111+
single: Internals; Internal Requests
112+
113+
Internal Requests
114+
-----------------
115+
116+
At any time during the handling of a request (the 'master' one), a sub-request
117+
can be handled (a forwarded or an embedded one). You can pass the request type
118+
to the ``handle()`` method (its second argument):
119+
120+
* ``HttpKernelInterface::MASTER_REQUEST``;
121+
* ``HttpKernelInterface::FORWARDED_REQUEST``;
122+
* ``HttpKernelInterface::EMBEDDED_REQUEST``.
123+
124+
The type is passed to all events and listeners can act accordingly (some
125+
processing must only occurs on the master request).
126+
127+
.. index::
128+
pair: Kernel; Event
129+
130+
Events
131+
------
132+
133+
All events have a ``request_type`` parameter, which allows listeners to know
134+
the type of the request. For instance, if a listener must only be active for
135+
master requests, add the following code at the beginning of your listener
136+
method::
137+
138+
if (HttpKernelInterface::MASTER_REQUEST !== $event->getParameter('request_type')) {
139+
// return immediately
140+
// if the event is a filter, return the filtered value instead
141+
return;
142+
}
143+
144+
.. tip::
145+
If you are not yet familiar with the Symfony2 Event Dispatcher, read the
146+
:doc:`dedicated chapter </guides/event/overview>` first.
147+
148+
.. index::
149+
single: Event; core.request
150+
151+
``core.request`` Event
152+
~~~~~~~~~~~~~~~~~~~~~~
153+
154+
*Type*: ``notifyUntil()``
155+
156+
*Parameters*: ``request_type`` and ``request``
157+
158+
As the event is notified with the ``notifyUntil()`` method, if a listener
159+
returns a Response object, other listeners won't be called.
160+
161+
This event is used by ``FrameworkBundle`` to populate the ``_controller``
162+
Request attribute, via the
163+
:class:`Symfony\\Bundle\\FrameworkBundle\\RequestListener`. RequestListener
164+
uses a :class:`Symfony\\Components\\Routing\\RouterInterface` object to match
165+
the Request and determine the Controller name (stored in the ``_controller``
166+
Request attribute).
167+
168+
.. index::
169+
single: Event; core.controller
170+
171+
``core.controller`` Event
172+
~~~~~~~~~~~~~~~~~~~~~~~~~
173+
174+
*Type*: ``filter``
175+
176+
*Arguments*: ``request_type`` and ``request``
177+
178+
*Value to filter*: The Controller value
179+
180+
This event is not used by ``FrameworkBundle``.
181+
182+
.. index::
183+
single: Event; core.view
184+
185+
``core.view`` Event
186+
~~~~~~~~~~~~~~~~~~~
187+
188+
*Type*: ``filter``
189+
190+
*Arguments*: ``request_type`` and ``request``
191+
192+
*Value to filter*: The Controller returned value
193+
194+
This event is not used by ``FrameworkBundle``. It can be used to implement a
195+
view sub-system.
196+
197+
.. index::
198+
single: Event; core.response
199+
200+
``core.response`` Event
201+
~~~~~~~~~~~~~~~~~~~~~~~
202+
203+
*Type*: ``filter``
204+
205+
*Arguments*: ``request_type`` and ``request``
206+
207+
*Value to filter*: The Response instance
208+
209+
``FrameworkBundle`` registers several listeners:
210+
211+
* :class:`Symfony\\Components\\HttpKernel\\Profiler\\ProfilerListener`:
212+
collects data for the current request;
213+
214+
* :class:`Symfony\\Components\\HttpKernel\\Profiler\\WebDebugToolbarListener`:
215+
injects the Web Debug Toolbar;
216+
217+
* :class:`Symfony\\Components\\HttpKernel\\ResponseListener`: fixes the
218+
Response ``Content-Type``;
219+
220+
* :class:`Symfony\\Components\\HttpKernel\\Cache\\EsiListener`: adds a
221+
``Surrogate-Control`` HTTP header when the Response needs to be parsed for
222+
ESI tags.
223+
224+
.. index::
225+
single: Event; core.exception
226+
227+
``core.exception`` Event
228+
~~~~~~~~~~~~~~~~~~~~~~~~
229+
230+
*Type*: ``notifyUntil``
231+
232+
*Arguments*: ``request_type``, ``request``, and ``exception``
233+
234+
``FrameworkBundle`` registers a
235+
:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\ExceptionListener` that
236+
forwards the Request to a given Controller (the value of the
237+
``exception_listener.controller`` parameter -- must be in the
238+
``class::method`` notation).
239+
240+
.. _kernel_listener_tag:
241+
242+
Enabling Custom Listeners
243+
-------------------------
244+
245+
To enable a custom listener, add it as a regular service in one of your
246+
configuration, and tag it with ``kernel.listener``:
247+
248+
.. configuration-block::
249+
250+
.. code-block:: yaml
251+
252+
services:
253+
kernel.listener.your_listener_name:
254+
class: Fully\Qualified\Listener\Class\Name
255+
tag: { name: kernel.listener }
256+
257+
.. code-block:: xml
258+
259+
<service id="kernel.listener.your_listener_name" class="Fully\Qualified\Listener\Class\Name">
260+
<tag name="kernel.listener" />
261+
</service>
262+
263+
.. code-block:: php
264+
265+
$container
266+
->register('kernel.listener.your_listener_name', 'Fully\Qualified\Listener\Class\Name')
267+
->addTag('kernel.listener')
268+
;
269+
270+
The Listener must have a ``register()`` method that takes an
271+
``EventDispatcher`` as its argument and registers itself::
272+
273+
/**
274+
* Registers a core.* listener.
275+
*
276+
* @param EventDispatcher $dispatcher An EventDispatcher instance
277+
*/
278+
public function register(EventDispatcher $dispatcher)
279+
{
280+
$dispatcher->connect('core.*', array($this, 'xxxxxxx'));
281+
}

guides/internals/overview.rst

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
.. index::
2+
single: Internals
3+
4+
Internals Overview
5+
==================
6+
7+
Looks like you want to understand how Symfony2 works and how to extend it.
8+
That makes me very happy! This section is an in-depth explanation of the
9+
Symfony2 internals.
10+
11+
.. note::
12+
You only need to read this section if you want to understand how Symfony2
13+
works behind the scene, or if you want to extend Symfony2.
14+
15+
The Symfony2 code is made of several independent layers. Each layer is built
16+
on top of the previous one.
17+
18+
.. tip::
19+
Autoloading is not managed by the framework directly; it's done
20+
independently with the help of the
21+
:class:`Symfony\\Framework\\UniversalClassLoader` class and the
22+
``src/autoload.php`` file. Read the :doc:`dedicated chapter
23+
</guides/tools/autoloader>` for more information.
24+
25+
``HttpFoundation`` Component
26+
----------------------------
27+
28+
The deepest level is the :namespace:`Symfony\\Components\\HttpFoundation`
29+
component. HttpFoundation provides the main objects needed to deal with HTTP.
30+
It is an Object-Oriented abstraction of some native PHP functions and
31+
variables:
32+
33+
* The :class:`Symfony\\Components\\HttpFoundation\\Request` class abstracts
34+
the main PHP global variables like ``$_GET``, ``$_POST``, ``$_COOKIE``,
35+
``$_FILES``, and ``$_SERVER``;
36+
37+
* The :class:`Symfony\\Components\\HttpFoundation\\Response` class abstracts
38+
some PHP functions like ``header()``, ``setcookie()``, and ``echo``;
39+
40+
* The :class:`Symfony\\Components\\HttpFoundation\\Session` and
41+
:class:`Symfony\\Components\\HttpFoundation\\Session\\SessionStorageInterface`
42+
class abstracts session management ``session_*()`` functions.
43+
44+
.. seealso:: Read more about the :doc:`HttpFoundation Component
45+
<http_foundation>`.
46+
47+
``HttpKernel`` Component
48+
------------------------
49+
50+
On top of HttpFoundation is the :namespace:`Symfony\\Components\\HttpKernel`
51+
component. HttpKernel handles the dynamic part of HTTP; it is a thin wrapper
52+
on top of the Request and Response classes to standardize the way Requests are
53+
handled. It also provides extension points and tools that makes it the ideal
54+
starting point to create a Web framework without too much overhead.
55+
56+
.. seealso:: Read more about the :doc:`HttpKernel Component <kernel>`.
57+
58+
``Framework``
59+
-------------
60+
61+
The :namespace:`Symfony\\Framework` adds configurability and extensibility to
62+
the HttpKernel component, thanks to the Dependency Injection component and a
63+
powerful plugin system (bundles).
64+
65+
.. seealso:: Read more about :doc:`Dependency Injection
66+
</guides/dependency_injection/index>` and :doc:`Bundles
67+
</guides/bundles/index>`.
68+
69+
``FrameworkBundle`` Bundle
70+
--------------------------
71+
72+
:namespace:`Symfony\\Bundle\\FrameworkBundle` is the bundle that ties the main
73+
components and libraries together to make a lightweight and fast MVC
74+
framework. It comes with a sensible default configuration and conventions to
75+
ease the learning curve.

0 commit comments

Comments
 (0)