mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-15 14:50:56 +08:00
574 lines
48 KiB
Markdown
574 lines
48 KiB
Markdown
Разбор и генерация URL
|
||
============
|
||
|
||
При обработке запрошенного URL, Yii приложение первым делом разбирает URL в [маршрут](structure-controllers.md#marsruty). Полученный маршрут используется при создании
|
||
соответствующего экземпляра действия контроллера для обработки запроса. Этот процесс называется *роутинг*.
|
||
|
||
Обратный роутингу процесс называется *Создание URL*, он отвечает за создание URL из заданного маршрута и соответствующих параметров запроса. При необходимости, созданный URL всегда может быть преобразован в
|
||
первоначальные маршрут и параметры запроса.
|
||
|
||
В основе роутинга и создания URL лежит использование [[yii\web\UrlManager|URL manager]],
|
||
зарегистрированного в качестве [компонента приложения](structure-application-components.md) `urlManager`.
|
||
[[yii\web\UrlManager|URL manager]] содержит метод [[yii\web\UrlManager::parseRequest()|parseRequest()]]
|
||
для разбора входящего запроса на маршрут и параметры запроса, и метод [[yii\web\UrlManager::createUrl()|createUrl()]]
|
||
для создания URL из заданного маршрута и параметров запроса.
|
||
|
||
Настройка компонента `urlManager` в конфигурации приложения, позволяет приложению распознавать различные
|
||
форматы URL без внесения изменений в существующий код приложения. Например, для
|
||
создания URL для действия `post/view`, можно использовать следующий код:
|
||
|
||
```php
|
||
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 <span id="url-formats"></span>
|
||
|
||
[[yii\web\UrlManager|URL manager]] поддерживает два формата URL:
|
||
|
||
- Обычный.
|
||
- Человекопонятные URL.
|
||
|
||
Обычный формат URL использует параметр `r` для передачи маршрута и любые другие параметры для передачи остальных параметров запроса. Например, URL `/index.php?r=post/view&id=100` задает маршрут `post/view` и параметр `id`, равный 100. Данный формат не требует специальной конфигурации [[yii\web\UrlManager|URL manager]] и работает с любыми настройками Веб сервера.
|
||
|
||
Человекопонятный формат URL представляет собой дополнительный путь, следующий за именем входного скрипта, описывающий маршрут и остальные параметров запроса. Например, дополнительный путь в URL `/index.php/post/100` - это `/post/100`, который может представлять маршрут `post/view` и параметр `id` со значением равным 100, при наличии соответствующего [[yii\web\UrlManager::rules|правила]]. Для использования ЧПУ, необходимо создать набор правил, соответствующих требованиям к URL.
|
||
|
||
Переключение между двумя форматами URL осуществляется при помощи свойства [[yii\web\UrlManager::enablePrettyUrl|enablePrettyUrl]] компонента [[yii\web\UrlManager|URL manager]] без внесения изменений в код приложения.
|
||
|
||
## Роутинг <span id="routing"></span>
|
||
|
||
Роутинг осуществляется в два этапа:
|
||
|
||
- Входящий запрос разбирается в маршрут и параметры запроса.
|
||
- Для обработки запроса создается [действие контроллера](structure-controllers.md#actions), соответствующее полученному
|
||
маршруту.
|
||
|
||
При использовании простого формата URL, получение маршрута из запроса заключается в получении параметра `r` из массива `GET`.
|
||
|
||
При использовании ЧПУ, компонент [[yii\web\UrlManager|URL manager]] ищет среди зарегистрированных [[yii\web\UrlManager::rules|правил]] подходящее для разрешения запроса в маршрут.
|
||
Если такое правило не найдено, вызывается исключение [[yii\web\NotFoundHttpException]].
|
||
|
||
После того, как из запроса получен маршрут, самое время создать действие контроллера, соответствующее этому маршруту.
|
||
Маршрут разделяется на несколько частей, метками деления служат прямые слеши. Например, маршрут `site/index` будет разделен на `site` и `index`. Каждая из частей представляет собой *идентификатор*, который может ссылаться на модуль, контроллер или действие. Начиная с первой части маршрута, приложение следует следующему алгоритму для создания модуля (если есть), контроллера и действия:
|
||
|
||
1. Текущим модулем считаем приложение.
|
||
2. Проверяем, содержит ли [[yii\base\Module::controllerMap|карта контроллеров]] текущего модуля текущий *идентификатор*.
|
||
Если содержит, в соответствии с конфигурацией контроллера, найденной в карте, создаем объект контроллера и переходим в п. 5 для обработки оставшейся части маршрута.
|
||
3. Проверяем, есть ли модуль, соответствующий *идентификатору* в списке модулей (свойство [[yii\base\Module::modules|modules]]) текущего модуля. Если есть, в соответствии с конфигурацией модуля, найденной в списке модулей, создаем модуль и переходим в п. 2, считая только что созданный модуль текущим.
|
||
4. Рассматриваем *идентификатор* как [идентификатор контроллера](structure-controllers.md#id-kontrollerov) и создаем объект контроллера. Для оставшейся части маршрута выполняем п. 5.
|
||
5. Контроллер ищет текущий *идентификатор* в его [[yii\base\Controller::actions()|карте действий]]. В случае нахождения, контроллер создает действие, в соответствии с конфигурацией, найденной в карте. Иначе, контроллер пытается создать встроенное действие, описанное методом, соответствующим текущему [идентификатору действия](structure-controllers.md#id-dejstvij).
|
||
|
||
При возникновении ошибок на любом из описанных выше этапов, вызывается исключение [[yii\web\NotFoundHttpException]], указывающее на ошибку в процессе роутинга.
|
||
|
||
### Маршрут по умолчанию <span id="default-route"></span>
|
||
|
||
В случае, если в результате разбора запроса получен пустой маршрут, вместо него будет использован, так называемый, маршрут по умолчанию. Изначально, маршрут по умолчанию имеет значение `site/index`, и указывает на действие `index` контроллера `site`. Указать свое значение можно при помощи свойства приложения [[yii\web\Application::defaultRoute|defaultRoute]], например так:
|
||
|
||
```php
|
||
[
|
||
// ...
|
||
'defaultRoute' => 'main/index',
|
||
];
|
||
```
|
||
|
||
В добавок к маршруту по умолчанию приложения, существует маршрут по умолчанию модулей. Например, если у нас есть модуль
|
||
`user` и запрос разбирается в маршрут `user`, [[yii\base\Module::defaultRoute|defaultRoute]] модуля используется для
|
||
определения контроллера. По умолчанию имя контроллера —`default`. Если действие не задано в [[yii\base\Module::defaultRoute|defaultRoute]],
|
||
то для его определения используется свойство [[yii\base\Controller::defaultAction|defaultAction]] контроллера.
|
||
В данном примере полный маршрут будет `user/default/index`.
|
||
|
||
|
||
### Маршрут `catchAll` <span id="catchall-route"></span>
|
||
|
||
Иногда возникает необходимость временно перевести приложение в режим обслуживания и отображать одно информационное сообщение для всех запросов. Существует много вариантов реализации этой задачи. Но одним из самых простых, является использование свойства [[yii\web\Application::catchAll]], например так:
|
||
|
||
```php
|
||
[
|
||
// ...
|
||
'catchAll' => ['site/offline'],
|
||
];
|
||
```
|
||
|
||
В данном случае, действие `site/offline` будет обрабатывать все входящие запросы.
|
||
|
||
Свойство `catchAll` должно принимать массив, первый элемент которого определяет маршрут, а остальные элементы (пары ключ-значение) определяют параметры, [передаваемые действию](structure-controllers.md#parametry-dejstvij).
|
||
|
||
## Создание URL <span id="creating-urls"></span>
|
||
|
||
Для создания разных видов URL из заданных маршрутов и параметров, Yii предоставляет метод-помощник [[yii\helpers\Url::to()]]. Примеры:
|
||
|
||
```php
|
||
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, соответствующие [[yii\web\UrlManager::rules|правилам создания URL]].
|
||
|
||
Маршрут, переданный методу [[yii\helpers\Url::to()]], является контекстно зависимым. Он может быть *относительным* или *абсолютным*, в зависимости от следующих правил:
|
||
|
||
- Если маршрут является пустой строкой, будет использован текущий [[yii\web\Controller::route|маршрут]];
|
||
- Если маршрут не содержит слешей вообще, он рассматривается как *идентификатор* действия текущего контроллера и будет дополнен значением [[\yii\web\Controller::uniqueId|uniqueId]] текущего контроллера в качестве префикса;
|
||
- Если маршрут не содержит слеша в начале, он будет рассматриваться как маршрут относительно текущего модуля и будет дополнен значением [[\yii\base\Module::uniqueId|uniqueId]] текущего модуля, в качестве префикса.
|
||
|
||
Начиная с версии 2.0.2, при составлении маршрутов, стало возможным использовать [псевдонимы](concept-aliases.md). В таком случае, псевдоним будет преобразован в маршрут, который будет использован для создания URL по правилам, указанным выше.
|
||
|
||
Для примера, будем считать, что текущим модулем является `admin`, а текущим контроллером - `post`,
|
||
|
||
```php
|
||
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()]] лежит использование двух методов компонента [[yii\web\UrlManager|URL manager]]: [[yii\web\UrlManager::createUrl()|createUrl()]] и [[yii\web\UrlManager::createAbsoluteUrl()|createAbsoluteUrl()]]. Ниже будут рассмотрены способы конфигурации [[yii\web\UrlManager|URL manager]] для создания URL в различных форматах.
|
||
|
||
Метод [[yii\helpers\Url::to()]], так же, поддерживает создание URL не связанных с маршрутами приложения.
|
||
В данном случае, нужно передать в качестве первого параметра строку, а не массив. Например,
|
||
|
||
```php
|
||
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. Например,
|
||
|
||
```php
|
||
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();
|
||
```
|
||
|
||
## Использование человекопонятных URL <span id="using-pretty-urls"></span>
|
||
|
||
Для активации ЧПУ, необходимо настроить компонент `urlManager` в конфигурации приложения следующим образом:
|
||
|
||
```php
|
||
[
|
||
'components' => [
|
||
'urlManager' => [
|
||
'enablePrettyUrl' => true,
|
||
'showScriptName' => false,
|
||
'enableStrictParsing' => false,
|
||
'rules' => [
|
||
// ...
|
||
],
|
||
],
|
||
],
|
||
]
|
||
```
|
||
|
||
Свойство [[yii\web\UrlManager::enablePrettyUrl|enablePrettyUrl]] является ключевым, активирует формат ЧПУ.
|
||
Остальные свойства не обязательные. Однако, в примере выше, показан самый популярный вариант конфигурации ЧПУ.
|
||
|
||
* [[yii\web\UrlManager::showScriptName|showScriptName]]: это свойство определяет необходимость включения имени входного скрипта в создаваемый URL. Например, при его значении `false`, вместо `/index.php/post/100`, будет сгенерирован URL `/post/100`.
|
||
* [[yii\web\UrlManager::enableStrictParsing|enableStrictParsing]]: это свойство позволяет включить строгий разбор URL. Если строгий разбор URL включен, запрошенный URL должен соответствовать хотя бы одному из [[yii\web\UrlManager::rules|правил]], иначе будет вызвано исключение [[yii\web\NotFoundHttpException]]. Если строгий разбор URL отключен и ни одно из [[yii\web\UrlManager::rules|правил]] не подходит для разбора запрошенного URL, часть этого URL, представляющая путь, будет использована как маршрут.
|
||
* [[yii\web\UrlManager::rules|rules]]: это свойство содержит набор правил для разбора и создания URL. Это основное свойство, с которым нужно работать, что бы URL создавались в формате, соответствующем требованиям приложения.
|
||
|
||
> Note: Для того, чтобы скрыть имя входного скрипта в создаваемых URL, кроме установки значения свойства [[yii\web\UrlManager::showScriptName|showScriptName]] в `false`, необходимо настроить Веб сервер, чтобы он мог правильно определять PHP скрипт, который должен быть запущен, если в запрошенном URL он не указан явно. Рекомендованные настройки для Apache и Nginx описаны в разделе [Установка Yii](start-installation.md#rekomenduemye-nastrojki-apache).
|
||
|
||
### Правила URL <span id="url-rules"></span>
|
||
|
||
Правила URL - это экземпляр класса [[yii\web\UrlRule]] или класса, унаследованного от него. Каждое правило состоит из шаблона, используемого для поиска пути в запрошенном URL, маршрута и нескольких параметров запроса. Правило может быть использовано для разбора запроса в том случае, если шаблон правила совпадает с запрошенным URL. Правило может быть использовано для создания URL в том случае, если его маршрут и параметры запроса совпадают с заданными.
|
||
|
||
При включенном режиме ЧПУ, компонент [[yii\web\UrlManager|URL manager]] использует правила URL, содержащиеся в его свойстве [[yii\web\UrlManager::rules|rules]], для разбора входящих запросов и создания URL. Обычно, при разборе входящего запроса, [[yii\web\UrlManager|URL manager]] проверяет все правила в порядке их следования, до *первого* правила, соответствующего запрошенному URL. Найденное правило используется для разбора URL на маршрут и параметры запроса. Аналогично для создания URL компонент [[yii\web\UrlManager|URL manager]] ищет первое правило, соответствующее заданному маршруту и параметрам и использует его для создания URL.
|
||
|
||
[[yii\web\UrlManager::rules|Правила]] задаются ассоциативным массивом, где ключи определяют шаблоны, а значения соответствующие маршруты. Каждая пара шаблон-маршрут составляет правило разбора URL. Например, следующие [[yii\web\UrlManager::rules|правила]] определяют два правила разбора URL. Первое правило задает соответствие URL `posts` маршруту `post/index`. Второе правило задает соответствие URL, соответствующего регулярному выражению `post/(\d+)` маршруту `post/view` и параметру `id`.
|
||
|
||
```php
|
||
[
|
||
'posts' => 'post/index',
|
||
'post/<id:\d+>' => 'post/view',
|
||
]
|
||
```
|
||
> Note: Шаблон правила используется для поиска соответствия с частью URL, определяющей путь. Например, в URL `/index.php/post/100?source=ad` путь определяет часть `post/100` (начальный и конечный слеши игнорируются), соответствующая регулярному выражению `post/(\d+)`.
|
||
|
||
Правила URL можно определять не только в виде пар шаблон-маршрут, но и в виде массива. Каждый массив используется для определения одного правила. Такой вид определения правил используется в случаях, когда необходимо указать другие параметры правила URL. Например,
|
||
|
||
```php
|
||
[
|
||
// ...другие правила URL...
|
||
|
||
[
|
||
'pattern' => 'posts',
|
||
'route' => 'post/index',
|
||
'suffix' => '.json',
|
||
],
|
||
]
|
||
```
|
||
|
||
По умолчанию, если в конфигурации правила URL не указан явно параметр `class`, будет создано правило класса [[yii\web\UrlRule]].
|
||
|
||
|
||
### Именованные параметры <span id="named-parameters"></span>
|
||
|
||
Правило URL может содержать несколько именованных параметров запроса, которые указываются в шаблоне в следующем формате: `<ParamName:RegExp>`, где `ParamName` определяет имя параметра, а `RegExp` - необязательное регулярное выражение, используемое для определения значения параметра. В случае, если `RegExp` не указан, значением параметра будет любая последовательность символов кроме слешей.
|
||
|
||
> Note: Возможно указание только регулярного выражения для параметров. В таком случае, остальная часть шаблона будет считаться простым текстом.
|
||
|
||
После разбора URL, параметры запроса, соответствующие шаблону правила, будут доступны в массиве `$_GET` через компонент приложения `request`.
|
||
При создании URL, значения указанных параметров будут вставлены в URL в соответствии с шаблоном правила.
|
||
|
||
Рассмотрим несколько примеров работы с именованными параметрами. Допустим, мы определили следующие три правила URL:
|
||
|
||
```php
|
||
[
|
||
'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 будет создан простым соединением маршрута, как части пути, и параметров, как части запроса.
|
||
|
||
### Параметры в маршрутах <span id="parameterizing-routes"></span>
|
||
|
||
В маршруте правила URL возможно указание имен параметров. Это позволяет использовать правило URL для обработки нескольких маршрутов. Например, следующие правила содержат параметры `controller` и `action` в маршрутах.
|
||
|
||
```php
|
||
[
|
||
'<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`.
|
||
|
||
> Note: Использование параметров в маршрутах позволяет значительно уменьшить количество правил URL и улучшить производительность компонента [[yii\web\UrlManager|URL manager]].
|
||
|
||
По умолчанию, все параметры, указанные в правиле, являются обязательными. Если запрошенный URL не содержит обязательный параметр, или если URL создается без обязательного параметра, данное правило не будет применено. Свойство [[yii\web\UrlRule::defaults]] позволяет сделать нужные параметры не обязательными. Параметры, перечисленные в данном свойстве, будут иметь заданные значения, в случае если они пропущены.
|
||
|
||
В следующем правиле описаны необязательные параметры `page` и `tag`, которые примут значения `1` и `пустая строка` в случае, если они будут пропущены.
|
||
|
||
```php
|
||
[
|
||
// ...другие правила...
|
||
[
|
||
'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 правила для достижения того же результата.
|
||
|
||
|
||
### Правила с именами серверов <span id="rules-with-server-names"></span>
|
||
|
||
Существует возможность включать имена серверов в шаблон правил URL. Главным образом, это удобно, когда требуется разное поведение приложения, в зависимости от разных имен Веб серверов. Например, следующее правило позволит разобрать URL `http://admin.example.com/login` в маршрут `admin/user/login` и `http://www.example.com/login` в `site/login`.
|
||
|
||
```php
|
||
[
|
||
'http://admin.example.com/login' => 'admin/user/login',
|
||
'http://www.example.com/login' => 'site/login',
|
||
]
|
||
```
|
||
|
||
Также возможно комбинирование параметров и имени сервера для динамического извлечения данных из него. Например, следующее правило позволит разобрать URL `http://en.example.com/posts` на маршрут и параметр `language=en`.
|
||
|
||
```php
|
||
[
|
||
'http://<language:\w+>.example.com/posts' => 'post/index',
|
||
]
|
||
```
|
||
|
||
> Note: Правила, содержащие имя сервера, НЕ должны содержать в шаблоне подкаталог пути ко входному скрипту. Например, если приложение расположено в `http://www.example.com/sandbox/blog`, шаблон должен быть `http://www.example.com/posts`, вместо `http://www.example.com/sandbox/blog/posts`. Это позволит изменять расположение приложения без необходимости внесения изменений в его код.
|
||
|
||
### Суффиксы в URL <span id="url-suffixes"></span>
|
||
|
||
Компонент предоставляет возможность добавления к URL суффиксов. Например, можно добавить к URL `.html`, что бы они выглядели как статические HTML страницы; можно добавить к URL суффикс `.json`, для указания на ожидаемый тип данных ответа. Настроить суффиксы в URL можно при помощи соответствующего свойства [[yii\web\UrlManager::suffix]] в конфигурации приложения:
|
||
|
||
```php
|
||
[
|
||
'components' => [
|
||
'urlManager' => [
|
||
'enablePrettyUrl' => true,
|
||
'showScriptName' => false,
|
||
'enableStrictParsing' => true,
|
||
'suffix' => '.html',
|
||
'rules' => [
|
||
// ...
|
||
],
|
||
],
|
||
],
|
||
]
|
||
```
|
||
|
||
Данная конфигурация позволяет компоненту [[yii\web\UrlManager|URL manager]] разбирать и создавать URL с суффиксом `.html`.
|
||
|
||
> Tip: При установке суффикса `/`, все URL будут заканчиваться слешем.
|
||
|
||
> Note: При настроенном суффиксе, все URL не содержащие этот суффикс будут расценены как неизвестные URL. Такое поведение рекомендовано для SEO (поисковая оптимизация).
|
||
|
||
Иногда возникает необходимость использовать разные суффиксы для разных URL. Добиться этого можно настройкой свойства [[yii\web\UrlRule::suffix|suffix]] у каждого правила. Когда это свойство установлено, оно имеет приоритет перед общей конфигурацией компонента [[yii\web\UrlManager|URL manager]]. Например, cледующая конфигурация содержит правило URL, которое использует `.json` в качестве суффикса вместо глобального `.html`.
|
||
|
||
```php
|
||
[
|
||
'components' => [
|
||
'urlManager' => [
|
||
'enablePrettyUrl' => true,
|
||
'showScriptName' => false,
|
||
'enableStrictParsing' => true,
|
||
'suffix' => '.html',
|
||
'rules' => [
|
||
// ...
|
||
[
|
||
'pattern' => 'posts',
|
||
'route' => 'post/index',
|
||
'suffix' => '.json',
|
||
],
|
||
],
|
||
],
|
||
],
|
||
]
|
||
```
|
||
|
||
|
||
### Нормализация URL <span id="url-normalization"></span>
|
||
|
||
Начиная с версии 2.0.10 [[yii\web\UrlManager|UrlManager]] может быть настроен на использование [[yii\web\UrlNormalizer|UrlNormalizer]],
|
||
что позволяет справиться с вариациями одного и того же URL с присутствующим или отсутствующим слешем в конце.
|
||
Технически `http://example.com/path` и `http://example.com/path/` являются разными URL, отдача одинакового содержимого
|
||
в обоих вариантах может негативно повлиять на SEO. По умолчанию нормализатор заменяет повторяющиеся слеши на один и либо
|
||
убирает, либо добавляет завершающие слеши в зависимости от суффикса и производит [редирект 301](https://en.wikipedia.org/wiki/HTTP_301)
|
||
на нормализованный URL. Нормализатор может быть настроен как глобально для менеджера URL, так и индивидуально для
|
||
каждого правила. По умолчанию все правила используют нормализатор, заданный в менеджере URL. Вы можете выставить
|
||
[[yii\web\UrlRule::$normalizer|UrlRule::$normalizer]] в `false` для отключения нормализации для конкретного правила.
|
||
|
||
Ниже преведён пример конфигурации UrlNormalizer:
|
||
|
||
```php
|
||
[
|
||
'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, // не убираем дублирующиеся слеши для этого правила
|
||
],
|
||
],
|
||
],
|
||
],
|
||
],
|
||
]
|
||
```
|
||
|
||
> Note: по умолчанию [[yii\web\UrlManager::$normalizer|UrlManager::$normalizer]] отключен. Чтобы использовать
|
||
нормализацию его необходимо сконфигурировать.
|
||
|
||
### HTTP методы <span id="http-methods"></span>
|
||
|
||
При реализации RESTful API, зачастую бывает необходимость в том, чтобы один и тот же URL был разобран в разные маршруты, в зависимости от HTTP метода запроса. Это легко достигается указанием HTTP методов, поддерживаемых правилом в начале шаблона. Если правило поддерживает несколько HTTP методов, их имена разделяются запятыми. Например, следующие правила имеют шаблон `post/<id:\d+>` с разными поддерживаемыми HTTP методами. Запрос `PUT post/100` будет разобран в маршрут `post/create`, в то время, как запрос `GET post/100` будер разобран в `post/view`.
|
||
|
||
```php
|
||
[
|
||
'PUT,POST post/<id:\d+>' => 'post/create',
|
||
'DELETE post/<id:\d+>' => 'post/delete',
|
||
'post/<id:\d+>' => 'post/view',
|
||
]
|
||
```
|
||
|
||
> Note: Если правило URL содержит HTTP метод в шаблоне, это правило будет использовано только при разборе URL. Такое правило не будет учитываться компонентом [[yii\web\UrlManager|URL manager]] при создании URL.
|
||
|
||
> Tip: Для упрощения маршрутизации RESTful API, Yii предоставляет специальный класс [[yii\rest\UrlRule]], который достаточно эффективен и предоставляет такие удобные возможности, как автоматическое приведение идентификаторов контроллеров к множественной форме. Более подробную информацию можно найти в разделе Веб-сервисы REST [Роутинг](rest-routing.md).
|
||
|
||
|
||
### Гибкая настройка правил <span id="customizing-rules"></span>
|
||
|
||
В предыдущих примерах, преимущественно, приводились правила URL, заданные парами шаблон-маршрут. Это самый распространенный, краткий формат. В некоторых случаях возникает необходимость более гибкой настройки правил, например указание суффикса при помощи свойства [[yii\web\UrlRule::suffix]]. Пример конфигурации правила URL при помощи массива был рассмотрен в главе [Суффиксы в URL](#suffiksy-v-url):
|
||
|
||
```php
|
||
[
|
||
// ...другие правила URL...
|
||
|
||
[
|
||
'pattern' => 'posts',
|
||
'route' => 'post/index',
|
||
'suffix' => '.json',
|
||
],
|
||
]
|
||
```
|
||
|
||
> Info: По умолчанию, если в конфигурации правила явно незадан параметр `class`, будет создано правило класса [[yii\web\UrlRule]].
|
||
|
||
|
||
### Добавление правил URL динамически <span id="adding-rules"></span>
|
||
|
||
Правила URL могут быть динамически добавлены в компонент [[yii\web\UrlManager|URL manager]]. Часто это необходимо подключаемым [модулям](structure-modules.md) для настройки своих правил URL. Для того, что бы динамически добавленные правила могли влиять на процесс роутинга, они должны быть добавлены в процессе [предзагрузки](runtime-bootstrapping.md). В частности, модули должны реализовываться интерфейс [[yii\base\BootstrapInterface]] и добавлять правила в методе [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]], например:
|
||
|
||
```php
|
||
public function bootstrap($app)
|
||
{
|
||
$app->getUrlManager()->addRules([
|
||
// правила URL описываются здесь
|
||
], false);
|
||
}
|
||
```
|
||
|
||
Так же, необходимо включить данный модуль в [[yii\web\Application::bootstrap]], чтобы он смог участвовать в процессе [предзагрузки](runtime-bootstrapping.md).
|
||
|
||
|
||
### Создание классов правил <span id="creating-rules"></span>
|
||
|
||
Несмотря на то, что встроенный класс [[yii\web\UrlRule]] достаточно функционален для большинства проектов, иногда возникает необходимость в создании своего класса правил URL. Например, на сайте продавца автомобилей существует необходимость поддержки URL в таком формате: `/Manufacturer/Model`, где и `Manufacturer` и `Model` должны соответствовать данным, хранящимся в базе данных. Стандартный класс [[yii\web\UrlRule]] не подойдет, так как он рассчитан на работу со статичными шаблонами.
|
||
|
||
Для решения данной проблемы можно создать такой класс правила URL.
|
||
|
||
```php
|
||
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:
|
||
|
||
```php
|
||
[
|
||
// ...другие правила...
|
||
|
||
[
|
||
'class' => 'app\components\CarUrlRule',
|
||
// ...настройка других параметров правила...
|
||
],
|
||
]
|
||
```
|
||
|
||
## Производительность <span id="performance-consideration"></span>
|
||
|
||
При разработке сложных Веб приложений, важно оптимизировать правила URL так, чтобы разбор запросов и создание URL занимали минимальное время.
|
||
|
||
Использование параметров в маршрутах позволяет уменьшить количество правил, что значительно увеличивает производительность.
|
||
|
||
При разборе или создании URL, компонент [[yii\web\UrlManager|URL manager]] проверяет правила в порядке их определения. Поэтому следует более узконаправленные и/или часто используемые правила размещать раньше прочих.
|
||
|
||
В случае, если несколько правил имеют один и тот же префикс в шаблоне или маршруте, можно рассмотреть использование [[yii\web\GroupUrlRule]], что позволит компоненту [[yii\web\UrlManager|URL manager]] более эффективно обрабатывать правила группами. Часто это бывает полезно в случае, если приложение состоит из модулей, каждый из которых имеет свой набор правил с идентификатором модуля в качестве общего префикса.
|