routing


Beautiful URLs are an absolute must for any serious web application. This means that ugly URLs like index.php?article_id=57 will be replaced by /read/intro-to-symfony.

Having flexibility is even more important. What do you need to do to change the URL of the page from /blog to /news? How many links do you need to track and update to make changes? This is easy if you use Symfony's routing.

Symfony Router allows you to define creative URLs that map to different areas of your application. By the end of this chapter, you will be able to:

  • Create complex routes that will map to controllers

  • In templates and controls Generate URL in the server

  • Load routing resources from Bundle (can also be from other places)

  • Debug routing

Routing example

A route refers to the mapping from a URL path (path) to a controller (controller). For example, you want to match some URLs: /blog/my-post and /blog/all-about-symfony, and send a route to a "can query and render that blog post" " on the controller. Routing is very simple:

Annotations:// src/AppBundle/Controller/BlogController.phpnamespace AppBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class BlogController extends Controller{
    /**
     * @Route("/blog/{slug}", name="blog_show")
     */
    public function showAction($slug)
    {
        // ...
    }}
YAML:# app/config/routing.ymlblog_show:
    path:      /blog/{slug}
   defaults:  { _controller: AppBundle:Blog:show }
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/routing        http://symfony.com/schema/routing/routing-1.0.xsd">     <route id="blog_show" path="/blog/{slug}">
        <default key="_controller">AppBundle:Blog:show</default>
    </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\RouteCollection;use Symfony\Component\Routing\Route; $collection = new RouteCollection();$collection->add('blog_show', new Route('/blog/{slug}', array(
    '_controller' => 'AppBundle:Blog:show',))); return $collection;

define blog_show routing pattern, used to match URLs like /blog/*, use slug for relevant parameters or wildcards represents and is passed in. For a URL like /blog/my-blog-post, the slug variable gets the value of my-blog-post and is used by your controller. Meishiblog_show is an internal name. It has no practical meaning and is just a unique identifier. Later, you can use it to generate some URLs.

If you don't want to use annotations because you don't like them, or because you don't want to depend on SensioFrameworkExtraBundle, you can also use YAML, XML or PHP. In these formats, the _controller parameter is a special key that tells symfony which controller should be executed for the URL specified by the route. _controllerThe string is called logical name. It follows the rules and points to a specific php class and method, AppBundle\Controller\BlogController::showAction method.

Congratulations! You just created a route and connected it to the controller. Now, when you visit /blog/my-post, the showAction controller will be executed and the $slug variable will be equal to my-post.

The goal of Symfony routing: Map the requested URL to the controller. Following this goal, you'll learn a variety of techniques that make mapping even the most complex URLs simple.

Routing: A Deeper Look

When a request is sent to your application, it contains the exact "resource" address of the client request. This address is called a URL (or URI), and it can be /contact, /blog/read-me, or anything else. Here is an example of an HTTP request:

GET /blog/my-blog-post

The purpose of the symfony routing system is to parse the URL and determine which controller to call. The whole process is like this:

  1. The request is processed by Symfony's front-end controller (such as app.php).

  2. The core of symfony (Kernel kernel) requires the router to check the request.

  3. Route matches the input URL to a specific route and returns the route information, including the controller information to be executed.

  4. The Symfony kernel executes the controller and ultimately returns the Response object.

1466599518_84162_47822_request-flow-1.png

Routing converts an input URL into a specific tool to execute the controller.

Create Routes

Symfony loads all routes into your application from a single routing configuration file. The beautiful routing configuration file is usually app/config/routing.yml, but you can also place the file anywhere through the application configuration file (including configuration files in xml or php format).

YAML:# app/config/config.yml
framework:   
# ...
router: { resource: '%kernel.root_dir%/config/routing.yml' }
XML:<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:framework="http://symfony.com/schema/dic/symfony"    xsi:schemaLocation="http://symfony.com/schema/dic/services        http://symfony.com/schema/dic/services/services-1.0.xsd        http://symfony.com/schema/dic/symfony        http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">     <framework:config>
        <!-- ... -->
        <framework:router resource="%kernel.root_dir%/config/routing.xml" />
    </framework:config></container>
PHP:// app/config/config.php$container->loadFromExtension('framework', array(
   // ...    'router' => array(        'resource' => '%kernel.root_dir%/config/routing.php',    ),));

Although all routes can be loaded from a file, it is common practice to include additional routing resources. To do this, you configure the external routing file into the main routing file. For detailed information, please see this chapter: Contains external routing resources.

Basic routing configuration ¶

It is easy to define a route, and a typical application should also have many routes. A basic route contains two parts: path match and defaults array:

Annotations:// src/AppBundle/Controller/MainController.php // ...class MainController extends Controller{
    /**
     * @Route("/")
     */
    public function homepageAction()
    {
        // ...
    }}
YAML:# app/config/routing.yml_welcome:
    path:      /
    defaults:  { _controller: AppBundle:Main:homepage }
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/routing        http://symfony.com/schema/routing/routing-1.0.xsd">     <route id="_welcome" path="/">
        <default key="_controller">AppBundle:Main:homepage</default>
    </route> </routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\RouteCollection;use Symfony\Component\Routing\Route; $collection = new RouteCollection();$collection->add('_welcome', new Route('/', array(
    '_controller' => 'AppBundle:Main:homepage',))); return $collection;

The route matches the homepage (/) and map it to the AppBundle:Main:homepage controller. _controllerThe string is converted by Symfony into a PHP function for execution. The aesthetic process is briefly mentioned in this chapter (Controller Naming Patterns).

Routing with parameters ¶

The routing system supports many interesting ways of writing routes. Many routes can contain one or more "parameter or wildcard" placeholders:

Annotations:// src/AppBundle/Controller/BlogController.php // ...class BlogController extends Controller{
    /**
     * @Route("/blog/{slug}")
     */
    public function showAction($slug)
    {
        // ...
    }}
YAML:# app/config/routing.ymlblog_show:
    path:      /blog/{slug}
    defaults:  { _controller: AppBundle:Blog:show }
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/routing        http://symfony.com/schema/routing/routing-1.0.xsd">     <route id="blog_show" path="/blog/{slug}">
        <default key="_controller">AppBundle:Blog:show</default>
    </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\RouteCollection;use Symfony\Component\Routing\Route; $collection = new RouteCollection();$collection->add('blog_show', new Route('/blog/{slug}', array(
    '_controller' => 'AppBundle:Blog:show',))); return $collection;


Pretty paths will match any /blog/* URL. Even better, the beautiful {slug} placeholder will be automatically matched into the controller. In other words, if the URL is /blog/hello-world, the value of the $slug variable in the controller is hello-world. This can be used to match strings in blog post titles.

However, routing in this way will not match URLs like /blog, because by default, all placeholders are required. Of course, this can also be modified by adding placeholder (parameter) values ​​to the defaults array.

Add {wildcard} conditions

Take a quick look at the routes you have created:

Annotations:// src/AppBundle/Controller/BlogController.php // ...class BlogController extends Controller{
    /**
     * @Route("/blog/{page}", defaults={"page" = 1})
     */
    public function indexAction($page)
    {
        // ...
    }     /**
     * @Route("/blog/{slug}")
     */
    public function showAction($slug)
    {
        // ...
    }}
YAML:# app/config/routing.ymlblog:
    path:      /blog/{page}
    defaults:  { _controller: AppBundle:Blog:index, page: 1 }blog_show:
    path:      /blog/{slug}
    defaults:  { _controller: AppBundle:Blog:show }
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/routing        http://symfony.com/schema/routing/routing-1.0.xsd">     <route id="blog" path="/blog/{page}">
        <default key="_controller">AppBundle:Blog:index</default>
        <default key="page">1</default>
    </route>     <route id="blog_show" path="/blog/{slug}">
        <default key="_controller">AppBundle:Blog:show</default>
    </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\RouteCollection;use Symfony\Component\Routing\Route; $collection = new RouteCollection();$collection->add('blog', new Route('/blog/{page}', array(
    '_controller' => 'AppBundle:Blog:index',
    'page'        => 1,))); $collection->add('blog_show', new Route('/blog/{show}', array(
    '_controller' => 'AppBundle:Blog:show',))); return $collection;


Can you spot the problem? Both routes match URLs like /blog/*. Symfony routing always chooses the first matching (blog) route it matches. In other words, the blog_show route will always be matched. In contrast, a URL like /blog/my-blog-post will match the first (blog) route and return a my-blog-post The value is given to the {page} parameter.

##URLRouteParameters##/blog/my-blog-postblog_show$slug

Give {wildcard} a default value

Advanced routing example

In Symfony you can create a powerful routing structure to achieve everything you need. Here is an example to show how flexible the routing system is:

Annotations:// src/AppBundle/Controller/ArticleController.php // ...class ArticleController extends Controller{
    /**
     * @Route(
     *     "/articles/{_locale}/{year}/{title}.{_format}",
     *     defaults={"_format": "html"},
     *     requirements={
     *         "_locale": "en|fr",
     *         "_format": "html|rss",
     *         "year": "\d+"
     *     }
     * )
     */
    public function showAction($_locale, $year, $title)
    {
    }}
YAML:# app/config/routing.ymlarticle_show:
  path:     /articles/{_locale}/{year}/{title}.{_format}
  defaults: { _controller: AppBundle:Article:show, _format: html }
  requirements:
      _locale:  en|fr
      _format:  html|rss
      year:     \d+
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/routing        http://symfony.com/schema/routing/routing-1.0.xsd">     <route id="article_show"        path="/articles/{_locale}/{year}/{title}.{_format}">         <default key="_controller">AppBundle:Article:show</default>
        <default key="_format">html</default>
        <requirement key="_locale">en|fr</requirement>
        <requirement key="_format">html|rss</requirement>
        <requirement key="year">\d+</requirement>     </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\RouteCollection;use Symfony\Component\Routing\Route; $collection = new RouteCollection();$collection->add(
    'article_show',
    new Route('/articles/{_locale}/{year}/{title}.{_format}', array(
        '_controller' => 'AppBundle:Article:show',
        '_format'     => 'html',
    ), array(
        '_locale' => 'en|fr',
        '_format' => 'html|rss',
        'year'    => '\d+',
    ))); return $collection;

As you can see, beautiful routing only matches a part of the URL that satisfies {_locale} is ( en or fr) and {year} are numeric. This route also shows you that you can use a period to separate two placeholders. The URL matched by the above route is as follows:

  • ##/articles/en/2010/my-post

  • /articles/fr/2010/my-post.rss

  • ##/articles/en/2013/my-latest-post.html

Special _format route parameters

This example also highlights the special

_format

Routing parameters. When this parameter is used, the matching value becomes the "request format" of the Request object. Ultimately, the request format is used in places like "setting the

Content-Type

of the response" (for example, a json request format will be converted to application/ jsonContent-Type). It can also be used in the controller to render different templates based on different _format values. The _format parameter is a very powerful way to render the same content in different formats. In versions before symfony3.0, you can override the format parameter (

_format

) in the request (object) by adding a parameter named "_format" Just query parameters (for example: /foo/bar?_format=json). Abuse of this behavior is considered bad practice and will make upgrading your program to symfony3 "extremely complicated".

#Sometimes you want to make certain parts of a route "global configuration". Symfony can do this using service container parameters. See How to use service container parameters in routing to learn more.

Special Route Parameters ¶

As you can see, every route parameter or default value can be used as a parameter of the controller method. Additionally, three parameters are special: Each adds a unique functionality to your application:

  • _controller
  • As you can see, this parameter is used to determine which controller to execute "when the route matches".
  • _format
  • is used to set the request format (request format. Learn more).
  • _locale
  • Used to set the requested locale (learn more).

Controller naming pattern

If you use YAML, XML or PHP route configuration, then each route must have a _controller parameter that indicates which controller should be executed when the route matches. This parameter uses a simple string pattern called logical controller name, which Symfony uses to map a specific PHP method or class. This pattern has three parts, separated by colons:

bundle:controller:action

Assume, a _controller The value is an AppBundle:Blog:show which means:

/blog/2blog_list$page = 2
= my-blog-post
##BundleController ClassMethod Name##AppBundleBlogController showAction

The controller might look like this:

// src/AppBundle/Controller/BlogController.phpnamespace AppBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class BlogController extends Controller{
    public function showAction($slug)
    {
        // ...
    }}

Note that Symfony added the string Controller as the class name on Blog (Blog=>BlogController), add the string Action as the method name (show=>showAction).

You can also specify this class using its FQCN class name and method: AppBundle\Controller\BlogController::showAction. But if you follow some simple naming conventions, logical names will be simpler and more flexible.

In addition to using logical names and FQCN class names, Symfony also supports a third way of specifying controllers. This approach is separated only by a colon (e.g. service_name:indexAction) and refers to the controller as a service (see How to define a controller as a service).

Routing parameters and controller parameters ¶

Routing parameters (such as {slug} are very important because they (they) are Used as parameters for controller methods:

public function showAction($slug){
  // ...}

In reality, defaults sets the parameter values ​​​​together into a form array. Each key in the array is used as a controller Parameters.

In other words, for each parameter of the controller method, Symfony2 will look up the route parameter based on that name and point its value to the controller as the parameter. In the advanced example above Among them, any combination of the following variables (in any way) are used as parameters of the showAction() method:

  • $_locale

  • $year

  • $title

  • $_format

  • $_controller# The

  • ##$_route

placeholder and

defaults set are merged together, even if it is $_controller Variables are also available. For a more detailed discussion, see As a Controller – Passing Route Parameters into Controllers.

You can also use specific

$ _routeVariable, its value is the matched route name.

You can even define additional information in your routes and access it in your controllers. For more information read How to pass additional information from routes to controllers

Generating URLs ¶

The routing system is also used to generate URLs. In reality, routing is a two-way system: mapping URLs to controller parameters and mapping route parameters back to the URL. The match() and generate() methods constitute this two-way system. Using the previous blog_show example:

$params = $this->get('router')->match('/blog/my-blog-post');
// array(
//     'slug'        => 'my-blog-post',
//  '_controller' => 'AppBundle:Blog:show',
// ) 
$uri = $this->get('router')->generate('blog_show', array(
  'slug' => 'my-blog-post'));
// /blog/my-blog-post

To generate a URL, you need to specify the name of the route (such as blog_show) and any wildcards (such as slug = my-blog-post). With this information, any URL can be easily generated:

class MainController extends Controller{
    public function showAction($slug)
    {
        // ...         $url = $this->generateUrl(
            'blog_show',
            array('slug' => 'my-blog-post')
        );
    }}

In the controller, if you do not inherit the symfony parent class Controller, then you cannot use generateUrl()Shortcut method, but you can use router's generate()Service method:

$url = $this->container->get('router')->generate(
    'blog_show',
    array('slug' => 'my-blog-post'));

In the upcoming section, you will learn how to generate URL addresses in templates .

If your application front-end uses ajax requests, you may want to generate the URL in JavaScript based on your routing configuration. By using the FOSJsRoutingBundle, you can do:

var url = Routing.generate(
    'blog_show',
    {"slug": 'my-blog-post'});

Please read this bundle document for more information.

Generate URLs with Query Strings

This generate method uses a wildcard array to generate URLs. But if additional key-value pairs are added to it, they will be added as Query Strings to generate a new URL:

$this->get('router')->generate('blog', array(
    'page' => 2,
    'category' => 'Symfony'));// /blog/2?category=Symfony

Generate URL in template

When connecting between application pages, the most common place to do this is to generate URLs from templates. Doing this is actually the same as before, but using a template helper function:

Twig:<a href="{{ path('blog_show', {'slug': 'my-blog-post'}) }}">
  Read this blog post.
</a>
php:<a href="<?php echo $view['router']->path('blog_show', array(
    'slug' => 'my-blog-post',)) ?>">
    Read this blog post.
</a>

Generate absolute URL

By default, the router will generate relative URLs (such as /blog). In the controller, it is very simple to set the third parameter of the generateUrl() method to UrlGeneratorInterface::ABSOLUTE_URL.

use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
 $this->generateUrl('blog_show', array('slug' => 'my-blog-post'), UrlGeneratorInterface::ABSOLUTE_URL);
// http://www.example.com/blog/my-blog-post

In the template engine Twig, use the url() function (generates an absolute URL) instead of the path() function (generates a relative URL). URL). In php, you need to pass in UrlGeneratorInterface::ABSOLUTE_URL:

Twig:<a href="{{ url('blog_show', {'slug': 'my-blog-post'}) }}">
  Read this blog post.
</a>
php:<a href="<?php echo $view['router']->url('blog_show', array(
    'slug' => 'my-blog-post',)) ?>">
    Read this blog post.
</a>

当生成一个绝对URL链接时,所使用的主机自动检测当前使用的Request对象。当生成从web环境外的绝对URL(例如一个控制台命令)这是行不通的。请参见 如何从控制台生成URL 来学习如何解决这个问题。


Summary ¶

Routing is a URL that maps the incoming request to the URL used to process the request A system of controller functions. It allows you to specify a beautiful URL and "decouple" the functionality of the application from the URL. Routing is a two-way mechanism, meaning it can also be used to generate URLs.

Keep Going! ¶

Routing, verified! Now, go and unblock the controller's power.