Управління URL-адресами у веб-додатках включає у себе два аспекти:
У додатках на Yii ці завдання вирішуються з використанням класу CUrlManager.
Примітка: Ви можете не користуватися Yii для генерації URL, однак, так робити не рекомендується, тому що ви не зможете легко поміняти URL додатка через конфігурацію без зміни коду.
В принципі, адреси URL можна задати прямо в коді представлень контролера, проте куди зручніше створювати їх динамічно:
$url=$this->createUrl($route,$params);
де $this
відноситься до екземпляра контролера; $route
відповідає маршруту запиту, а $params
є списком параметрів GET
для додавання до URL.
За замовчуванням, адреси створюються за допомогою createUrl в get
-форматі. Наприклад, при значеннях параметрів $route='post/read'
і $params=array('id'=>100)
, отримаємо такий URL:
/index.php?r=post/read&id=100
де параметри зазначені у вигляді набору пар імʼя=значення
, зʼєднаних знаком &
, а параметр r
вказує на маршрут. Однак, цей формат не дуже дружелюбний по відношенню до користувача.
Підказка: Для того, щоб згенерувати 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 таким чином, щоб метод createUrl міг автоматично переключитися на використання нового формату, а додаток міг коректно сприймати новий формат адрес URL:
array(
…
'components'=>array(
…
'urlManager'=>array(
'urlFormat'=>'path',
),
),
);
Зверніть увагу, що вказувати клас компонента urlManager не потрібно, тому що він вже оголошений як CUrlManager в CWebApplication.
Підказка: Адреса URL, генерована методом createUrl є відносним. Для того, щоб отримати абсолютну адресу, потрібно додати префікс, використовуючи
Yii::app()->request->hostInfo
, або викликати метод createAbsoluteUrl.
Якщо у якості формата адреси URL використовується path
, то ми можемо визначити правила формування URL, щоб зробити адреси більш привабливими і зрозумілими з точки зору користувача. Наприклад, ми можемо використовувати коротку адресу /post/100
замість довгого варіанту /index.php/post/read/id/100
. CUrlManager використовує правила формування URL як для створення, так і для обробки адрес.
Правила формування URL задаються шляхом конфігурації властивості rules компонента додатку urlManager:
array(
…
'components'=>array(
…
'urlManager'=>array(
'urlFormat'=>'path',
'rules'=>array(
'pattern1'=>'route1',
'pattern2'=>'route2',
'pattern3'=>'route3',
),
),
),
);
Правила задаються у вигляді масиву пар шаблон-шлях, де кожна пара відповідає одному правилу. Шаблон правила - рядок, який повинен збігатися із шляхом в URL. Шлях правила повинен вказувати на існуючий шлях контролера.
Крім показаного вище способу завдання правил, можна описати правило із зазначенням додаткових параметрів:
'pattern1'=>array('route1', 'urlSuffix'=>'.xml', 'caseSensitive'=>false)
Починаючи з версії 1.1.7, можна використовувати показаний нижче формат. Тобто патерн вказується як елемент масиву, що дозволяє вказати кілька правил одного патерну:
array('route1', 'pattern'=>'pattern1', 'urlSuffix'=>'.xml', 'caseSensitive'=>false)
Тут масив містить список додаткових параметрів для правила. Можливо вказати наступні параметри:
pattern: патерн, який буде використаний при зіставленні і створенні URL. Дана можливість доступна з версії 1.1.7.
urlSuffix: суфікс URL, який використовується виключно для даного правила. За замовчуванням дорівнює null, що означає використання значення CUrlManager::urlSuffix.
caseSensitive: чи враховує правило регістр. За замовчуванням дорівнює null, що означає використання значення CUrlManager::caseSensitive.
defaultParams: GET-параметри за замовчуванням (імʼя=>значення
) для даного правила. При спрацьовуванні правила параметри будуть додані в $_GET
.
matchValue: чи повинні значення GET-параметрів при створенні URL збігатися з відповідними підвиразами в основному правилі. За замовчуванням дорівнює null, що означає використання значення CUrlManager::matchValue. При значенні параметра false
правило буде використано для створення URL тільки якщо імена параметрів збігаються з іменами в правилі. При значенні true
значення параметрів додатково повинні збігатися з підвиразами у правилі. Варто зазначити, що установка значення в true
знижує продуктивність.
verb: тип HTTP запиту (наприклад, GET
, POST
, DELETE
), для якого працює дане правило. За замовчуванням дорівнює null, що означає роботу правила з будь-якими HTTP запитами. Якщо необхідно вказати кілька типів запитів, їх треба розділити комами. У тому випадку, коли правило не збігається з поточним типом запиту, воно пропускається на етапі розбору запиту. Дана опція використовується тільки для розбору запиту і введена для підтримки URL у стилі REST. Дана можливість доступна з версії 1.1.7.
parsingOnly: чи використовувати правило тільки на етапі розбору запиту. За замовчуванням дорівнює false
, що означає, що правило використовується як для розбору запиту, так і для побудови URL. Дана можливість доступна з версії 1.1.7.
Правило може бути асоційоване з кількома GET-параметрами. Ці параметри вказуються у шаблоні правила у вигляді маркерів наступним чином:
<ParamName:ParamPattern>
де ParamName
відповідає імені GET-параметра, а необовʼязковий ParamPattern
- регулярному виразу, який використовується для перевірки відповідності значенню GET-параметра. Якщо ParamPattern
не зазначений, то параметр повинен відповідати будь-яким символам, крім слеша /
. У момент створення URL маркери будуть замінені на відповідні значення параметрів, а в момент обробки URL, відповідним GET-параметрами будуть присвоєні результати обробки.
Для наочності наведемо кілька прикладів. Припустимо, що наш набір правил складається з трьох правил:
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 для генерації адреси 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
).
Примітка: Використання правил URL знижує продуктивність додатку. Це відбувається з тієї причини, що у процесі парсинга запитаного URL CUrlManager намагається знайти відповідність кожного правила до тих пір, поки яке-небудь з правил не буде застосовано. Чим більше правил, тим більше втрати продуктивності. Тому у разі високонавантажених додатків використання правил URL варто мінімізувати.
Ми можемо використовувати іменовані параметри у маршруті правила. Таке правило може бути застосоване до декількох маршрутах, що збігаються з правилом. Це може допомогти зменшити число правил і, таким чином, підвищити продуктивність додатку.
Для того, щоб показати параметризацію маршрутів, використовуємо наступний набір правил:
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:
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.
Спочатку зконфігуруємо веб-сервер таким чином, щоб адреса URL без вказівки імені вхідного скрипта як і раніше передавався на обробку вхідного скрипта. Для сервера Apache HTTP server це досягається шляхом включення механізму перетворення 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 компонента
urlManager рівним false
.
Тепер, викликавши $this->createUrl('post/read',array('id'=>100))
, ми отримаємо URL /post/100
. Що важливо, ця адреса URL буде коректно розпізнана нашим веб-додатком.
На додаток до всього перерахованого вище, ми можемо додати до наших адрес URL закінчення. Наприклад, ми можемо отримати /post/100.html
замість /post/100
, представивши користувачеві начебто статичну сторінку. Для цього потрібно просто налаштувати компонент urlManager шляхом встановлення властивості urlSuffix будь-якого бажаного закінчення.
Примітка: дана можливість доступна з версії 1.1.8.
За замовчуванням кожне правило URL для CUrlManager представлено обʼєктом класу CUrlRule. Цей обʼєкт розбирає запити і створює URL по заданому правилу. Незважаючи на те, що CUrlRule досить гнучкий і підходить для роботи із більшістю форматів URL, іноді потрібні які-небудь особливі можливості.
Наприклад, для сайту з продажу автомобілів може знадобитися підтримувати URL виду /Виробник/Модель
, де і Виробник
і Модель
повинні відповідати даним з певної таблиці бази даних. У цьому випадку клас CUrlRule не підійде так як він, в основному, працює із статично описаними регулярними виразами, а не з базою даних.
У даному випадку можна реалізувати новий клас правила URL, успадкувавши CBaseUrlRule, і використовувати його в одному або декількох правилах. Для наведеного вище прикладу з продажу автомобілів підійдуть такі правила URL:
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
вигляду /Виробник/Модель
. Даний клас може бути реалізований наступним чином:
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:
Крім показаного вище типового використання, свій клас URL може стати у нагоді і в інших ситуаціях. Наприклад, можна реалізувати клас правила, який буде записувати у журнал адреси URL, що розбираються і створюються. Це може стати у нагоді на етапі розробки. Також можна реалізувати клас, який показує особливу сторінку помилки 404 у тому випадку, коли всі інші правила не спрацювали для адреси URL, що розбирається. Варто зазначити, що в цьому випадку правило з цим спеціальним класом повинно вказуватися останнім у списку.
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.