4

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?

Community
  • 1
  • 1

1 Answers1

3

You should try this in your routing.yml:

mywebsite_blog:
    resource: "@MywebsiteBlogBundle/Resources/config/routing.yml"
    prefix:   /{_label}blog/
    defaults: {_label: mylabel/}
    requirements:
        _label: ([\w\d]+/)?

Results:

app/console router:match /mylabel/blog/  # OK
app/console router:match /blog/          # OK
mykiwi
  • 1,572
  • 1
  • 15
  • 32
  • When I see the tiny difference with what I tried, I wondered when I stopped thinking! Thank you. It's not exactly what I was trying to do (I have to remove the `/` when getting my `_label` parameter -not a big deal) but it is the closest and much better than playing with custom Route Loader. I don't accept for now, I'll wait a bit in case a better answer is suggested (though I think this one is the simpler one we can find). –  Jun 25 '15 at 08:54
  • True but I don't think that there is a solution for remove the `/` automatically. – mykiwi Jun 25 '15 at 10:02
  • Yes I removed my `Loader` and used your solution instead. Removing the ending `/` when I need to use my `_label` is not a big issue. :) –  Jun 25 '15 at 10:06