Skip to content

Commit c1cd667

Browse files
Cookbook article about custom route loaders
1 parent 0b7d8f4 commit c1cd667

File tree

3 files changed

+161
-0
lines changed

3 files changed

+161
-0
lines changed

cookbook/map.rst.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
* :doc:`/cookbook/routing/slash_in_parameter`
103103
* :doc:`/cookbook/routing/redirect_in_config`
104104
* :doc:`/cookbook/routing/method_parameters`
105+
* :doc:`/cookbook/routing/custom_route_loader`
105106

106107
* :doc:`/cookbook/security/index`
107108

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
.. index::
2+
single: Routing; Custom route loader
3+
4+
How to Create a Custom Route Loader
5+
===================================
6+
7+
Loading Routes
8+
--------------
9+
10+
The routes in a Symfony application are loaded by the :class:`Symfony\\Bundle\\FrameworkBundle\\Routing\\DelegatingLoader`.
11+
This loader uses several other loaders (delegates) to load resources of
12+
different types, for instance Yaml files or ``@Route`` and ``@Method`` annotations
13+
in controller files. The specialized loaders implement :class:`Symfony\\Component\\Config\\Loader\\LoaderInterface`
14+
and therefore have two important methods: :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports`
15+
and :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load`.
16+
17+
Take these lines from ``routing.yml``:
18+
19+
.. code-block:: yaml
20+
21+
_demo:
22+
resource: "@AcmeDemoBundle/Controller/DemoController.php"
23+
type: annotation
24+
prefix: /demo
25+
26+
The main loader tries all the delegate loaders and calls their
27+
:method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports`
28+
with the given resource ("@AcmeDemoBundle/Controller/DemoController.php")
29+
and type ("annotation") as arguments. When one of the loader returns ``true``,
30+
its method :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load`
31+
will be called, and the loader returns a :class:`Symfony\\Component\\Routing\\RouteCollection`
32+
containing :class:`Symfony\\Component\\Routing\\Route` objects.
33+
34+
Creating a Custom Loader
35+
------------------------
36+
37+
To load routes in another way then using annotations, Yaml or XML files,
38+
you need to create a custom route loader. This loader should implement
39+
:class:`Symfony\\Component\\Config\\Loader\\LoaderInterface`.
40+
41+
The sample loader below supports resources of type "extra". The resource
42+
name itself is not used in the example::
43+
44+
namespace Acme\DemoBundleBundle\Routing;
45+
46+
use Symfony\Component\Config\Loader\LoaderInterface;
47+
use Symfony\Component\Config\Loader\LoaderResolver;
48+
use Symfony\Component\Routing\Route;
49+
use Symfony\Component\Routing\RouteCollection;
50+
51+
class ExtraLoader implements LoaderInterface
52+
{
53+
private $loaded = false;
54+
55+
public function load($resource, $type = null)
56+
{
57+
if (true === $this->loaded) {
58+
throw new \RuntimeException('Do not add the "extra" loader twice');
59+
}
60+
61+
$routes = new RouteCollection();
62+
63+
// prepare a new route
64+
$pattern = '/extra/{parameter}';
65+
$defaults = array(
66+
'_controller' => 'AcmeDemoBundle:Demo:extra',
67+
);
68+
$requirements = array(
69+
'parameter' => '\d+',
70+
);
71+
$route = new Route($pattern, $defaults, $requirements);
72+
73+
// add the new route to the route collection:
74+
$routeName = 'extraRoute';
75+
$routes->add($routeName, $route);
76+
77+
return $routes;
78+
}
79+
80+
public function supports($resource, $type = null)
81+
{
82+
return 'extra' === $type;
83+
}
84+
85+
public function getResolver()
86+
{
87+
// irrelevant to us, since we don't use a loader resolver
88+
}
89+
90+
public function setResolver(LoaderResolver $resolver)
91+
{
92+
// also irrelevant
93+
}
94+
}
95+
96+
.. note::
97+
98+
Make sure the controller you specify really exists.
99+
100+
Now define a service for the ``ExtraLoader``:
101+
102+
.. configuration-block::
103+
104+
.. code-block:: yaml
105+
106+
services:
107+
acme_demo.routing_loader:
108+
class: Acme\DemoBundle\Routing\ExtraLoader
109+
tags:
110+
- { name: routing.loader }
111+
112+
.. code-block:: xml
113+
114+
<?xml version="1.0" ?>
115+
<container xmlns="http://symfony.com/schema/dic/services"
116+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
117+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
118+
119+
<services>
120+
<service id="acme_demo.routing_loader" class="Acme\DemoBundle\Routing\ExtraLoader">
121+
<tag name="routing.loader"></tag>
122+
</service>
123+
</services>
124+
</container>
125+
126+
.. code-block:: php
127+
128+
use Symfony\Component\DependencyInjection\Definition;
129+
130+
$container
131+
->setDefinition(
132+
'acme_demo.routing_loader',
133+
new Definition('Acme\DemoBundle\Routing\ExtraLoader')
134+
)
135+
->addTag('routing.loader')
136+
;
137+
138+
Notice the tag ``routing.loader``. All services with this tag will be marked
139+
as potential route loaders and added as specialized routers to the
140+
:class:`Symfony\\Bundle\\FrameworkBundle\\Routing\\DelegatingLoader`.
141+
142+
Finally, we only need to add a few extra lines in ``routing.yml``:
143+
144+
.. code-block:: yaml
145+
146+
AcmeDemoBundle_Extra:
147+
resource: .
148+
type: extra
149+
150+
The ``resource`` key is irrelevant, but required. The important part here
151+
is the ``type`` key. Its value should be "extra". This is the type which
152+
our ``ExtraLoader`` supports and this will make sure its ``load()`` method
153+
is called.
154+
155+
.. note::
156+
157+
The routes defined using the extra loader will be automatically cached
158+
by the framework. So whenever you change something to the behavior of
159+
the loader, don't forget to clear the cache.

cookbook/routing/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ Routing
88
slash_in_parameter
99
redirect_in_config
1010
method_parameters
11+
custom_route_loader

0 commit comments

Comments
 (0)