4
4
How to Create a custom Route Loader
5
5
===================================
6
6
7
- A custom route loader allows you to add routes to an application without
8
- including them, for example, in a YAML file. This comes in handy when
9
- you have a bundle but don't want to manually add the routes for the bundle
10
- to ``app/config/routing.yml ``. This may be especially important when you want
11
- to make the bundle reusable, or when you have open-sourced it as this would
12
- slow down the installation process and make it error-prone.
13
-
14
- Alternatively, you could also use a custom route loader when you want your
15
- routes to be automatically generated or located based on some convention or
16
- pattern. One example is the `FOSRestBundle `_ where routing is generated based
17
- off the names of the action methods in a controller.
7
+ What is a Custom Route Loader
8
+ -----------------------------
9
+
10
+ A custom route loader enables you to generate routes based on some
11
+ conventions or patterns. A great example for this use-case is the
12
+ `FOSRestBundle `_ where routes are generated based on the names of the
13
+ action methods in a controller.
14
+
15
+ A custom route loader does not enable your bundle to inject routes
16
+ without the need to modify the routing configuration
17
+ (e.g. ``app/config/routing.yml ``) manually.
18
+ If your bundle provides routes, whether via a configuration file, like
19
+ the `WebProfilerBundle ` does, or via a custom route loader, like the
20
+ `FOSRestBundle `_ does, an entry in the routing configuration is always
21
+ necessary.
18
22
19
23
.. note ::
20
24
21
25
There are many bundles out there that use their own route loaders to
22
26
accomplish cases like those described above, for instance
23
- `FOSRestBundle `_, `JMSI18nRoutingBundle `_, `KnpRadBundle `_ and `SonataAdminBundle `_.
27
+ `FOSRestBundle `_, `JMSI18nRoutingBundle `_, `KnpRadBundle `_ and
28
+ `SonataAdminBundle `_.
24
29
25
30
Loading Routes
26
31
--------------
@@ -35,20 +40,18 @@ and therefore have two important methods:
35
40
:method: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface::supports `
36
41
and :method: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface::load `.
37
42
38
- Take these lines from the ``routing.yml `` in the AcmeDemoBundle of the Standard
39
- Edition:
43
+ Take these lines from the ``routing.yml `` in the Symfony Standard Edition:
40
44
41
45
.. code-block :: yaml
42
46
43
- # src/Acme/DemoBundle/Resources /config/routing.yml
44
- _demo :
45
- resource : " @AcmeDemoBundle /Controller/DemoController.php "
47
+ # app /config/routing.yml
48
+ app :
49
+ resource : @AppBundle /Controller/
46
50
type : annotation
47
- prefix : /demo
48
51
49
- When the main loader parses this, it tries all the delegate loaders and calls
52
+ When the main loader parses this, it tries all registered delegate loaders and calls
50
53
their :method: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface::supports `
51
- method with the given resource (``@AcmeDemoBundle /Controller/DemoController.php ``)
54
+ method with the given resource (``@AppBundle /Controller/ ``)
52
55
and type (``annotation ``) as arguments. When one of the loader returns ``true ``,
53
56
its :method: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface::load ` method
54
57
will be called, which should return a :class: `Symfony\\ Component\\ Routing\\ RouteCollection `
@@ -59,20 +62,24 @@ Creating a custom Loader
59
62
60
63
To load routes from some custom source (i.e. from something other than annotations,
61
64
YAML or XML files), you need to create a custom route loader. This loader
62
- should implement :class: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface `.
65
+ has to implement :class: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface `.
66
+
67
+ In most cases it's better not to implement
68
+ :class: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface `
69
+ yourself, but extend from :class: `Symfony\\ Component\\ Config\\ Loader\\ Loader `.
63
70
64
71
The sample loader below supports loading routing resources with a type of
65
72
``extra ``. The type ``extra `` isn't important - you can just invent any resource
66
73
type you want. The resource name itself is not actually used in the example::
67
74
68
- namespace Acme\DemoBundle\Routing;
75
+ // src/AppBundle/Routing/ExtraLoader.php
76
+ namespace AppBundle\Routing;
69
77
70
- use Symfony\Component\Config\Loader\LoaderInterface;
71
- use Symfony\Component\Config\Loader\LoaderResolverInterface;
78
+ use Symfony\Component\Config\Loader\Loader;
72
79
use Symfony\Component\Routing\Route;
73
80
use Symfony\Component\Routing\RouteCollection;
74
81
75
- class ExtraLoader implements LoaderInterface
82
+ class ExtraLoader extends Loader
76
83
{
77
84
private $loaded = false;
78
85
@@ -87,14 +94,14 @@ type you want. The resource name itself is not actually used in the example::
87
94
// prepare a new route
88
95
$path = '/extra/{parameter}';
89
96
$defaults = array(
90
- '_controller' => 'AcmeDemoBundle:Demo :extra',
97
+ '_controller' => 'AppBundle:Extra :extra',
91
98
);
92
99
$requirements = array(
93
100
'parameter' => '\d+',
94
101
);
95
102
$route = new Route($path, $defaults, $requirements);
96
103
97
- // add the new route to the route collection:
104
+ // add the new route to the route collection
98
105
$routeName = 'extraRoute';
99
106
$routes->add($routeName, $route);
100
107
@@ -107,32 +114,36 @@ type you want. The resource name itself is not actually used in the example::
107
114
{
108
115
return 'extra' === $type;
109
116
}
117
+ }
110
118
111
- public function getResolver()
112
- {
113
- // needed, but can be blank, unless you want to load other resources
114
- // and if you do, using the Loader base class is easier (see below)
115
- }
119
+ Make sure the controller you specify really exists. In this case you
120
+ have to create an ``extraAction `` method in the ``ExtraController ``
121
+ of the ``AppBundle ``::
122
+
123
+ // src/AppBundle/Controller/ExtraController.php
124
+ namespace AppBundle\Controller;
116
125
117
- public function setResolver(LoaderResolverInterface $resolver)
126
+ use Symfony\Component\HttpFoundation\Response;
127
+ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
128
+
129
+ class ExtraController extends Controller
130
+ {
131
+ public function extraAction($parameter)
118
132
{
119
- // same as above
133
+ return new Response($parameter);
120
134
}
121
135
}
122
136
123
- .. note ::
124
-
125
- Make sure the controller you specify really exists.
126
-
127
137
Now define a service for the ``ExtraLoader ``:
128
138
129
139
.. configuration-block ::
130
140
131
141
.. code-block :: yaml
132
142
143
+ # app/config/services.yml
133
144
services :
134
- acme_demo .routing_loader :
135
- class : Acme\DemoBundle \Routing\ExtraLoader
145
+ app .routing_loader :
146
+ class : AppBundle \Routing\ExtraLoader
136
147
tags :
137
148
- { name: routing.loader }
138
149
@@ -144,7 +155,7 @@ Now define a service for the ``ExtraLoader``:
144
155
xsi : schemaLocation =" http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd" >
145
156
146
157
<services >
147
- <service id =" acme_demo .routing_loader" class =" Acme\DemoBundle \Routing\ExtraLoader" >
158
+ <service id =" app .routing_loader" class =" AppBundle \Routing\ExtraLoader" >
148
159
<tag name =" routing.loader" />
149
160
</service >
150
161
</services >
@@ -156,14 +167,15 @@ Now define a service for the ``ExtraLoader``:
156
167
157
168
$container
158
169
->setDefinition(
159
- 'acme_demo .routing_loader',
160
- new Definition('Acme\DemoBundle \Routing\ExtraLoader')
170
+ 'app .routing_loader',
171
+ new Definition('AppBundle \Routing\ExtraLoader')
161
172
)
162
173
->addTag('routing.loader')
163
174
;
164
175
165
- Notice the tag ``routing.loader ``. All services with this tag will be marked
166
- as potential route loaders and added as specialized routers to the
176
+ Notice the tag ``routing.loader ``. All services with this *tag * will be marked
177
+ as potential route loaders and added as specialized route loaders to the
178
+ ``routing.loader `` *service *, which is an instance of
167
179
:class: `Symfony\\ Bundle\\ FrameworkBundle\\ Routing\\ DelegatingLoader `.
168
180
169
181
Using the custom Loader
@@ -177,7 +189,7 @@ Instead, you only need to add a few extra lines to the routing configuration:
177
189
.. code-block :: yaml
178
190
179
191
# app/config/routing.yml
180
- AcmeDemoBundle_Extra :
192
+ app_extra :
181
193
resource : .
182
194
type : extra
183
195
@@ -201,8 +213,8 @@ Instead, you only need to add a few extra lines to the routing configuration:
201
213
202
214
return $collection;
203
215
204
- The important part here is the ``type `` key. Its value should be "extra".
205
- This is the type which the ``ExtraLoader `` supports and this will make sure
216
+ The important part here is the ``type `` key. Its value should be "extra" as
217
+ this is the type which the ``ExtraLoader `` supports and this will make sure
206
218
its ``load() `` method gets called. The ``resource `` key is insignificant
207
219
for the ``ExtraLoader ``, so it is set to ".".
208
220
@@ -215,11 +227,11 @@ for the ``ExtraLoader``, so it is set to ".".
215
227
More advanced Loaders
216
228
---------------------
217
229
218
- In most cases it's better not to implement
219
- :class: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface `
220
- yourself, but extend from :class: ` Symfony \\ Component \\ Config \\ Loader \\ Loader `.
221
- This class knows how to use a :class: `Symfony\\ Component\\ Config\\ Loader\\ LoaderResolver `
222
- to load secondary routing resources.
230
+ If your custom route loader extends from
231
+ :class: `Symfony\\ Component\\ Config\\ Loader\\ Loader ` as shown above, you
232
+ can also make use of the provided resolver, an instance of
233
+ :class: `Symfony\\ Component\\ Config\\ Loader\\ LoaderResolver `, to load secondary
234
+ routing resources.
223
235
224
236
Of course you still need to implement
225
237
:method: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface::supports `
@@ -228,7 +240,8 @@ Whenever you want to load another resource - for instance a YAML routing
228
240
configuration file - you can call the
229
241
:method: `Symfony\\ Component\\ Config\\ Loader\\ Loader::import ` method::
230
242
231
- namespace Acme\DemoBundle\Routing;
243
+ // src/AppBundle/Routing/AdvancedLoader.php
244
+ namespace AppBundle\Routing;
232
245
233
246
use Symfony\Component\Config\Loader\Loader;
234
247
use Symfony\Component\Routing\RouteCollection;
@@ -239,7 +252,7 @@ configuration file - you can call the
239
252
{
240
253
$collection = new RouteCollection();
241
254
242
- $resource = '@AcmeDemoBundle /Resources/config/import_routing.yml';
255
+ $resource = '@AppBundle /Resources/config/import_routing.yml';
243
256
$type = 'yaml';
244
257
245
258
$importedRoutes = $this->import($resource, $type);
@@ -251,7 +264,7 @@ configuration file - you can call the
251
264
252
265
public function supports($resource, $type = null)
253
266
{
254
- return $type === 'advanced_extra' ;
267
+ return 'advanced_extra' === $type ;
255
268
}
256
269
}
257
270
0 commit comments