Skip to content

Commit b57afc0

Browse files
committed
Merge pull request #776 from Nek-/new/custom-route-loader
Adding missing part about custom route loader
2 parents c73e2d1 + 447ad13 commit b57afc0

File tree

2 files changed

+292
-1
lines changed

2 files changed

+292
-1
lines changed
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
.. index::
2+
single: Routage; Chargeur de routes personnalisé
3+
4+
Comment créer un chargeur de routes personnalisé (custom loader)
5+
================================================================
6+
7+
Qu'est-ce qu'un chargeur de routes personnalisé ?
8+
-------------------------------------------------
9+
10+
Un chargeur de routes personnalisé vous permet de générer des
11+
routes basées sur des conventions ou modèles. Un bon exemple
12+
d'utilisation est le `FOSRestBundle`_ où les routes sont générées
13+
en utilisant les noms des actions dans les contrôleurs.
14+
15+
Un chargeur de routes ne permet pas à votre bundle d'injecter des
16+
routes sans modifier la configuration de routing (par exemple ``app/config/routing.yml``) manuellement.
17+
Que votre bundle apporte des routes via un fichier de configuration
18+
– comme le `WebProfilerBundle` fait – ou via un chargeur de routes
19+
personnalisé – comme le `FOSRestBundle`_ fait – une entrée dans la
20+
configuration du routing est toujours nécessaire.
21+
22+
.. note::
23+
24+
Il y a plusieurs bundles qui utilisent leur propre chargeur de
25+
routes, par exemple `FOSRestBundle`_, `JMSI18nRoutingBundle`_,
26+
`KnpRadBundle`_ et `SonataAdminBundle`_.
27+
28+
Charger des routes
29+
------------------
30+
31+
Dans une application Symfony, les routes sont chargées par la classe
32+
:class:`Symfony\\Bundle\\FrameworkBundle\\Routing\\DelegatingLoader`.
33+
Ce chargeur utilise d'autres chargeurs (il « délègue ») pour charger
34+
depuis plusieurs types de ressources, par exemple les fichiers YAML
35+
ou les annotations ``@Route`` et ``@Method`` dans les contrôleurs.
36+
Le chargeur spécialisé implémente
37+
:class:`Symfony\\Component\\Config\\Loader\\LoaderInterface`
38+
et possède donc deux méthodes importantes :
39+
:method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports`
40+
et :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load`.
41+
42+
Prenons ces lignes du fichier ``routing.yml`` de la
43+
Symfony Standard Edition :
44+
45+
.. code-block:: yaml
46+
47+
# app/config/routing.yml
48+
app:
49+
resource: @AppBundle/Controller/
50+
type: annotation
51+
52+
Lorsque le premier chargeurs parse cela, il essaie tous les chargeur
53+
enregistrés comme « déléguant » et appelle leur méthode
54+
:method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports`
55+
avec la ressource (``@AppBundle/Controller/``) et le type (``annotation``)
56+
en argument. Lorsque l'un des chargeurs retourne ``true``, sa méthode
57+
:method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load` va
58+
être appelée, celle-ci doit retourner une :class:`Symfony\\Component\\Routing\\RouteCollection`
59+
qui contient des objets :class:`Symfony\\Component\\Routing\\Route`.
60+
61+
Créer un chargeur personnalisé
62+
------------------------------
63+
64+
Pour charger des routes depuis une source personnalisée (c-a-d
65+
depuis quelque chose d'autre qu'annotations, YAML, ou XML), vous
66+
devez créer un chargeur de routes personnalisé. Ce chargeur doit
67+
implémenter la classe
68+
:class:`Symfony\\Component\\Config\\Loader\\LoaderInterface`.
69+
70+
Dans la plupart des cas il vaut mieux ne pas implémenter
71+
:class:`Symfony\\Component\\Config\\Loader\\LoaderInterface`
72+
par vous même mais étendre la classe
73+
:class:`Symfony\\Component\\Config\\Loader\\Loader`.
74+
75+
L'exemple de chargeur suivant supporte le chargement de ressources de
76+
routes avec le type ``extra``. Le type ``extra`` n'est pas important
77+
– vous pouvez inventer le type de ressources que vous voulez. Le nom
78+
de la ressource n'est pas utilisé dans l'exemple::
79+
80+
// src/AppBundle/Routing/ExtraLoader.php
81+
namespace AppBundle\Routing;
82+
83+
use Symfony\Component\Config\Loader\Loader;
84+
use Symfony\Component\Routing\Route;
85+
use Symfony\Component\Routing\RouteCollection;
86+
87+
class ExtraLoader extends Loader
88+
{
89+
private $loaded = false;
90+
91+
public function load($resource, $type = null)
92+
{
93+
if (true === $this->loaded) {
94+
throw new \RuntimeException('Do not add the "extra" loader twice');
95+
}
96+
97+
$routes = new RouteCollection();
98+
99+
// Préparation de la nouvelle route
100+
$path = '/extra/{parameter}';
101+
$defaults = array(
102+
'_controller' => 'AppBundle:Extra:extra',
103+
);
104+
$requirements = array(
105+
'parameter' => '\d+',
106+
);
107+
$route = new Route($path, $defaults, $requirements);
108+
109+
// Ajout de la nouvelle route à la collection de routes
110+
$routeName = 'extraRoute';
111+
$routes->add($routeName, $route);
112+
113+
$this->loaded = true;
114+
115+
return $routes;
116+
}
117+
118+
public function supports($resource, $type = null)
119+
{
120+
return 'extra' === $type;
121+
}
122+
}
123+
124+
Soyez sûr que le contrôleur que vous spécifiez existe vraiment.
125+
Dans ce cas vous devez créer une méthode ``extraAction`` dans le
126+
contrôleur ``ExtraController`` du bundle ``AppBundle``::
127+
128+
// src/AppBundle/Controller/ExtraController.php
129+
namespace AppBundle\Controller;
130+
131+
use Symfony\Component\HttpFoundation\Response;
132+
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
133+
134+
class ExtraController extends Controller
135+
{
136+
public function extraAction($parameter)
137+
{
138+
return new Response($parameter);
139+
}
140+
}
141+
142+
Définissez maintenant un service pour notre ``ExtraLoader`` :
143+
144+
.. configuration-block::
145+
146+
.. code-block:: yaml
147+
148+
# app/config/services.yml
149+
services:
150+
app.routing_loader:
151+
class: AppBundle\Routing\ExtraLoader
152+
tags:
153+
- { name: routing.loader }
154+
155+
.. code-block:: xml
156+
157+
<?xml version="1.0" ?>
158+
<container xmlns="http://symfony.com/schema/dic/services"
159+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
160+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
161+
162+
<services>
163+
<service id="app.routing_loader" class="AppBundle\Routing\ExtraLoader">
164+
<tag name="routing.loader" />
165+
</service>
166+
</services>
167+
</container>
168+
169+
.. code-block:: php
170+
171+
use Symfony\Component\DependencyInjection\Definition;
172+
173+
$container
174+
->setDefinition(
175+
'app.routing_loader',
176+
new Definition('AppBundle\Routing\ExtraLoader')
177+
)
178+
->addTag('routing.loader')
179+
;
180+
181+
Remarquez le tag ``routing.loader``, tous les services qui possèdent
182+
ce *tag* vont être marqués comme potentiel chargeur de routes et ajoutés
183+
comme chargeur de routes spécifique au *service* ``routing.loader``, qui
184+
est une instance de
185+
:class:`Symfony\\Bundle\\FrameworkBundle\\Routing\\DelegatingLoader`.
186+
187+
Utiliser le chargeur personnalisé
188+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
189+
190+
Si vous n'avez rien fait d'autre, votre chargeur de route personnalisé
191+
ne va *pas* être appelé. Vous devez ajouter quelques lignes à la
192+
configuration du routing :
193+
194+
.. configuration-block::
195+
196+
.. code-block:: yaml
197+
198+
# app/config/routing.yml
199+
app_extra:
200+
resource: .
201+
type: extra
202+
203+
.. code-block:: xml
204+
205+
<?xml version="1.0" encoding="UTF-8" ?>
206+
<routes xmlns="http://symfony.com/schema/routing"
207+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
208+
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
209+
210+
<import resource="." type="extra" />
211+
</routes>
212+
213+
.. code-block:: php
214+
215+
// app/config/routing.php
216+
use Symfony\Component\Routing\RouteCollection;
217+
218+
$collection = new RouteCollection();
219+
$collection->addCollection($loader->import('.', 'extra'));
220+
221+
return $collection;
222+
223+
La partie la plus importante est celle de la clé ``type``. Sa valeur
224+
doit être « extra » car c'est le type supporté par le ``ExtraLoader``
225+
et sans cela la méthode ``load()`` ne sera pas appelée. La clé
226+
``resource`` est inutile pour le ``ExtraLoader`` donc la valeur "."
227+
est spécifiée ici.
228+
229+
.. note::
230+
231+
Les routes définies par un chargeur de routes personnalisé vont
232+
être automatiquement mises en cache par le framework. Donc
233+
lorsque vous modifiez quelque-chose dans la classe de chargement,
234+
n'oubliez pas de vider le cache.
235+
236+
Chargeurs plus avancés
237+
----------------------
238+
239+
Si votre chargeur de routes étend de
240+
:class:`Symfony\\Component\\Config\\Loader\\Loader` comment
241+
montré précédemment, vous pouvez aussi utiliser le résolveur fourni,
242+
une instance de
243+
:class:`Symfony\\Component\\Config\\Loader\\LoaderResolver`, pour
244+
charger d'autres resources de routing.
245+
246+
Évidemment vous avez toujours besoin d'implémenter les méthodes
247+
:method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports`
248+
et :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load`.
249+
Lorsque vous voulez charger une autre resource – par exemple un fichier
250+
de configuration YAML ‑ vous pouvez appeler la méthode
251+
:method:`Symfony\\Component\\Config\\Loader\\Loader::import`::
252+
253+
// src/AppBundle/Routing/AdvancedLoader.php
254+
namespace AppBundle\Routing;
255+
256+
use Symfony\Component\Config\Loader\Loader;
257+
use Symfony\Component\Routing\RouteCollection;
258+
259+
class AdvancedLoader extends Loader
260+
{
261+
public function load($resource, $type = null)
262+
{
263+
$collection = new RouteCollection();
264+
265+
$resource = '@AppBundle/Resources/config/import_routing.yml';
266+
$type = 'yaml';
267+
268+
$importedRoutes = $this->import($resource, $type);
269+
270+
$collection->addCollection($importedRoutes);
271+
272+
return $collection;
273+
}
274+
275+
public function supports($resource, $type = null)
276+
{
277+
return 'advanced_extra' === $type;
278+
}
279+
}
280+
281+
.. note::
282+
283+
Le nom de la ressource et le type du routing importé peut être
284+
n'importe quoi tant que c'est supporté par la configuration du
285+
chargeur de route (YAML, XML, PHP, annotation, etc.).
286+
287+
.. _`FOSRestBundle`: https://github.com/FriendsOfSymfony/FOSRestBundle
288+
.. _`JMSI18nRoutingBundle`: https://github.com/schmittjoh/JMSI18nRoutingBundle
289+
.. _`KnpRadBundle`: https://github.com/KnpLabs/KnpRadBundle
290+
.. _`SonataAdminBundle`: https://github.com/sonata-project/SonataAdminBundle

cookbook/routing/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ Routage
99
redirect_in_config
1010
method_parameters
1111
service_container_parameters
12-
redirect_trailing_slash
12+
custom_route_loader
13+
redirect_trailing_slash

0 commit comments

Comments
 (0)