При обработке запрошенного URL, Yii приложение первым делом разбирает URL в маршрут. Полученный маршрут используется при создании соответствующего экземпляра действия контроллера для обработки запроса. Этот процесс называется роутинг.
Обратный роутингу процесс называется Создание URL, он отвечает за создание URL из заданного маршрута и соответствующих параметров запроса. При необходимости, созданный URL всегда может быть преобразован в первоначальные маршрут и параметры запроса.
В основе роутинга и создания URL лежит использование URL manager,
зарегистрированного в качестве компонента приложения urlManager
.
URL manager содержит метод parseRequest()
для разбора входящего запроса на маршрут и параметры запроса, и метод createUrl()
для создания URL из заданного маршрута и параметров запроса.
Настройка компонента urlManager
в конфигурации приложения, позволяет приложению распознавать различные
форматы URL без внесения изменений в существующий код приложения. Например, для
создания URL для действия post/view
, можно использовать следующий код:
use yii\helpers\Url;
// Url::to() вызывает UrlManager::createUrl() для создания URL
$url = Url::to(['post/view', 'id' => 100]);
В зависимости от настройки urlManager
, URL может быть создан в одном из следующих форматов (или любом другом формате). При последующем запросе URL в таком формате, он будет разобран на исходные маршрут и параметры запроса.
/index.php?r=post/view&id=100
/index.php/post/100
/post/100
URL manager поддерживает два формата URL:
Обычный формат URL использует параметр r
для передачи маршрута и любые другие параметры для передачи остальных параметров запроса. Например, URL /index.php?r=post/view&id=100
задает маршрут post/view
и параметр id
, равный 100. Данный формат не требует специальной конфигурации URL manager и работает с любыми настройками веб-сервера.
Человекопонятный формат URL представляет собой дополнительный путь, следующий за именем входного скрипта, описывающий маршрут и остальные параметров запроса. Например, дополнительный путь в URL /index.php/post/100
- это /post/100
, который может представлять маршрут post/view
и параметр id
со значением равным 100, при наличии соответствующего правила. Для использования ЧПУ, необходимо создать набор правил, соответствующих требованиям к URL.
Переключение между двумя форматами URL осуществляется при помощи свойства enablePrettyUrl компонента URL manager без внесения изменений в код приложения.
Роутинг осуществляется в два этапа:
При использовании простого формата URL, получение маршрута из запроса заключается в получении параметра r
из массива GET
.
При использовании ЧПУ, компонент URL manager ищет среди зарегистрированных правил подходящее для разрешения запроса в маршрут. Если такое правило не найдено, вызывается исключение yii\web\NotFoundHttpException.
После того, как из запроса получен маршрут, самое время создать действие контроллера, соответствующее этому маршруту.
Маршрут разделяется на несколько частей, метками деления служат прямые слеши. Например, маршрут site/index
будет разделен на site
и index
. Каждая из частей представляет собой идентификатор, который может ссылаться на модуль, контроллер или действие. Начиная с первой части маршрута, приложение следует следующему алгоритму для создания модуля (если есть), контроллера и действия:
При возникновении ошибок на любом из описанных выше этапов, вызывается исключение yii\web\NotFoundHttpException, указывающее на ошибку в процессе роутинга.
В случае, если в результате разбора запроса получен пустой маршрут, вместо него будет использован, так называемый, маршрут по умолчанию. Изначально, маршрут по умолчанию имеет значение site/index
, и указывает на действие index
контроллера site
. Указать свое значение можно при помощи свойства приложения defaultRoute, например так:
[
// ...
'defaultRoute' => 'main/index',
];
В добавок к маршруту по умолчанию приложения, существует маршрут по умолчанию модулей. Например, если у нас есть модуль
user
и запрос разбирается в маршрут user
, defaultRoute модуля используется для
определения контроллера. По умолчанию имя контроллера —default
. Если действие не задано в defaultRoute,
то для его определения используется свойство defaultAction контроллера.
В данном примере полный маршрут будет user/default/index
.
catchAll
¶Иногда возникает необходимость временно перевести приложение в режим обслуживания и отображать одно информационное сообщение для всех запросов. Существует много вариантов реализации этой задачи. Но одним из самых простых, является использование свойства yii\web\Application::$catchAll, например так:
[
// ...
'catchAll' => ['site/offline'],
];
В данном случае, действие site/offline
будет обрабатывать все входящие запросы.
Свойство catchAll
должно принимать массив, первый элемент которого определяет маршрут, а остальные элементы (пары ключ-значение) определяют параметры, передаваемые действию.
Для создания разных видов URL из заданных маршрутов и параметров, Yii предоставляет метод-помощник yii\helpers\Url::to(). Примеры:
use yii\helpers\Url;
// создает URL для маршрута: /index.php?r=post/index
echo Url::to(['post/index']);
// создает URL для маршрута с параметрами: /index.php?r=post/view&id=100
echo Url::to(['post/view', 'id' => 100]);
// создает якорный URL: /index.php?r=post/view&id=100#content
echo Url::to(['post/view', 'id' => 100, '#' => 'content']);
// создает абсолютный URL: http://www.example.com/index.php?r=post/index
echo Url::to(['post/index'], true);
// создает абсолютный URL с использованием схемы https: https://www.example.com/index.php?r=post/index
echo Url::to(['post/index'], 'https');
Обратите внимание, что в последнем примере подразумевается использование обычного формата URL. При использовании ЧПУ, будут созданы другие URL, соответствующие правилам создания URL.
Маршрут, переданный методу yii\helpers\Url::to(), является контекстно-зависимым. Он может быть относительным или абсолютным, в зависимости от следующих правил:
Начиная с версии 2.0.2, при составлении маршрутов, стало возможным использовать псевдонимы. В таком случае, псевдоним будет преобразован в маршрут, который будет использован для создания URL по правилам, указанным выше.
Для примера, будем считать, что текущим модулем является admin
, а текущим контроллером - post
,
use yii\helpers\Url;
// запрошенный маршрут: /index.php?r=admin/post/index
echo Url::to(['']);
// относительный маршрут с указанием только идентификатора действия: /index.php?r=admin/post/index
echo Url::to(['index']);
// относительный маршрут: /index.php?r=admin/post/index
echo Url::to(['post/index']);
// абсолютный маршрут: /index.php?r=post/index
echo Url::to(['/post/index']);
// /index.php?r=post/index псевдоним "@posts" определен как "/post/index"
echo Url::to(['@posts']);
В основе реализации метода yii\helpers\Url::to() лежит использование двух методов компонента URL manager: createUrl() и createAbsoluteUrl(). Ниже будут рассмотрены способы конфигурации URL manager для создания URL в различных форматах.
Метод yii\helpers\Url::to() также поддерживает создание URL, не связанных с маршрутами приложения. В данном случае, нужно передать в качестве первого параметра строку, а не массив. Например,
use yii\helpers\Url;
// запрошенный URL: /index.php?r=admin/post/index
echo Url::to();
// URL из псевдонима: http://example.com
Yii::setAlias('@example', 'http://example.com/');
echo Url::to('@example');
// абсолютный URL: http://example.com/images/logo.gif
echo Url::to('/images/logo.gif', true);
Кроме метода to()
, класс yii\helpers\Url предоставляет и другие удобные методы для создания URL. Например,
use yii\helpers\Url;
// домашний URL: /index.php?r=site/index
echo Url::home();
// базовый URL, удобно использовать в случае, когда приложение расположено в подкаталоге
// относительно корневого каталога веб-сервера
echo Url::base();
// канонический URL запрошенного URL
// подробнее https://support.google.com/webmasters/answer/139066?hl=ru
echo Url::canonical();
// запомнить запрошенный URL и восстановить его при следующих запросах
Url::remember();
echo Url::previous();
Для активации ЧПУ, необходимо настроить компонент urlManager
в конфигурации приложения следующим образом:
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => false,
'rules' => [
// ...
],
],
],
]
Свойство enablePrettyUrl является ключевым, активирует формат ЧПУ. Остальные свойства необязательные. Однако в примере выше показан самый популярный вариант конфигурации ЧПУ.
false
, вместо /index.php/post/100
, будет сгенерирован URL /post/100
.Примечание: Для того, чтобы скрыть имя входного скрипта в создаваемых URL, кроме установки значения свойства showScriptName в
false
, необходимо настроить веб-сервер, чтобы он мог правильно определять PHP-скрипт, который должен быть запущен, если в запрошенном URL он не указан явно. Рекомендованные настройки для Apache и Nginx описаны в разделе Установка Yii.
Правила URL - это экземпляр класса yii\web\UrlRule или класса, унаследованного от него. Каждое правило состоит из шаблона, используемого для поиска пути в запрошенном URL, маршрута и нескольких параметров запроса. Правило может быть использовано для разбора запроса в том случае, если шаблон правила совпадает с запрошенным URL. Правило может быть использовано для создания URL в том случае, если его маршрут и параметры запроса совпадают с заданными.
При включенном режиме ЧПУ, компонент URL manager использует правила URL, содержащиеся в его свойстве rules, для разбора входящих запросов и создания URL. Обычно, при разборе входящего запроса, URL manager проверяет все правила в порядке их следования, до первого правила, соответствующего запрошенному URL. Найденное правило используется для разбора URL на маршрут и параметры запроса. Аналогично для создания URL компонент URL manager ищет первое правило, соответствующее заданному маршруту и параметрам и использует его для создания URL.
Правила задаются ассоциативным массивом, где ключи определяют шаблоны, а значения соответствующие маршруты. Каждая пара шаблон-маршрут составляет правило разбора URL. Например, следующие правила определяют два правила разбора URL. Первое правило задает соответствие URL posts
маршруту post/index
. Второе правило задает соответствие URL, соответствующего регулярному выражению post/(\d+)
маршруту post/view
и параметру id
.
[
'posts' => 'post/index',
'post/<id:\d+>' => 'post/view',
]
Примечание: Шаблон правила используется для поиска соответствия с частью URL, определяющей путь. Например, в URL
/index.php/post/100?source=ad
путь определяет частьpost/100
(начальный и конечный слеши игнорируются), соответствующая регулярному выражениюpost/(\d+)
.
Правила URL можно определять не только в виде пар шаблон-маршрут, но и в виде массива. Каждый массив используется для определения одного правила. Такой вид определения правил используется в случаях, когда необходимо указать другие параметры правила URL. Например,
[
// ...другие правила URL...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.json',
],
]
По умолчанию, если в конфигурации правила URL не указан явно параметр class
, будет создано правило класса yii\web\UrlRule.
Правило URL может содержать несколько именованных параметров запроса, которые указываются в шаблоне в следующем формате: <ParamName:RegExp>
, где ParamName
определяет имя параметра, а RegExp
- необязательное регулярное выражение, используемое для определения значения параметра. В случае, если RegExp
не указан, значением параметра будет любая последовательность символов кроме слешей.
Примечание: Возможно указание только регулярного выражения для параметров. В таком случае остальная часть шаблона будет считаться простым текстом.
После разбора URL, параметры запроса, соответствующие шаблону правила, будут доступны в массиве $_GET
через компонент приложения request
.
При создании URL, значения указанных параметров будут вставлены в URL в соответствии с шаблоном правила.
Рассмотрим несколько примеров работы с именованными параметрами. Допустим, мы определили следующие три правила URL:
[
'posts/<year:\d{4}>/<category>' => 'post/index',
'posts' => 'post/index',
'post/<id:\d+>' => 'post/view',
]
При разборе следующих URL:
/index.php/posts
будет разобран в маршрут post/index
при помощи второго правила;/index.php/posts/2014/php
будет разобран на маршрут post/index
и параметры year
со значением 2014, category
со значением php
при помощи первого правила;/index.php/post/100
будет разобран на маршрут post/view
и параметр id
со значением 100 при помощи третьего правила;/index.php/posts/php
вызовет исключение yii\web\NotFoundHttpException, если yii\web\UrlManager::$enableStrictParsing имеет значение true
, так как правило для разбора данного URL отсутствует. Если yii\web\UrlManager::$enableStrictParsing имеет значение false
(по умолчанию), значение posts/php
будет возвращено в качестве маршрута.При создании URL:
Url::to(['post/index'])
создаст /index.php/posts
при помощи второго правила;Url::to(['post/index', 'year' => 2014, 'category' => 'php'])
создаст /index.php/posts/2014/php
при помощи первого правила;Url::to(['post/view', 'id' => 100])
создаст /index.php/post/100
при помощи третьего правила;Url::to(['post/view', 'id' => 100, 'source' => 'ad'])
создаст /index.php/post/100?source=ad
при помощи третьего правила.
Параметр source
не указан в правиле, поэтому он добавлен в созданный URL в качестве параметра запроса.Url::to(['post/index', 'category' => 'php'])
создаст /index.php/post/index?category=php
без использования правил. При отсутствии подходящего правила, URL будет создан простым соединением маршрута, как части пути, и параметров, как части запроса.В маршруте правила URL возможно указание имен параметров. Это позволяет использовать правило URL для обработки нескольких маршрутов. Например, следующие правила содержат параметры controller
и action
в маршрутах.
[
'<controller:(post|comment)>/<id:\d+>/<action:(create|update|delete)>' => '<controller>/<action>',
'<controller:(post|comment)>/<id:\d+>' => '<controller>/view',
'<controller:(post|comment)>s' => '<controller>/index',
]
Для разбора URL /index.php/comment/100/create
будет использовано первое правило, которое установит значения параметров controller
равным comment
и action
равным create
. Таким образом, маршрут <controller>/<action>
будет разрешен в comment/create
.
Аналогично, для маршрута comment/index
, при помощи третьего правила, будет создан URL comment/index
.
Примечание: Использование параметров в маршрутах позволяет значительно уменьшить количество правил URL и улучшить производительность компонента URL manager.
По умолчанию все параметры, указанные в правиле, являются обязательными. Если запрошенный URL не содержит обязательный параметр, или если URL создается без обязательного параметра, данное правило не будет применено. Свойство yii\web\UrlRule::$defaults позволяет сделать нужные параметры не обязательными. Параметры, перечисленные в данном свойстве, будут иметь заданные значения, в случае если они пропущены.
В следующем правиле описаны необязательные параметры page
и tag
, которые примут значения 1
и пустая строка
в случае, если они будут пропущены.
[
// ...другие правила...
[
'pattern' => 'posts/<page:\d+>/<tag>',
'route' => 'post/index',
'defaults' => ['page' => 1, 'tag' => ''],
],
]
Вышеприведенное правило может быть использовано для разбора или создания следующих URL:
/index.php/posts
: page
равно 1, tag
равно ''./index.php/posts/2
: page
равно 2, tag
равно ''./index.php/posts/2/news
: page
равно 2, tag
равно 'news'
./index.php/posts/news
: page
равно 1, tag
равно 'news'
.Без использования необязательных параметров понадобилось бы создать 4 правила для достижения того же результата.
Существует возможность включать имена серверов в шаблон правил URL. Главным образом, это удобно, когда требуется разное поведение приложения, в зависимости от разных имен веб-серверов. Например, следующее правило позволит разобрать URL http://admin.example.com/login
в маршрут admin/user/login
и http://www.example.com/login
в site/login
.
[
'http://admin.example.com/login' => 'admin/user/login',
'http://www.example.com/login' => 'site/login',
]
Также возможно комбинирование параметров и имени сервера для динамического извлечения данных из него. Например, следующее правило позволит разобрать URL http://en.example.com/posts
на маршрут и параметр language=en
.
[
'http://<language:\w+>.example.com/posts' => 'post/index',
]
Примечание: Правила, содержащие имя сервера, НЕ должны содержать в шаблоне подкаталог пути ко входному скрипту. Например, если приложение расположено в
http://www.example.com/sandbox/blog
, шаблон должен бытьhttp://www.example.com/posts
, вместоhttp://www.example.com/sandbox/blog/posts
. Это позволит изменять расположение приложения без необходимости внесения изменений в его код.
Компонент предоставляет возможность добавления к URL суффиксов. Например, можно добавить к URL .html
, чтобы они выглядели как статические HTML-страницы; можно добавить к URL суффикс .json
, для указания на ожидаемый тип данных ответа. Настроить суффиксы в URL можно при помощи соответствующего свойства yii\web\UrlManager::$suffix в конфигурации приложения:
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'suffix' => '.html',
'rules' => [
// ...
],
],
],
]
Данная конфигурация позволяет компоненту URL manager разбирать и создавать URL с суффиксом .html
.
Подсказка: При установке суффикса
/
, все URL будут заканчиваться слешем.
Примечание: При настроенном суффиксе, все URL не содержащие этот суффикс будут расценены как неизвестные URL. Такое поведение рекомендовано для SEO (поисковая оптимизация).
Иногда возникает необходимость использовать разные суффиксы для разных URL. Добиться этого можно настройкой свойства suffix у каждого правила. Когда это свойство установлено, оно имеет приоритет перед общей конфигурацией компонента URL manager. Например, следующая конфигурация содержит правило URL, которое использует .json
в качестве суффикса вместо глобального .html
.
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'suffix' => '.html',
'rules' => [
// ...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.json',
],
],
],
],
]
Начиная с версии 2.0.10 UrlManager может быть настроен на использование UrlNormalizer,
что позволяет справиться с вариациями одного и того же URL с присутствующим или отсутствующим слешем в конце.
Технически http://example.com/path
и http://example.com/path/
являются разными URL, отдача одинакового содержимого
в обоих вариантах может негативно повлиять на SEO. По умолчанию нормализатор заменяет повторяющиеся слеши на один и либо
убирает, либо добавляет завершающие слеши в зависимости от суффикса и производит редирект 301
на нормализованный URL. Нормализатор может быть настроен как глобально для менеджера URL, так и индивидуально для
каждого правила. По умолчанию все правила используют нормализатор, заданный в менеджере URL. Вы можете выставить
UrlRule::$normalizer в false
для отключения нормализации для конкретного правила.
Ниже преведён пример конфигурации UrlNormalizer:
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'suffix' => '.html',
'normalizer' => [
'class' => 'yii\web\UrlNormalizer',
'action' => UrlNormalizer::ACTION_REDIRECT_TEMPORARY, // используем временный редирект вместо постоянного
],
'rules' => [
// ...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '/',
'normalizer' => false, // отключаем нормализатор для этого правила
],
[
'pattern' => 'tags',
'route' => 'tag/index',
'normalizer' => [
'collapseSlashes' => false, // не убираем дублирующиеся слеши для этого правила
],
],
],
],
],
]
Примечание: По умолчанию UrlManager::$normalizer отключен. Чтобы использовать нормализацию, его необходимо сконфигурировать.
При реализации RESTful API, зачастую бывает необходимость в том, чтобы один и тот же URL был разобран в разные маршруты, в зависимости от HTTP-метода запроса. Это легко достигается указанием HTTP-методов, поддерживаемых правилом в начале шаблона. Если правило поддерживает несколько HTTP-методов, их имена разделяются запятыми. Например, следующие правила имеют шаблон post/<id:\d+>
с разными поддерживаемыми HTTP-методами. Запрос PUT post/100
будет разобран в маршрут post/create
, в то время, как запрос GET post/100
будер разобран в post/view
.
[
'PUT,POST post/<id:\d+>' => 'post/create',
'DELETE post/<id:\d+>' => 'post/delete',
'post/<id:\d+>' => 'post/view',
]
Примечание: Если правило URL содержит HTTP-метод в шаблоне, это правило будет использовано только при разборе URL. Такое правило не будет учитываться компонентом URL manager при создании URL.
Подсказка: Для упрощения маршрутизации RESTful API, Yii предоставляет специальный класс yii\rest\UrlRule, который достаточно эффективен и предоставляет такие удобные возможности, как автоматическое приведение идентификаторов контроллеров к множественной форме. Более подробную информацию можно найти в разделе Веб-сервисы REST Роутинг.
В предыдущих примерах, преимущественно, приводились правила URL, заданные парами шаблон-маршрут. Это самый распространенный, краткий формат. В некоторых случаях возникает необходимость более гибкой настройки правил, например указание суффикса при помощи свойства yii\web\UrlRule::$suffix. Пример конфигурации правила URL при помощи массива был рассмотрен в главе Суффиксы в URL:
[
// ...другие правила URL...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.json',
],
]
Информация: По умолчанию, если в конфигурации правила явно не задан параметр
class
, будет создано правило класса yii\web\UrlRule.
Правила URL могут быть динамически добавлены в компонент URL manager. Часто это необходимо подключаемым модулям для настройки своих правил URL. Для того чтобы динамически добавленные правила могли влиять на процесс роутинга, они должны быть добавлены в процессе предзагрузки. В частности, модули должны реализовываться интерфейс yii\base\BootstrapInterface и добавлять правила в методе bootstrap(), например:
public function bootstrap($app)
{
$app->getUrlManager()->addRules([
// правила URL описываются здесь
], false);
}
Также необходимо включить данный модуль в yii\web\Application::bootstrap(), чтобы он смог участвовать в процессе предзагрузки.
Несмотря на то, что встроенный класс yii\web\UrlRule достаточно функционален для большинства проектов, иногда возникает необходимость в создании своего класса правил URL. Например, на сайте продавца автомобилей существует необходимость поддержки URL в таком формате: /Manufacturer/Model
, где и Manufacturer
и Model
должны соответствовать данным, хранящимся в базе данных. Стандартный класс yii\web\UrlRule не подойдет, так как он рассчитан на работу со статичными шаблонами.
Для решения данной проблемы можно создать такой класс правила URL.
namespace app\components;
use yii\web\UrlRuleInterface;
use yii\base\BaseObject;
class CarUrlRule extends BaseObject implements UrlRuleInterface
{
public function createUrl($manager, $route, $params)
{
if ($route === 'car/index') {
if (isset($params['manufacturer'], $params['model'])) {
return $params['manufacturer'] . '/' . $params['model'];
} elseif (isset($params['manufacturer'])) {
return $params['manufacturer'];
}
}
return false; // данное правило не применимо
}
public function parseRequest($manager, $request)
{
$pathInfo = $request->getPathInfo();
if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {
// Ищем совпадения $matches[1] и $matches[3]
// с данными manufacturer и model в базе данных
// Если нашли, устанавливаем $params['manufacturer'] и/или $params['model']
// и возвращаем ['car/index', $params]
}
return false; // данное правило не применимо
}
}
И использовать новый класс yii\web\UrlManager::$rules при определении правил URL:
[
// ...другие правила...
[
'class' => 'app\components\CarUrlRule',
// ...настройка других параметров правила...
],
]
При разработке сложных веб-приложений, важно оптимизировать правила URL так, чтобы разбор запросов и создание URL занимали минимальное время.
Использование параметров в маршрутах позволяет уменьшить количество правил, что значительно увеличивает производительность.
При разборе или создании URL, компонент URL manager проверяет правила в порядке их определения. Поэтому следует более узконаправленные и/или часто используемые правила размещать раньше прочих.
В случае, если несколько правил имеют один и тот же префикс в шаблоне или маршруте, можно рассмотреть использование yii\web\GroupUrlRule, что позволит компоненту URL manager более эффективно обрабатывать правила группами. Часто это бывает полезно в случае, если приложение состоит из модулей, каждый из которых имеет свой набор правил с идентификатором модуля в качестве общего префикса.
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.