Files
yii/docs/guide/ru/topics.url.txt
2012-05-09 16:25:38 +04:00

415 lines
26 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Управление URL
==============
Управление URL-адресами в веб-приложениях включает в себя два аспекта:
1. Приложению необходимо разобрать запрос пользователя, поступающий в виде URL,
на отдельные параметры.
2. Приложение должно предоставлять способ формирования адресов URL, с которыми
оно сможет корректно работать.
В приложениях на Yii эти задачи решаются с использованием класса [CUrlManager].
> Note|Примечание: Вы можете не пользоваться Yii для генерации URL, однако,
так делать не рекомендуется, потому как вы не сможете легко поменять URL
приложения через конфигурацию без изменения кода.
Создание адресов URL
--------------------
В принципе, адреса URL можно задать прямо в коде представлений контроллера,
однако куда удобнее создавать их динамически:
~~~
[php]
$url=$this->createUrl($route,$params);
~~~
где `$this` относится к экземпляру контроллера; `$route` соответствует [маршруту](/doc/guide/basics.controller#route) запроса,
а `$params` является списком параметров `GET` для добавления к URL.
По умолчанию, адреса создаются посредством [createUrl|CController::createUrl] в `get`-формате.
Например, при значениях параметров `$route='post/read'` и `$params=array('id'=>100)`, получим такой URL:
~~~
/index.php?r=post/read&id=100
~~~
где параметры указаны в виде набора пар `имя=значение`, соединенных знаком `&`, а
параметр `r` указывает на [маршрут](/doc/guide/basics.controller#route). Однако, этот формат не очень
дружелюбен по отношению к пользователю.
> Tip|Подсказка: Для того, чтобы сгенерировать URL с хештегом, к примеру,
`/index.php?r=post/read&id=100#title`, необходимо передать параметр `#`
следующим образом: `$this->createUrl('post/read',array('id'=>100,'#'=>'title'))`.
Мы можем сделать так, чтобы адрес, приведенный в качестве примера выше, выглядел более аккуратно и понятно
за счет использования формата `path`, который исключает использование
строки запроса и включает все GET-параметры в информационную часть адреса URL:
~~~
/index.php/post/read/id/100
~~~
Для изменения формата представления адреса URL, нужно настроить компонент приложения [urlManager|CWebApplication::urlManager]
таким образом, чтобы метод [createUrl|CController::createUrl] мог автоматически переключиться на использование нового формата, а
приложение могло корректно воспринимать новый формат адресов URL:
~~~
[php]
array(
'components'=>array(
'urlManager'=>array(
'urlFormat'=>'path',
),
),
);
~~~
Обратите внимание, что указывать класс компонента [urlManager|CWebApplication::urlManager] не требуется, т.к.
он уже объявлен как [CUrlManager] в [CWebApplication].
> Tip|Подсказка: Адрес URL, генерируемый методом [createUrl|CController::createUrl] является относительным. Для того, чтобы получить
абсолютный адрес, нужно добавить префикс, используя `Yii::app()->request->hostInfo`, или вызвать метод
[createAbsoluteUrl|CController::createAbsoluteUrl].
Человекопонятные URL
--------------------
Если в качестве формата адреса URL используется `path`, то мы можем определить правила формирования URL, чтобы
сделать адреса более привлекательными и понятными с точки зрения пользователя. Например, мы можем использовать
короткий адрес `/post/100` вместо длинного варианта `/index.php/post/read/id/100`. [CUrlManager] использует правила формирования URL
как для создания, так и для обработки адресов.
Правила формирования URL задаются путем конфигурации свойства [rules|CUrlManager::rules] компонента приложения
[urlManager|CWebApplication::urlManager]:
~~~
[php]
array(
'components'=>array(
'urlManager'=>array(
'urlFormat'=>'path',
'rules'=>array(
'pattern1'=>'route1',
'pattern2'=>'route2',
'pattern3'=>'route3',
),
),
),
);
~~~
Правила задаются в виде массива пар шаблон-путь, где каждая пара соответствует одному правилу.
Шаблон правила — строка, которая должна совпадать с путём в URL. Путь правила должен
указывать на существующий [путь контроллера](/doc/guide/basics.controller#route).
Кроме показанного выше способа задания правил, можно описать правило с указанием
дополнительных параметров:
~~~
[php]
'pattern1'=>array('route1', 'urlSuffix'=>'.xml', 'caseSensitive'=>false)
~~~
Начиная с версии 1.1.7, можно использовать показанный ниже формат. То есть
паттерн указывается как элемент массива, что позволяет указать несколько правил
одного паттерна:
~~~
[php]
array('route1', 'pattern'=>'pattern1', 'urlSuffix'=>'.xml', 'caseSensitive'=>false)
~~~
Здесь массив содержит список дополнительных параметров для правила. Возможно
указать следующие параметры:
- [pattern|CUrlRule::pattern]: паттерн, который будет использован при сопоставлении
и создании URL. Данная возможность доступна с версии 1.1.7.
- [urlSuffix|CUrlRule::urlSuffix]: суффикс URL, используемый исключительно для данного правила.
По умолчанию равен null, что означает использование значения [CUrlManager::urlSuffix].
- [caseSensitive|CUrlRule::caseSensitive]: учитывает ли правило регистр. По умолчанию параметр
равен null, что означает использование значения [CUrlManager::caseSensitive].
- [defaultParams|CUrlRule::defaultParams]: GET-параметры по умолчанию (`имя=>значение`) для данного правила.
При срабатывании правила параметры будут добавлены в `$_GET`.
- [matchValue|CUrlRule::matchValue]: должны ли значения GET-параметров при создании URL совпадать
с соответствующими подвыражениями в основном правиле. По умолчанию параметр равен null,
что означает использование значения [CUrlManager::matchValue]. При значении параметра false
правило будет использовано для создания URL только если имена параметров совпадают с именами в правиле.
При значении true значения параметров дополнительно должны совпадать с подвыражениями в правиле.
Стоит отметить, что установка значения в true снижает производительность.
- [verb|CUrlRule::verb]: тип HTTP запроса (например, `GET`, `POST`, `DELETE`),
для которого работает данное правило. По умолчанию равен null, что означает
работу правила с любыми HTTP запросами. Если необходимо указать несколько
типов запросов, их надо разделить запятыми. В том случае, когда правило не
совпадает с текущим типом запроса, оно пропускается на этапе разбора запроса.
Данная опция используется только для разбора запроса и введена для поддержки
URL в стиле REST. Данная возможность доступна с версии 1.1.7.
- [parsingOnly|CUrlRule::parsingOnly]: использовать ли правило только на
этапе разбора запроса. По умолчанию параметр равен false, что означает, что
правило используется как для разбора запроса, так и для построения URL.
Данная возможность доступна с версии 1.1.7.
Использование именованных параметров
------------------------------------
Правило может быть ассоциировано с несколькими GET-параметрами. Эти параметры
указываются в шаблоне правила в виде маркеров следующим образом:
~~~
<ParamName:ParamPattern>
~~~
где `ParamName` соответствует имени GET-параметра, а необязательный
`ParamPattern` — регулярному выражению, которое используется для проверки
соответствия значению GET-параметра. Если `ParamPattern` не указан, то
параметр должен соответствовать любым символам, кроме слэша `/`. В момент
создания URL маркеры будут заменены на соответствующие значения параметров,
а в момент обработки URL, соответствующим GET-параметрам будут
присвоены результаты обработки.
Для наглядности приведем несколько примеров. Предположим, что наш набор правил состоит из трех правил:
~~~
[php]
array(
'posts'=>'post/list',
'post/<id:\d+>'=>'post/read',
'post/<year:\d{4}>/<title>'=>'post/read',
)
~~~
- Вызов `$this->createUrl('post/list')` сгенерирует `/index.php/posts`. Здесь было применено первое правило.
- Вызов `$this->createUrl('post/read',array('id'=>100))` сгенерирует `/index.php/post/100`. Применено второе правило.
- Вызов `$this->createUrl('post/read',array('year'=>2008,'title'=>'a
sample post'))` сгенерирует `/index.php/post/2008/a%20sample%20post`.
Использовано третье правило.
- Вызов `$this->createUrl('post/read')` сгенерирует
`/index.php/post/read`. Ни одно из правил не было применено.
При использовании [createUrl|CController::createUrl] для генерации адреса URL, маршрут и GET-параметры, переданные
методу, используются для определения правила, которое нужно применить. Правило применяется в том случае, когда все параметры, ассоциированные с правилом,
присутствуют среди GET-параметров, а маршрут соответствует параметру маршрута.
Если же количество GET-параметров больше, чем требует правило, то лишние параметры
будут включены в строку запроса. Например, если вызвать `$this->createUrl('post/read',array('id'=>100,'year'=>2008))`,
мы получим `/index.php/post/100?year=2008`. Для того, чтобы лишние параметры были отражены в информационной части пути, необходимо
добавить к правилу `/*`. Таким образом, используя правило `post/<id:\d+>/*` получим URL вида `/index.php/post/100/year/2008`.
Как уже говорилось, вторая задача правил URL — разбирать URL-запросы. Этот процесс обратный процессу создания URL.
Например, когда пользователь запрашивает `/index.php/post/100`, применяется второе правило из примера выше и запрос
преобразовывается в маршрут `post/read` и GET-параметр `array('id'=>100)` (доступный через `$_GET`).
> Note|Примечание: Использование правил URL снижает производительность приложения.
Это происходит по той причине, что в процессе парсинга запрошенного URL
[CUrlManager] пытается найти соответствие каждому правилу до тех пор, пока
какое-нибудь из правил не будет применено. Чем больше правил, тем больший урон
производительности. Поэтому в случае высоконагруженных приложений использование
правил URL стоит минимизировать.
Параметризация маршрутов
------------------------
Мы можем использовать именованные параметры
в маршруте правила. Такое правило может быть применено к нескольким маршрутам,
совпадающим с правилом. Это может помочь уменьшить число правил и, таким образом,
повысить производительность приложения.
Для того, чтобы показать параметризацию маршрутов, используем следующий набор правил:
~~~
[php]
array(
'<_c:(post|comment)>/<id:\d+>/<_a:(create|update|delete)>' => '<_c>/<_a>',
'<_c:(post|comment)>/<id:\d+>' => '<_c>/read',
'<_c:(post|comment)>s' => '<_c>/list',
)
~~~
Мы использовали два именованных параметра в маршруте правил: `_c` и `_a`.
Первый соответствует названию контроллера и может быть равен `post` или `comment`,
второй — названию action-а и может принимать значения `create`, `update` или `delete`.
Вы можете называть параметры по-другому, если их имена не конфликтуют с GET-параметрами,
которые могут использоваться в URL.
При использовании правил, приведённых выше, URL `/index.php/post/123/create`
будет обработано как маршрут `post/create` с GET-параметром `id=123`.
По маршруту `comment/list` с GET-параметром `page=2`, мы можем создать URL
`/index.php/comments?page=2`.
Параметризация имён хостов
--------------------------
Также возможно использовать имена хостов в правилах для разбора и
создания URL. Можно выделять часть имени хоста в GET-параметр.
Например, URL `http://admin.example.com/en/profile` может быть разобран в
GET-параметры `user=admin` и `lang=en`. С другой стороны, правила с именами
хостов могут также использоваться для создания URL адресов.
Чтобы использовать параметризованные имена хостов, включите имя хоста в правила URL:
~~~
[php]
array(
'http://<user:\w+>.example.com/<lang:\w+>/profile' => 'user/profile',
)
~~~
Пример выше говорит, что первый сегмент имени хоста должен стать
параметром `user`, а первый сегмент пути — параметром `lang`. Правило
соответствует маршруту `user/profile`.
Помните, что [CUrlManager::showScriptName] не работает при создании URL
адреса с использованием правил с параметризованным именем хоста.
Стоит отметить, что правило с параметризованным именем хоста не должно
содержать поддиректорий в том случае, если приложение находится в поддиректории
корня вебсервера. К примеру, если приложение располагается по адресу
`http://www.example.com/sandbox/blog`, мы должны использовать точно такое же
правило URL, как описано выше. Без поддиректории: `sandbox/blog`.
Скрываем `index.php`
--------------------
С целью сделать адрес URL еще более привлекательным можно спрятать имя входного скрипта `index.php`. Для этого необходимо настроить
веб-сервер и компонент приложения [urlManager|CWebApplication::urlManager].
Вначале сконфигурируем веб-сервер таким образом, чтобы адрес URL без указания имени входного скрипта по-прежнему
передавался на обработку входному скрипту. Для сервера [Apache HTTP server](http://httpd.apache.org/) это достигается
путем включения механизма преобразования URL и заданием нескольких правил. Для этого
необходимо создать файл `/wwwroot/blog/.htaccess`, содержащий правила, приведённые ниже.
Те же правила могут быть размещены в файле конфигурации Apache
в секции `Directory` для `/wwwroot/blog`.
~~~
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
~~~
Далее нужно установить свойство [showScriptName|CUrlManager::showScriptName] компонента
[urlManager|CWebApplication::urlManager] равным `false`.
Теперь, вызвав `$this->createUrl('post/read',array('id'=>100))`, мы получим URL `/post/100`. Что важно, этот
адрес URL будет корректно распознан нашим веб-приложением.
Подмена окончания в адресе URL
------------------------------
В дополнение ко всему перечисленному выше, мы можем добавить к нашим адресам URL окончание. Например,
мы можем получить `/post/100.html` вместо `/post/100`, представив пользователю как будто бы статичную страничку.
Для этого нужно просто настроить компонент [urlManager|CWebApplication::urlManager] путем назначения свойству
[urlSuffix|CUrlManager::urlSuffix] любого желаемого окончания.
Использование своего класса правила URL
---------------------------------------
> Note|Примечание: данная возможность доступна с версии 1.1.8.
По умолчанию каждое правило URL для [CUrlManager] представлено объектом
класса [CUrlRule]. Этот объект разбирает запросы и создаёт URL по заданному правилу.
Несмотря на то, что [CUrlRule] достаточно гибок и подходит для работы с большинством
форматов URL, иногда требуются какие-либо особенные возможности.
К примеру, для сайта по продаже автомобилей может потребоваться поддерживать URL
вида `/Производитель/Модель`, где и `Производитель` и `Модель` должны соответствовать
данным из определённой таблицы базы данных. В этом случае класс [CUrlRule] не
подойдёт так как он, в основном, работает с статически описанными регулярными
выражениями, а не с базой данных.
В данном случае можно реализовать новый класс правила URL, унаследовав [CBaseUrlRule],
и использовать его в одном или нескольких правилах. Для приведённого выше примера
с продажей автомобилей подойдут следующие правила URL:
~~~
[php]
array(
// стандартное правило для обработки '/' как 'site/index'
'' => 'site/index',
// стандартное правило для обработки '/login' как 'site/login' и т.д.
'<action:(login|logout|about)>' => 'site/<action>',
// своё правило для URL вида '/Производитель/Модель'
array(
'class' => 'application.components.CarUrlRule',
'connectionID' => 'db',
),
// стандартное правило для обработки 'post/update' и др.
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
),
~~~
Выше мы использовали свой класс правила URL `CarUrlRule` для обработки URL
вида `/Производитель/Модель`. Данный класс может быть реализован следующим образом:
~~~
[php]
class CarUrlRule extends CBaseUrlRule
{
public $connectionID = 'db';
public function createUrl($manager,$route,$params,$ampersand)
{
if ($route==='car/index')
{
if (isset($params['manufacturer'], $params['model']))
return $params['manufacturer'] . '/' . $params['model'];
else if (isset($params['manufacturer']))
return $params['manufacturer'];
}
return false; // не применяем данное правило
}
public function parseUrl($manager,$request,$pathInfo,$rawPathInfo)
{
if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches))
{
// Проверяем $matches[1] и $matches[3] на предмет
// соответствия производителю и модели в БД.
// Если соответствуют, выставляем $_GET['manufacturer'] и/или $_GET['model']
// и возвращаем строку с маршрутом 'car/index'.
}
return false; // не применяем данное правило
}
}
~~~
Свой класс правила URL должен реализовать два абстрактных метода, объявленных в
[CBaseUrlRule]:
* [createUrl()|CBaseUrlRule::createUrl()]
* [parseUrl()|CBaseUrlRule::parseUrl()]
Кроме показанного выше типичного использования, свой класс URL может пригодиться
и в других ситуациях. Например, можно реализовать класс правила, который будет
записывать в журнал разбираемые и создаваемые URL. Это может пригодиться на
этапе разработки. Также можно реализовать класс, который показывает особую страницу
ошибки 404 в том случае, когда все остальные правила для разбираемого URL не сработали.
Стоит отметить, что в этом случае правило с этим специальным классом должно
указываться последним в списке.
<div class="revision">$Id: topics.url.txt 3329 2011-06-28 08:31:35Z mdomba $</div>