Компонент Маршрутизація

Дата оновлення перекладу 2022-05-02

Компонент Маршрутизація

Компонент Маршрутизація з'єднує HTTP-запит з набором змінних конфігурації.

Установка

1
$ composer require symfony/routing

Також ви можете клонувати репозиторій https://github.com/symfony/routing.

Note

Якщо ви встановлюєте цей компонент поза додатком Symfony, вам потрібно підключити файл vendor/autoload.phpу вашому коді для включення механізму автозавантаження класів, наданих Composer. Детальніше можна прочитати у цій статті.

Використання

See also

Ця стаття пояснює як використовувати функції Маршрутизатору у якості незалежного компоненту в будь-якому додатку PHP. Прочитайте статтю Routing для розуміння, як використовувати його в додатках Symfony.

Для того, щоб встановити базову систему маршрутизації, вам необхідні три складові:

  • RouteCollection, який містить визначення маршрутів (екземпляри класу Route)
  • RequestContext, який містить інформацію про запит
  • UrlMatcher, який виконує з'єднання запиту з єдиним маршрутом

Ось швидкий приклад. Відмітьте, що передбачається, що ви вже сконфігурували ваш автозавантажувач, щоб він завантажував компонент Маршрутизація:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$route = new Route('/foo', array('_controller' => 'MyController'));
$routes = new RouteCollection();
$routes->add('route_name', $route);

$context = new RequestContext('/');

$matcher = new UrlMatcher($routes, $context);

$parameters = $matcher->match('/foo');
// масив ('_controller' => 'MyController', '_route' => 'route_name')

Note

Параметри RequestContext можуть бути наповнені значеннями, що зберігаються в $_SERVER, але легше використовувати компонент HttpFoundation, як пояснюється нижче.

Ви можете додавати до RouteCollection стільки маршрутів, скільки хочете.

Метод RouteCollection::add() бере два аргументи. Перший - це ім'я маршруту. Другий - об'єкт Route, який очікує URL-шлях і деякий масив користувацьких змінних в своєму конструкторі. Цей масив користувацьких змінних може бути чим завгодно важливим для вашого додатку, і повертатися при співстваленні маршруту.

UrlMatcher::match() повертає змінні, які ви встановили в маршруті, а також рандомні заповнювачі (див. нижче). Тепер ваш застосунок може використовувати цю інформацію, щоб продовжувати обробку запиту. На додаток до сконфігурованих змінних, додається ключ _route, який містить ім'я відповідного маршруту.

Якщо відповідний маршрут не знайдено, буде викликане ResourceNotFoundException.

Визначення маршрутів

Повне визначення маршруту може містити до семи частин:

  1. Маршрут шляху URL. Він співставляється з URL, який передано `RequestContext`, і може містити названі рандомні заповнювачі (наприклад, {placeholders}), щоб відповідати динамічним частинам URL.
  2. Масив значень за замовчуванням. Містить масив арбітражних значень, які будуть повернені, коли запит відповідає маршруту.
  3. Масив вимог. Він визначає обмеження значень заповнювачів у вигляді регулярних виразів.
  4. Масив опцій. Він містить внутрішні налаштування для маршруту та є найменш необхідним.
  5. Хостинг. Співставляється з хостингом запиту. Дивіться Как сделать так, чтобы маршрут соответствовал на основании хоста, щоб дізнатися більше.
  6. Масив схем. Форсує певну HTTP-схему (http, https).
  7. Масив методів. Форсує певний метод HTTP-запиту (HEAD, GET, POST, ...).

Розгляньте наступний маршрут, який поєднує деякі з цих ідей:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$route = new Route(
    '/archive/{month}', // шлях
    array('_controller' => 'showArchive'), // значення за замовчуванням values
    array('month' => '[0-9]{4}-[0-9]{2}', 'subdomain' => 'www|m'), // вимоги
    array(), // опції
    '{subdomain}.example.com', // хостинг
    array(), // схеми
    array() // методи
);

// ...

$parameters = $matcher->match('/archive/2012-01');
// array(
//     '_controller' => 'showArchive',
//     'month' => '2012-01',
//     'subdomain' => 'www',
//     '_route' => ...
//  )

$parameters = $matcher->match('/archive/foo');
// викликає ResourceNotFoundException

В цьому випадку, маршрут співставляється з /archive/2012-01, так як метасимвол {month} відповідає регулярному виразу заданого метасимволу. Однак, /archive/foo не відповідає, так як "foo" не підходить метасимволу місяця.

При використанні метасимволів, вони повертаються у вигляді масиву, при виклику match. Частина шляху, з якою співставляється метасимвол (наприклад, 2012-01), використовується в якость значення.

Tip

Якщо ви хочете співставити всі URL, які починаються з певного шляху і закінчуються довільним суфіксом, ви можете використовувати наступне визначення маршруту:

1
2
3
4
5
$route = new Route(
    '/start/{suffix}',
    array('suffix' => ''),
    array('suffix' => '.*')
);

Використання префіксів

Ви можете додавати маршрути або інші екземпляри RouteCollection до іншої колекції. Таким чином, ви можете побудувати дерево маршрутів. Крім того, ви можете визначити префікс та значення за замовчуванням для параметрів, вимог, опцій, схем та хостингу для всіх маршрутів піддерева, використовуючи методи, надані класом RouteCollection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$rootCollection = new RouteCollection();

$subCollection = new RouteCollection();
$subCollection->add(...);
$subCollection->add(...);
$subCollection->addPrefix('/prefix');
$subCollection->addDefaults(array(...));
$subCollection->addRequirements(array(...));
$subCollection->addOptions(array(...));
$subCollection->setHost('admin.example.com');
$subCollection->setMethods(array('POST'));
$subCollection->setSchemes(array('https'));

$rootCollection->addCollection($subCollection);

Установка параметрів запиту

RequestContext надає інформацію про поточний запит. Ви можете визначити всі параметри HTTP-запиту з цим класом через його конструктор:

1
2
3
4
5
6
7
8
9
10
public function __construct(
    $baseUrl = '',
    $method = 'GET',
    $host = 'localhost',
    $scheme = 'http',
    $httpPort = 80,
    $httpsPort = 443,
    $path = '/',
    $queryString = ''
)

Зазчиай ви можете передати значення зі змінної $_SERVER, щоб наповнити RequestContext. Але якщо ви використовуєте компонент HttpFoundation , ви можете використати його клас Request, щоб наповнити RequestContext за допомогою скорочення:

1
2
3
4
use Symfony\Component\HttpFoundation\Request;

$context = new RequestContext();
$context->fromRequest(Request::createFromGlobals());

Генерування URL

В той час як UrlMatcher намагається знайти маршрут, який відповідає заданому запиту, ви можете також побудувати URL з певного маршруту:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

$routes = new RouteCollection();
$routes->add('show_post', new Route('/show/{slug}'));

$context = new RequestContext('/');

$generator = new UrlGenerator($routes, $context);

$url = $generator->generate('show_post', array(
    'slug' => 'my-blog-post',
));
// /show/my-blog-post

Note

Якщо ви визначили схему, генерується абсолютний URL, якщо схема поточного RequestContext не відповідає вимозі.

Перевірка існування шляху

У додатках, що динамічно розвиваються, може бути необхідним перевірити існування шляхе перед генеруванням URL. В таких випадках не використовуйте метод getRouteCollection() тому що він повторно створює кеш таблиці маршрутизації та уповільнює застосунок.

Замість цього спробуйте створити URL та ловіть виключення RouteNotFoundException, яке буде викликано, якщо маршрут не існує:

1
2
3
4
5
6
7
8
9
use Symfony\Component\Routing\Exception\RouteNotFoundException;

// ...

try {
    $url = $generator->generate($dynamicRouteName, $parameters);
} catch (RouteNotFoundException $e) {
    // маршрут не визначено...
}

Завантаження маршрутів з файлу

Ви вже бачили, як ви з легкістю можете додавати маршрути в колекцію прямо всередині PHP. Але ви також можете завантажувати маршрути із безлічі різних файлів.

Компонент Маршрутизація постачається з певною кількістю класів завантажувачів, і кожний надає вам можливість завантажувати колекцію визначення маршрутів із зовнішнього файлу якогось формату. Кожний завантажувач очікує екземпляр FileLocator, в якості аргументу конструктору. Ви можете використовувати FileLocator, щоб визначити масив шляхів, в яких завантажувач шукатиме запитувані файли. Якщо файл не знайдено, завантажувач повертає RouteCollection.

Якщо ви використовуєте YamlFileLoader, то визначення маршруту виглядатиме так:

1
2
3
4
5
6
7
8
# routes.yaml
route1:
    path:     /foo
    defaults: { _controller: 'MyController::fooAction' }

route2:
    path:     /foo/bar
    defaults: { _controller: 'MyController::foobarAction' }

Щоб завантажити цей файл, ви можете використати наступний код. Передбачається, що ваш файл routes.yaml знаходиться в тому ж каталозі, що і в коді нижче:

1
2
3
4
5
6
7
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;

// шукає всередині *цього* каталогу
$fileLocator = new FileLocator(array(__DIR__));
$loader = new YamlFileLoader($fileLocator);
$routes = $loader->load('routes.yaml');

Окрім YamlFileLoader, існує два інших завантажувача, які працюють таким же чином:

Якщо ви використовуєте PhpFileLoader, то вам необхідно надати ім'я PHP-файлу, який повертає RouteCollection:

1
2
3
4
5
6
7
8
9
10
11
12
// RouteProvider.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$routes = new RouteCollection();
$routes->add(
    'route_name',
    new Route('/foo', array('_controller' => 'ExampleController'))
);
// ...

return $routes;

Маршрути, як завершувачі

Також існує ClosureLoader, який викликає завершувач, та використовує результат в якості RouteCollection:

1
2
3
4
5
6
7
8
use Symfony\Component\Routing\Loader\ClosureLoader;

$closure = function () {
    return new RouteCollection();
};

$loader = new ClosureLoader();
$routes = $loader->load($closure);

Маршрути, як анотації

Нарешті, існують AnnotationDirectoryLoader та AnnotationFileLoader, для завантаження визначень маршруту з анотацій класу. Конкретні деталі тут не розглядаються.

Note

Для того, чтобы использовать загрузчик аннотаций, вам нужно было установить в Composеr пакеты doctrine/annotations и doctrine/cache.

Tip

Классы аннотаций не загружаются автоматически, так что вам нужно загружать их, используя хагрузчик классов таким образом:

1
2
3
4
5
6
7
8
9
use Composer\Autoload\ClassLoader;
use Doctrine\Common\Annotations\AnnotationRegistry;

/** @var ClassLoader $loader */
$loader = require __DIR__.'/../vendor/autoload.php';

AnnotationRegistry::registerLoader([$loader, 'loadClass']);

return $loader;

Маршрутизатор "все-в-одному"

Клас Router є пакетом "все-в-одному", для швидкого використання компоненту Маршрутизація. Конструктор очікує екземпляр завантажувача, шлях до головного визначення маршруту та деякі інші налаштування:

1
2
3
4
5
6
7
public function __construct(
    LoaderInterface $loader,
    $resource,
    array $options = array(),
    RequestContext $context = null,
    LoggerInterface $logger = null
);

З опцією cache_dir, ви можете увімкнути кешування маршруту (якщо ви надасте шлях), або відключити кешування (якщо воно встановлене, як null). Кешування проводиться фоново автоматично, якщо ви хочете його використовувати. Базовим прикладом класу Router буде:

1
2
3
4
5
6
7
8
9
10
$fileLocator = new FileLocator(array(__DIR__));
$requestContext = new RequestContext('/');

$router = new Router(
    new YamlFileLoader($fileLocator),
    'routes.yaml',
    array('cache_dir' => __DIR__.'/cache'),
    $requestContext
);
$router->match('/foo/bar');

Note

Якщо ви використовуєте кешування, компонент Маршрутизація скомпілює нові класи, які зберігаються в cache_dir. Це означає, що ваш скрипт повинен мати дозвіл на запис в цій локації.

Підтримка маршрутизації Unicode

Компонент Маршрутизація підтримує символи UTF-8 у шляхах маршруту та вимогах. Завдяки опції маршруту utf8 , ви можете зробити так, щоб Symfony співставляла та генерувала маршрут з використанням UTF-8 символів:

  • Annotations
  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /**
     * @Route("/category/{name}", name="route1", options={"utf8": true})
     */
    public function category()
    {
        // ...
    }

В цьому маршруті, опція utf8 встановлена як true, що змушує Symfony розглянути вимогу . на відповідніть якимось символам UTF-8, замість одного символу байту. Це означає, що наступні URL будуть відповідати: /category/日本語, /category/فارسی, /category/한국어, і т.д. У випадку, якщо ви хотіли знати, ця опція також дозволяє вмикати та співставляти емоджі в URL.

Ви також можете включати UTF-8 рядки в якості вимог маршрутизації:

  • Annotations
  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /**
     * @Route(
     *     "/category/{name}",
     *     name="route2",
     *     requirements={"default"="한국어"},
     *     options={"utf8": true}
     * )
     */
    public function default()
    {
        // ...
    }

Tip

Окрім символів UTF-8, компонент Маршрутизація також підтримує всі властивості PCRE Unicode, які екранують послідовності, що відповідають загальним типам символів. Наприклад, \p{Lu} відповідає будь-яким символам верхнього регістру на будь-якій мові, \p{Greek} відповідає будь-якому грецькому символу, \P{Han} відповідає будь-якому символу, який не включено в скрипт Chinese Han.

Дізнайтеся більше