Files
yii/docs/guide/uk/topics.url.txt

297 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 3591 2012-02-17 21:44:32Z qiang.xue@gmail.com $</div>