Search code examples
symfonysymfony-2.5

Symfony2 Routing Optional Paths


How can Symfony2 routing be setup to allow more optional paths.

Currently the routing file looks like this, the controller contains 3 actions to handle the requests.

MediaFilmBundle_film:
    pattern:  /films
    defaults: { _controller: MediaFilmBundle:Film:index }
MediaFilmBundle_Film_Genre:
    pattern:  /films/genre/{genre_slug}
    defaults: { _controller: MediaFilmBundle:Film:genre }
MediaFilmBundle_Film_Source:
    pattern:  /films/source/{source_slug}
    defaults: { _controller: MediaFilmBundle:Film:source }

This work but how can it be made better or is the following beyond Symfony2, is it possible to do something like the following so there is only one action that handles it all.

MediaFilmBundle_film:
    pattern:  /films/genre/{genre_slug}/source/{source_slug}
    defaults: { _controller: MediaFilmBundle:Film:index }

The above route should match all of the following:

    /films
    /films/genre/horror
    /films/source/america
    /films/genre/action/source/england

Ideally it should not match the following or the controller could redirect it to the standard format genre/../source/..

    /films/source/england/genre/action

The route could be matched using the existing structure like so:

MediaFilmBundle_Film_Genre_Source:
    pattern:  /films/genre/{genre_slug}/source/{source_slug}
    defaults: { _controller: MediaFilmBundle:Film:genreSource }

The problem with this approach is as more slugs are added more routes and more actions are needed.

  • 1 slug = 2 routes and actions
  • 2 slugs = 4 routes and actions
  • 3 slugs = 8 routes and actions
  • n slugs = ...

Solution

  • Default parameters can be used to make slugs optional:

    MediaFilmBundle_film:
        pattern:  /films/{type_one}/{value_one}/{type_two}/{value_two}
        defaults: { _controller: MediaFilmBundle:Film:index, type_one: ""}
    

    All slugs after the first optional one become by default optional and will be set to empty values if not provided. In your controller you will have to implement the logic to check if type_one slug was provided and if it is of type genre or source and then parse value_one. Then check if type_two slug is provided, if it is blank perform the logic that you have for paths /films/genre/horror. If it is provided parse the type and value and perform logic that you have for paths /films/genre/action/source/England

    The optional slugs are described here: http://symfony.com/doc/current/book/routing.html#required-and-optional-placeholders

    You may also want to check out Dynamic Router if you really need to make this work for dynamic number of slugs: http://symfony.com/doc/current/cmf/bundles/routing/dynamic.html