The definitive guide of Symfony 1.0

9.4. Routing Configuration

The routing system does two things:

  • It interprets the external URL of incoming requests and transforms it into an internal URI, to determine the module/action and the request parameters.
  • It formats the internal URIs used in links into external URLs (provided that you use the link helpers).

The conversion is based on a set of routing rules . These rules are stored in a routing.yml configuration file located in the application config/ directory. Listing 9-15 shows the default routing rules, bundled with every symfony project.

Listing 9-15 - The Default Routing Rules, in myapp/config/routing.yml

# default rules
  url:   /
  param: { module: default, action: index }

  url:   /symfony/:action/*
  param: { module: default }

  url:   /:module
  param: { action: index }

  url:   /:module/:action/*

9.4.1. Rules and Patterns

Routing rules are bijective associations between an external URL and an internal URI. A typical rule is made up of the following:

  • A unique label, which is there for legibility and speed, and can be used by the link helpers
  • A pattern to be matched (url key)
  • An array of request parameter values (param key)

Patterns can contain wildcards (represented by an asterisk, *) and named wildcards (starting with a colon, :). A match to a named wildcard becomes a request parameter value. For instance, the default rule defined in Listing 9-15 will match any URL like /foo/bar, and set the module parameter to foo and the action parameter to bar. And in the default_symfony rule, symfony is a keyword and action is named wildcard parameter.

The routing system parses the routing.yml file from the top to the bottom and stops at the first match. This is why you must add your own rules on top of the default ones. For instance, the URL /foo/123 matches both of the rules defined in Listing 9-16, but symfony first tests my_rule:, and as that rule matches, it doesn't even test the default: one. The request is handled by the mymodule/myaction action with bar set to 123 (and not by the foo/123 action).

Listing 9-16 - Rules Are Parsed Top to Bottom

  url:   /foo/:bar
  param: { module: mymodule, action: myaction }

# default rules
  url:   /:module/:action/*

Note When a new action is created, it does not imply that you must create a routing rule for it. If the default module/action pattern suits you, then forget about the routing.yml file. If, however, you want to customize the action's external URL, add a new rule above the default one.

Listing 9-17 shows the process of changing the external URL format for an article/read action.

Listing 9-17 - Changing the External URL Format for an article/read Action

<?php echo url_for('article/read?id=123') ?>
 => /article/read/id/123       // Default formatting

// To change it to /article/123, add a new rule at the beginning
// of your routing.yml
  url:   /article/:id
  param: { module: article, action: read }

The problem is that the article_by_id rule in Listing 9-17 breaks the default routing for all the other actions of the article module. In fact, a URL like article/delete will match this rule instead of the default one, and call the read action with id set to delete instead of the delete action. To get around this difficulty, you must add a pattern constraint so that the article_by_id rule matches only URLs where the id wildcard is an integer.

9.4.2. Pattern Constraints

When a URL can match more than one rule, you must refine the rules by adding constraints, or requirements, to the pattern. A requirement is a set of regular expressions that must be matched by the wildcards for the rule to match.

For instance, to modify the article_by_id rule so that it matches only URLs where the id parameter is an integer, add a line to the rule, as shown in Listing 9-18.

Listing 9-18 - Adding a Requirement to a Routing Rule

  url:   /article/:id
  param: { module: article, action: read }
  requirements: { id: \d+ }

Now an article/delete URL can't match the article_by_id rule anymore, because the 'delete' string doesn't satisfy the requirements. Therefore, the routing system will keep on looking for a match in the following rules and finally find the default rule.

9.4.3. Setting Default Values

You can give named wildcards a default value to make a rule work, even if the parameter is not defined. Set default values in the param: array.

For instance, the article_by_id rule doesn't match if the id parameter is not set. You can force it, as shown in Listing 9-19.

Listing 9-19 - Setting a Default Value for a Wildcard

  url:          /article/:id
  param:        { module: article, action: read, id: 1 }

The default parameters don't need to be wildcards found in the pattern. In Listing 9-20, the display parameter takes the value true, even if it is not present in the URL.

Listing 9-20 - Setting a Default Value for a Request Parameter

  url:          /article/:id
  param:        { module: article, action: read, id: 1, display: true }

If you look carefully, you can see that article and read are also default values for module and action variables not found in the pattern.

Tip You can define a default parameter for all the routing rules by defining the sf_routing_default configuration parameter. For instance, if you want all the rules to have a theme parameter set to default by default, add the line sfConfig::set('sf_routing_defaults', array('theme' => 'default')); to your application's config.php.

9.4.4. Speeding Up Routing by Using the Rule Name

The link helpers accept a rule label instead of a module/action pair if the rule label is preceded by an at sign (@), as shown in Listing 9-21.

Listing 9-21 - Using the Rule Label Instead of the Module/Action

<?php echo link_to('my article', 'article/read?id='.$article->getId()) ?>

// can also be written as
<?php echo link_to('my article', '@article_by_id?id='.$article->getId()) ?>

There are pros and cons to this trick. The advantages are as follows:

  • The formatting of internal URIs is done much faster, since symfony doesn't have to browse all the rules to find the one that matches the link. In a page with a great number of routed hyperlinks, the boost will be noticeable if you use rule labels instead of module/action pairs.
  • Using the rule label helps to abstract the logic behind an action. If you decide to change an action name but keep the URL, a simple change in the routing.yml file will suffice. All of the link_to() calls will still work without further change.
  • The logic of the call is more apparent with a rule name. Even if your modules and actions have explicit names, it is often better to call @display_article_by_slug than article/display.

On the other hand, a disadvantage is that adding new hyperlinks becomes less self-evident, since you always need to refer to the routing.yml file to find out which label is to be used for an action.

The best choice depends on the project. In the long run, it's up to you.

Tip During your tests (in the dev environment), if you want to check which rule was matched for a given request in your browser, develop the "logs and msgs" section of the web debug toolbar and look for a line specifying "matched route XXX". You will find more information about the web debug mode in Chapter 16.

9.4.5. Adding an .html Extension

Compare these two URLs:

Even if it is the same page, users (and robots) may see it differently because of the URL. The second URL evokes a deep and well-organized web directory of static pages, which is exactly the kind of websites that search engines know how to index.

To add a suffix to every external URL generated by the routing system, change the suffix value in the application settings.yml, as shown in Listing 9-22.

Listing 9-22 - Setting a Suffix for All URLs, in myapp/config/settings.yml

    suffix:         .html

The default suffix is set to a period (.), which means that the routing system doesn't add a suffix unless you specify it.

It is sometimes necessary to specify a suffix for a unique routing rule. In that case, write the suffix directly in the related url: line of the routing.yml file, as shown in Listing 9-23. Then the global suffix will be ignored.

Listing 9-23 - Setting a Suffix for One URL, in myapp/config/routing.yml

  url:          /latest_articles
  param:        { module: article, action: list }

  url:          /latest_articles.rss
  param:        { module: article, action: list, type: feed }

9.4.6. Creating Rules Without routing.yml

As is true of most of the configuration files, the routing.yml is a solution to define routing rules, but not the only one. You can define rules in PHP, either in the application config.php file or in the front controller script, but before the call to dispatch(), because this method determines the action to execute according to the present routing rules. Defining rules in PHP authorizes you to create dynamic rules, depending on configuration or other parameters.

The object that handles the routing rules is the sfRouting singleton. It is available from every part of the code by requiring sfRouting::getInstance(). Its prependRoute() method adds a new rule on top of the existing ones defined in routing.yml. It expects four parameters, which are the same as the parameters needed to define a rule: a route label, a pattern, an associative array of default values, and another associative array for requirements. For instance, the routing.yml rule definition shown in Listing 9-18 is equivalent to the PHP code shown in Listing 9-24.

Listing 9-24 - Defining a Rule in PHP

  'article_by_id',                                  // Route name
  '/article/:id',                                   // Route pattern
  array('module' => 'article', 'action' => 'read'), // Default values
  array('id' => '\d+'),                             // Requirements

The sfRouting singleton has other useful methods for handling routes by hand: clearRoutes(), hasRoutes(), getRoutesByName(), and so on. Refer to the API documentation ( to learn more.

Tip Once you start to fully understand the concepts presented in this book, you can increase your understanding of the framework by browsing the online API documentation or, even better, the symfony source. Not all the tweaks and parameters of symfony can be described in this book. The online documentation, however, is limitless.