I need my website to be accessible with 2 different URL, for example:
/blog => Homepage
/blog/article/1 => Article page (etc.)
/abcde/blog => Homepage
/abcde/blog/article/1 => Article page (etc.)
When "abcde" is in my URL, I need to have the same controller/action running, but being able to get this "abcde" value (a few changes will result from this parameter).
I have found many similar questions but never exactly what I am looking for:
- I am not looking for a language/translation routing bundle
- "abcde" parameter must be optional
- My bundle has several controllers and actions, I don't want to write 2 routes for each. (Neither do I want to have to update anything each time I add a new controller/action.)
Initial app/config/routing.yml
mywebsite_blog: resource: "@MywebsiteBlogBundle/Resources/config/routing.yml" prefix: /blog/
If I simply add a second route, as
resource
is the same, it overwrites the first one.I tried to add an optional parameter on the initial route:
mywebsite_blog: resource: "@MywebsiteBlogBundle/Resources/config/routing.yml" prefix: /{_label}/blog/ defaults: {_label: mylabel} requirements: _label: .*
That way I can access /abcde/blog
, //blog
, but not /blog
(404).
Not finding how to resolve my issue simply with using routing.yml (if it is possible I will be happy to learn how and stop there), I read How to Create a custom Route Loader on Symfony doc. I am not sure I'm going to the right direction but I tried it and manage to do a few things, still not exactly what I want.
LabelLoader.php
class LabelLoader extends Loader {
private $loaded = false;
public function load($resource, $type = null) {
if (true === $this->loaded) {
throw new \RuntimeException('Do not add the "label" loader twice');
}
$routes = new RouteCollection();
// Prepare a new route (this is were I tried to play with it)
$path = '/{_label}/blog/';
$defaults = array(
'_controller' => 'MywebsiteBlogBundle:Index:home',
);
$route = new Route($path, $defaults);
// Add the new route to the route collection
$routeName = 'labelRoute';
$routes->add($routeName, $route);
$this->loaded = true;
return $routes;
}
public function supports($resource, $type = null) {
return 'label' === $type;
}
}
That way, /blog
and /abcde/blog
works the way I want to. I can access the _label
variable in my _init() function (I'm using listeners and InitializableControllerInterface, in case it is important to know here), checking if empty or not, etc.
But obviously it works for only one controller/action (Index:home
). I would like to change this so that it can works for my whole MywebsiteBlogBundle.
In my custom Loader, I wanted to test something like:
$routes = new RouteCollection();
// Hypotetical function returning all the routes I want to have twice.
// Methods getPath() and getController() called below are hypotetical too.
$mywebsiteBlogRoutes = getExisitingMywebsiteBlogBundleRoutes();
foreach($mywebsiteBlogRoutes as $blogRoute) {
// Prepare a new route
$path = '/{_label}/blog/'.$blogRoute->getPath();
$defaults = array(
'_controller' => $blogRoute->getController(),
);
$route = new Route($path, $defaults);
// Add the new route to the route collection
$routeName = 'labelRoute';
$routes->add($routeName, $route);
}
But:
It does not seem very clean (but if that's the only way I find to do it for now, I'll try it)
I tried to get all my routes reading this answer and as soon as I try
$collection = $router->getRouteCollection();
I have a "Circular reference detected" error that I don't manage to fix. I'm trying to understand what's happening here. Edit: I fixed it. Still, I don't think it's a very clean solution.
Should I go back to routing.yml or is it possible to do something here with the custom Routing Loader?