I need to build a route which has a dynamic condition.
For the moment, I simply use requirements
in order the match against a static list a words:
/**
* @Route(
* "/{category}/{id}",
* requirements={
* "category"="^(foo|bar)$"
* }
* )
*
* ...
*/
But now I need these words to be retrieved dynamically from a service method.
While searching a solution, I gave a hope to the condition
expression language; but the only
variables which are accessible here are the context and the request. However, to achieve my goal I
need a full access to container services.
In other words, I would like the following pseudo-php to be executed in order to test the route:
if (in_array($category, MyService::getAllCategories())) {
/* Inform Symfony that the route matches (then use this controller) */
} else {
/* Inform Symfony that the route does not match and that the routing process
* has to go on. */
}
Please note that the main reason of my problem is that the {category}
parameter is placed early in
the url, and then can offuscate other routes. Then I can't just test my condition inside the
controller and return a 404 if the condition is not required. I surely could place this route at
the end in the routing process order, but I don't think it is a good solution.
Custom route loader can be a solution ... http://symfony.com/doc/current/routing/custom_route_loader.html This example generates not dinamic routes, but works fine.
Only as example, assuming CategoryProvider and Category are your classes ...
<?php
// src/Routing/CategoryLoader.php
namespace App\Routing;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use App\CategoryProvider;
class CategoryLoader extends Loader
{
private $isLoaded = false;
private $catProvider;
public function __construct(CategoryProvider $catProvider)
{
$this->catProvider = $catProvider;
}
public function load($resource, $type = null)
{
if (true === $this->isLoaded) {
throw new \RuntimeException('Do not add the "extra" loader twice');
}
$routes = new RouteCollection();
foreach ($this->catProvider->getAll() as $cat) {
// prepare a new route
$path = sprintf('/%s/{id}', $cat->getSlug());
$defaults = [
'_controller' => 'App\Controller\ExtraController::extra',
];
$requirements = [
'parameter' => '\d+',
];
$route = new Route($path, $defaults, $requirements);
// add the new route to the route collection
$routeName = 'categoryRoute' . $cat->getSlug();
$routes->add($routeName, $route);
}
$this->isLoaded = true;
return $routes;
}
public function supports($resource, $type = null)
{
return 'extra' === $type;
}
}