Symfony2: An alternative to Symfony 1's "routing.load_configuration" event
Matthias Noback
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.)