Symfony 1 had the lovely routing.load_configuration
event. Listening to this event enabled the developer to add some routes dynamically, "on-the-fly". Plugins used to do this most of the time. I was looking for a way to accomplish the same in Symfony 2. I've used the following as a solution.
We are going to listen to the kernel.request
event, but we make sure we get notified in an early stage, so that the router hasn't done it's magic yet. Then we quickly add some extra routes to the RouteCollection
.
Create a routing listener
First we need an event listener, let's call it RoutingListener
. The router will be injected by defining this dependency in the service's definition (see below). onEarlyKernelRequest
will be the method that responds to the kernel.request
event and adds an extra route to the router's route collection:
// in src/Acme/DemoBundle/EventListener/RoutingListener.php
namespace Acme\DemoBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Routing\Route;
class RoutingListener
{
protected $router;
public function __construct(RouterInterface $router)
{
$this->router = $router;
}
public function onEarlyKernelRequest(GetResponseEvent $event)
{
// create a new route; other arguments would be an
// array containing requirements and an array with options
$route = new Route('/welcome-to-symfony2', array(
'_controller' => 'AcmeDemoBundle:Welcome:index',
));
$this->router->getRouteCollection()->add('extraRoute', $route);
}
}
Now we should announce the existence of this listener to the kernel itself. We can do this by defining the listener as a service in /src/Acme/DemoBundle/Resources/services.xml
:
<?xml version="1.0" ?>
<container xmlns="https://symfony.com/schema/dic/services"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<!-- ... --->
<service id="acme.routing_listener" class="Acme\DemoBundle\EventListener\RoutingListener">
<argument type="service" id="router" />
<tag name="kernel.event_listener" event="kernel.request" method="onEarlyKernelRequest" priority="255" />
</service>
</services>
</container>
I wonder which value is really appropriate for "priority", but at least this one works.
As you can see, we register the service using the tag "kernel.event_listener" as a service which responds to the kernel event kernel.request
. Upon this event, the onEarlyKernelRequest
should be fired and this adds the extra route. The service has one dependency, namely the router, which will be injected as the first argument of the constructor.
Test the setup by browsing to /app_dev.php/welcome-to-symfony2
. You should now see the welcome page of your Symfony2 installation.
Nice, but...
Your newly added routes won't appear in the output of the console command router:debug
, since the kernel.request
only gets fired for web applications. Nevertheless, the WebProfilerExtraBundle shows all the routes correctly. (You might even ask if a router:debug
command actually is an appropriate console command, since routing is a typical "web" thing, but I admit it may be a little annoying that these "on-the-fly" created routes don't appear in the list.)
you're the man, man!!!!
I just love this, best solution ever.
I've been looking for something this elegant for a few months already)))
Hi Matthias,
I’m getting a “No route found” error same as Maria . my sf version is 2.0.8.
Your articles are so awesome,thanks your hard work.
Hi Andrew, as I wrote to Maria, see http://php-and-symfony.matt... for how you should try to accomplish this (in a much better way than described above).
Hi Matthias.
Nice post. I've tried to do what you said, but I'm getting a "No route found" error.
I've tried to debug the route collection and everything looks ok - The route is there. Any idea?
Note: When debugging the route collection I've noticed that all routes have the _controller like: "Bundle\FooBundle\Controller\FooController::fooAction". And, the route created as you're saying above appear like "BundleFooBundle:Foo:foo" - strange?
Cheers,
Maria
Okay, so I have completely redone this and the result is a new post, see http://php-and-symfony.matt... Good luck!
Thanks! I have not found any problem with this yet, though it is strange that both alternatives work (using the short or the long notation for controllers). Possibly this has something to do with different versions of Symfony2. I will try that later. Bye!