Компонент Routing
Дата обновления перевода: 2023-07-31
Компонент Routing
Компонент Routing соединяет HTTP запрос с набором переменных конфигурации.
Установка
1
$ composer require symfony/routing
Также вы можете клонировать репозиторий https://github.com/symfony/routing.
Note
Если вы устанавливаете этот компонент вне приложения Symfony, вам нужно
подключить файл vendor/autoload.php в вашем коде для включения механизма
автозагрузки классов, предоставляемых Composer. Детальнее читайте в
этой статье.
Использование
See also
Эта статья объясняет как использовать функции Routing как независимого компонента в любом приложении PHP. Прочитайте статью Маршрутизация для понимания как использовать его в приложениях Symfony.
Для тог, чтобы установить базову систему маршрутизации, вам нужно три составляющие:
- RouteCollection, который содержит определения маршрутов (экземпляры класса Route)
- RequestContext, который содержит информацию о запросе
- UrlMatcher, который выполняет соединение запроса с единственным маршрутом
Вот быстрый пример. Заметьте, что предполагается, что вы уже сконфигурировали ваш автозагрузчик, чтобы он загружал компонент Routing:
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.
Определение маршрутов
Полное определение маршрута может содержать до семи частей:
- Маршрут пути URL. Он сопоставляется с URL, переданным `RequestContext`,
и может содержать названные рандомные заполнители (например,
{placeholders}), чтобы соответствовать динамическим частям URL. - Массив значений по умолчанию. Содержит массив арбитражных значений, которые будут возвращены, когда запрос соответствует маршруту.
- Массив требований. Он определяет ограничения значений заполнителей в виде регулярных выражений.
- Массив опций. Они содержит внутренние настройки для маршрута и является наименее необходимыми.
- Хост. Сопоставляется с хостом запроса. Смотрите Как сделать так, чтобы маршрут соответствовал на основании хоста, чтобы узнать больше.
- Массив схем. Форсирует определённую HTTP схему (
http,https). - Массив методов. Форсирует определённый метод 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}', // path
array('_controller' => 'showArchive'), // default values
array('month' => '[0-9]{4}-[0-9]{2}', 'subdomain' => 'www|m'), // requirements
array(), // options
'{subdomain}.example.com', // host
array(), // schemes
array() // methods
);
// ...
$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. Но вы также можете загружать маршруты из множества различных файлов.
Компонент Routing поставляется с определённым количеством классов загрузчиков, и каждый предоставляет вам возможность загружать коллекцию определения маршрутов из внешнего файла какого-либо формата. Каждый загрузчик ожидает экземпляр 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 является пакетом "всё-в-одном", для быстрого использования компонента Routing. Конструктор ожидают экземпляр загрузчика, путь к главному определению маршрута и некоторые другие настройки:
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
Если вы используете кэширование, компонент Routing скомпилирует новые
классы, которые сохраняются в cache_dir. Это значит, что ваш скрипт должен
иметь разрешение на запись в этой локации.
Поддержка маршрутизации Unicode
Компонент Routing поддерживает символы UTF-8 в путях маршрута и требованиях.
Благодаря опции маршрута utf8 , вы можете сделать так, чтобы Symfony сопоставляла
и генерировала маршрут с использованием UTF-8 символов:
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 строки в качестве требований маршрутизации:
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, компонент Routing также поддерживает все
свойства PCRE Unicode, которые экранируют последовательности, соответствующие
общим типам символов. Например, \p{Lu} соответствует любым символам верхнего
регистра на любом языке, \p{Greek} соответствует любому греческому символу,
\P{Han} соответствует любому символу, не включённому в скрипт Chinese Han.
Узнать больше
- Маршрутизация
- Как ограничить сопоставление маршрутов с помощью условий
- Как создать пользовательский загрузчик маршрутов
- Как визуализиовать и отлаживать маршруты
- Как подключать внешние источники маршрутизации
- Как передать дополнительную информацию из маршрута в контроллер
- Как генерировать URL маршрутизации в JavaScript
- Как сделать так, чтобы маршрут соответствовал на основании хоста
- Как определять необязательные заполнители
- Как сконфигурировать перенаправление без пользовательского контроллера
- Перенаправление URL с замыкающим слешем
- Как определять требования маршрутов
- Поиск маршрутов из базы данных: Symfony CMF DynamicRouter
- Как заставить маршруты всегда использовать HTTPS или HTTP
- Как использовать параметры сервис-контейнера в ваших маршрутах
- Как позволить знак "/" в параметре маршрута
- Контроллер
- Расширения разрешения аргумента действия
- Как настроить страницы ошибок
- Как пересылать запросы другому контроллеру
- Как определять контроллеры как сервисы
- Как создать SOAP веб-сервис в контроллере Symfony
- Как загружать файлы
- Расширение разрещения аргумента действия