44How to Create a custom Route Loader
55===================================
66
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.
1822
1923..note ::
2024
2125 There are many bundles out there that use their own route loaders to
2226 accomplish cases like those described above, for instance
23- `FOSRestBundle `_, `JMSI18nRoutingBundle `_, `KnpRadBundle `_ and `SonataAdminBundle `_.
27+ `FOSRestBundle `_, `JMSI18nRoutingBundle `_, `KnpRadBundle `_ and
28+ `SonataAdminBundle `_.
2429
2530Loading Routes
2631--------------
@@ -35,20 +40,18 @@ and therefore have two important methods:
3540:method: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface::supports `
3641and:method: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface::load `.
3742
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:
4044
4145..code-block ::yaml
4246
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/
4650type :annotation
47- prefix :/demo
4851
49- When the main loader parses this, it tries allthe delegate loaders and calls
52+ When the main loader parses this, it tries allregistered delegate loaders and calls
5053their: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/ ``)
5255and type (``annotation ``) as arguments. When one of the loader returns ``true ``,
5356its:method: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface::load ` method
5457will be called, which should return a:class: `Symfony\\ Component\\ Routing\\ RouteCollection `
@@ -59,20 +62,24 @@ Creating a custom Loader
5962
6063To load routes from some custom source (i.e. from something other than annotations,
6164YAML 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 `.
6370
6471The sample loader below supports loading routing resources with a type of
6572``extra ``. The type ``extra `` isn't important - you can just invent any resource
6673type you want. The resource name itself is not actually used in the example::
6774
68- namespace Acme\DemoBundle\Routing;
75+ // src/AppBundle/Routing/ExtraLoader.php
76+ namespace AppBundle\Routing;
6977
70- use Symfony\Component\Config\Loader\LoaderInterface;
71- use Symfony\Component\Config\Loader\LoaderResolverInterface;
78+ use Symfony\Component\Config\Loader\Loader;
7279 use Symfony\Component\Routing\Route;
7380 use Symfony\Component\Routing\RouteCollection;
7481
75- class ExtraLoaderimplements LoaderInterface
82+ class ExtraLoaderextends Loader
7683 {
7784 private $loaded = false;
7885
@@ -87,14 +94,14 @@ type you want. The resource name itself is not actually used in the example::
8794 // prepare a new route
8895 $path = '/extra/{parameter}';
8996 $defaults = array(
90- '_controller' => 'AcmeDemoBundle:Demo :extra',
97+ '_controller' => 'AppBundle:Extra :extra',
9198 );
9299 $requirements = array(
93100 'parameter' => '\d+',
94101 );
95102 $route = new Route($path, $defaults, $requirements);
96103
97- // add the new route to the route collection:
104+ // add the new route to the route collection
98105 $routeName = 'extraRoute';
99106 $routes->add($routeName, $route);
100107
@@ -107,32 +114,36 @@ type you want. The resource name itself is not actually used in the example::
107114 {
108115 return 'extra' === $type;
109116 }
117+ }
110118
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;
116125
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)
118132 {
119- // same as above
133+ return new Response($parameter);
120134 }
121135 }
122136
123- ..note ::
124-
125- Make sure the controller you specify really exists.
126-
127137Now define a service for the ``ExtraLoader ``:
128138
129139..configuration-block ::
130140
131141 ..code-block ::yaml
132142
143+ # app/config/services.yml
133144services :
134- acme_demo .routing_loader :
135- class :Acme\DemoBundle \Routing\ExtraLoader
145+ app .routing_loader :
146+ class :AppBundle \Routing\ExtraLoader
136147tags :
137148 -{ name: routing.loader }
138149
@@ -144,7 +155,7 @@ Now define a service for the ``ExtraLoader``:
144155xsi : schemaLocation =" http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd" >
145156
146157 <services >
147- <service id =" acme_demo .routing_loader" class =" Acme\DemoBundle \Routing\ExtraLoader" >
158+ <service id =" app .routing_loader" class =" AppBundle \Routing\ExtraLoader" >
148159 <tag name =" routing.loader" />
149160 </service >
150161 </services >
@@ -156,14 +167,15 @@ Now define a service for the ``ExtraLoader``:
156167
157168 $container
158169 ->setDefinition(
159- 'acme_demo .routing_loader',
160- new Definition('Acme\DemoBundle \Routing\ExtraLoader')
170+ 'app .routing_loader',
171+ new Definition('AppBundle \Routing\ExtraLoader')
161172 )
162173 ->addTag('routing.loader')
163174 ;
164175
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
167179:class: `Symfony\\ Bundle\\ FrameworkBundle\\ Routing\\ DelegatingLoader `.
168180
169181Using the custom Loader
@@ -177,7 +189,7 @@ Instead, you only need to add a few extra lines to the routing configuration:
177189 ..code-block ::yaml
178190
179191# app/config/routing.yml
180- AcmeDemoBundle_Extra :
192+ app_extra :
181193resource :.
182194type :extra
183195
@@ -201,8 +213,8 @@ Instead, you only need to add a few extra lines to the routing configuration:
201213
202214 return $collection;
203215
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
206218its ``load() `` method gets called. The ``resource `` key is insignificant
207219for the ``ExtraLoader ``, so it is set to ".".
208220
@@ -215,11 +227,11 @@ for the ``ExtraLoader``, so it is set to ".".
215227More advanced Loaders
216228---------------------
217229
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.
223235
224236Of course you still need to implement
225237:method: `Symfony\\ Component\\ Config\\ Loader\\ LoaderInterface::supports `
@@ -228,7 +240,8 @@ Whenever you want to load another resource - for instance a YAML routing
228240configuration file - you can call the
229241:method: `Symfony\\ Component\\ Config\\ Loader\\ Loader::import ` method::
230242
231- namespace Acme\DemoBundle\Routing;
243+ // src/AppBundle/Routing/AdvancedLoader.php
244+ namespace AppBundle\Routing;
232245
233246 use Symfony\Component\Config\Loader\Loader;
234247 use Symfony\Component\Routing\RouteCollection;
@@ -239,7 +252,7 @@ configuration file - you can call the
239252 {
240253 $collection = new RouteCollection();
241254
242- $resource = '@AcmeDemoBundle /Resources/config/import_routing.yml';
255+ $resource = '@AppBundle /Resources/config/import_routing.yml';
243256 $type = 'yaml';
244257
245258 $importedRoutes = $this->import($resource, $type);
@@ -251,7 +264,7 @@ configuration file - you can call the
251264
252265 public function supports($resource, $type = null)
253266 {
254- return$type ==='advanced_extra' ;
267+ return'advanced_extra' ===$type ;
255268 }
256269 }
257270