Как определять требования маршрутов

Требования маршрутов могут быть использованы так, чтобы определённый маршрут соответствовал только при определённых условиях. Простейший пример включает в себя ограничение маршрута {wildcard} так, чтобы он соответствовал только некоторым регулярным выражениям:

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    // src/Controller/BlogController.php
    namespace App\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\Routing\Annotation\Route;
    
    class BlogController extends Controller
    {
        /**
         * @Route("/blog/{page}", name="blog_list", requirements={"page"="\d+"})
         */
        public function list($page)
        {
            // ...
        }
    }
    
  • YAML
    1
    2
    3
    4
    5
    6
    # config/routes.yaml
    blog_list:
        path:      /blog/{page}
        controller: App\Controller\BlogController::list
        requirements:
            page: '\d+'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    <!-- config/routes.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_list" path="/blog/{page}">
            <default key="_controller">App\Controller\BlogController::list</default>
            <requirement key="page">\d+</requirement>
        </route>
    
        <!-- ... -->
    </routes>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    // config/routes.php
    use Symfony\Component\Routing\RouteCollection;
    use Symfony\Component\Routing\Route;
    
    $collection = new RouteCollection();
    $collection->add('blog_list', new Route('/blog/{page}', array(
        '_controller' => 'App\Controller\BlogController::list',
    ), array(
        'page' => '\d+',
    )));
    
    // ...
    
    return $collection;
    

Благодаря требованию \d+ (т.е. "числовое значение" любой длины), /blog/2 будет соответствовать этому маршруту, но /blog/some-string - не будет.

Зачем вам вообще думать о требованиях? Если запрос соответствует двум маршрутам, то первый маршрут всегда будет выигрывать. Путём добавления требований к первому маршруту, вы можете сделать так, чтобы каждый маршрут соответствовал только в правильных ситуациях. См. Требования маршрутизации, чтобы увидеть примеры.

Так как требования параметров - это регулярный выражения, сложность и гибкость каждого требования полностью зависит от вас. Представьте, что домашняя страница вашего приложения доступна на двух разных языках, основываясь на URL:

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    // src/Controller/MainController.php
    
    // ...
    class MainController extends Controller
    {
        /**
         * @Route("/{_locale}", defaults={"_locale"="en"}, requirements={
         *     "_locale"="en|fr"
         * })
         */
        public function homepage($_locale)
        {
        }
    }
    
  • YAML
    1
    2
    3
    4
    5
    6
    7
    # config/routes.yaml
    homepage:
        path:       /{_locale}
        controller: App\Controller\MainController::homepage
        defaults:   { _locale: en }
        requirements:
            _locale:  en|fr
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <!-- config/routes.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="homepage" path="/{_locale}">
            <default key="_controller">App\Controller\MainController::homepage</default>
            <default key="_locale">en</default>
            <requirement key="_locale">en|fr</requirement>
        </route>
    </routes>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    // config/routes.php
    use Symfony\Component\Routing\RouteCollection;
    use Symfony\Component\Routing\Route;
    
    $collection = new RouteCollection();
    $collection->add('homepage', new Route('/{_locale}', array(
        '_controller' => 'App\Controller\MainController::homepage',
        '_locale'     => 'en',
    ), array(
        '_locale' => 'en|fr',
    )));
    
    return $collection;
    

Для входящих запросов, часть URL {_locale} соответствует регулярному выражению (en|fr).

Путь Параметры
/ {_locale} = "en"
/en {_locale} = "en"
/fr {_locale} = "fr"
/es не будет соответствовать этому маршруту

Note

Вы можете подключить сопоставление маршрутов UTF-8, установив опцию utf8 при объявлении или импортировании маршрутов. Таким образом, к примеру, . в требованиях будет совпадать с любыми символами UTF-8, а не только с одним байтом.

Tip

Требования маршрутов также могут включать в себя параметры контейнеров, как объявсняется в этой статье. Это может быть полезным, когда регулярное выражение очень сложное и многократно используется в вашем приложении.

Добавление требований HTTP-методов

В дополнение к URL, вы также можете использовать соответствие в методе входящего запроса (т.е. GET, HEAD, POST, PUT, DELETE). Представьте, что вы создаёте API для вашего блога, и у вас есть 2 маршрута: один для отображения записи (по запросу GET или HEAD), и один для обновления записи (по запросу PUT). Этого можно достичь с помощью следующей конфигурации маршрута:

  • Annotations
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // src/Controller/BlogApiController.php
    namespace App\Controller;
    
    // ...
    
    class BlogApiController extends Controller
    {
        /**
         * @Route("/api/posts/{id}", methods={"GET","HEAD"})
         */
        public function show($id)
        {
            // ... return a JSON response with the post
        }
    
        /**
         * @Route("/api/posts/{id}", methods="PUT")
         */
        public function edit($id)
        {
            // ... edit a post
        }
    }
    
  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    # config/routes.yaml
    api_post_show:
        path:       /api/posts/{id}
        controller: App\Controller\BlogApiController::show
        methods:    [GET, HEAD]
    
    api_post_edit:
        path:       /api/posts/{id}
        controller: App\Controller\BlogApiController::edit
        methods:    [PUT]
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    <!-- config/routes.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="api_post_show" path="/api/posts/{id}" methods="GET|HEAD">
            <default key="_controller">App\Controller\BlogApiController::show</default>
        </route>
    
        <route id="api_post_edit" path="/api/posts/{id}" methods="PUT">
            <default key="_controller">App\Controller\BlogApiController::edit</default>
        </route>
    </routes>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    // config/routes.php
    use Symfony\Component\Routing\RouteCollection;
    use Symfony\Component\Routing\Route;
    
    $collection = new RouteCollection();
    $collection->add('api_post_show', new Route('/api/posts/{id}', array(
        '_controller' => 'App\Controller\BlogApiController::show',
    ), array(), array(), '', array(), array('GET', 'HEAD')));
    
    $collection->add('api_post_edit', new Route('/api/posts/{id}', array(
        '_controller' => 'App\Controller\BlogApiController::edit',
    ), array(), array(), '', array(), array('PUT')));
    
    return $collection;
    

Несмотря на тот факт, что эти два маршрута имеют идентичные пути (/api/posts/{id}), первый маршрут будет соответствовать только запросам GET или HEAD, а второй - только запросам PUT. Это означает, что вы можете отобразить и изменить запись с одним и тем же URL, используя отдельные контроллеры для двух действий.

Note

Если не указано никаких methods (методов), то маршрут будет соответствовать всем методам.

Tip

Если вы используете HTML-формы и HTTP-методы кроме GET и POST, вам понадобится включить параметр _method чтобы сымитировать HTTP-метод. См. How to Change the Action and Method of a Form, чтобы узнать больше.

Добавление требования хоста

Вы также можете использовать соответствие в HTTP хосте входящего запроса. Чтобы узнать больше об этом, см. How to Match a Route Based on the Host в документации компонента Маршрутизация.

Добавление динамических требований с выражениями

Для очень сложных требований вы можете использовать динамические выражения для соответствия любой информации по запросу. Смотрите Условия маршрутизации.

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.