Контролер (controller)
— це екземпляр класу CController або успадкованого від нього класу.
Він створюється обʼєктом додатку тоді, коли користувач робить відповідний запит.
При запуску контролер виконує відповідну дію, що зазвичай передбачає створення відповідних моделей
і рендеринг необхідних представлень.
У найпростішому випадку дія
— це метод класу контролера, назва якого починається на action
.
У контролера є дія за замовчуванням, яка виконується у випадку, коли користувач не вказує дію при запиті.
За замовчуванням ця дія називається index
.
Змінити її можна шляхом встановлення значення CController::defaultAction.
Наступний код визначає контролер site
з діями index
(за замовчуванням) та contact
:
class SiteController extends CController
{
public function actionIndex()
{
// ...
}
public function actionContact()
{
// ...
}
}
Контролери та дії розпізнаються по їхнім ідентифікаторам.
Ідентифікатор контролера — це запис формату path/to/xyz
, що відповідає
файлу класу контролера protected/controllers/path/to/XyzController.php
, де xyz
слід замінити реальною назвою класу (наприклад, post
відповідає
protected/controllers/PostController.php
). Ідентифікатор дії — це назва
методу без префікса action
. Наприклад, якщо клас контролера містить метод
actionEdit
, то ідентифікатор відповідної дії — edit
.
Користувач звертається до контролера та дії за допомогою маршруту (route).
Маршрут формується шляхом обʼєднання ідентифікаторів контролера та дії, відокремлених символом /
.
Наприклад, маршрут post/edit
вказує на дію edit
контролеру PostController
і,
за замовчуванням, URL http://hostname/index.php?r=post/edit
приведе до виклику саме цих контролера та дії.
Примітка: За замовчуванням маршрути чутливі до регістру. >Це можливо змінити шляхом встановлення властивості >CUrlManager::caseSensitive у конфігурації додатка рівною
false
. >У режимі нечутливому до регістру переконайтеся, що назви директорій, >які містять файли класів контролерів написані в нижньому регістрі, а також >що controller map та action map >використовують ключі в нижньому регістрі.
Додаток може містити модулі. Маршрут до дії
контролера всередині модуля задається у форматі moduleID/controllerID/actionID
.
Більш детальніше це описано у розділі про модулі.
Екземпляр контролера створюється, коли CWebApplication обробляє вхідний запит. Одержавши ідентифікатор контролера, додаток використовує наступні правила для визначення класу контролера та його місцерозташування:
якщо встановлена властивість CWebApplication::catchAllRequest, контролер буде створений на основі цієї властивості, а контролер, який запитує користувач, буде проігноровано. Як правило, це використовується для встановлення додатка в режим технічного обслуговування та відображення статичної сторінки з відповідним повідомленням;
якщо ідентифікатор контролера виявлений у CWebApplication::controllerMap, то для створення екземпляру контролера буде використана відповідна конфігурація контролера;
якщо ідентифікатор контролера відповідає формату 'path/to/xyz'
, то імʼя класу
контролера визначається як XyzController
, а відповідний клас як
protected/controllers/path/to/XyzController.php
.
Наприклад, ідентифікатор контролера admin/user
відповідатиме класу
контролера — Usercontroller
та файл protected/controllers/admin/UserController.php
.
Якщо файл класу не існує, буде викликане виключення CHttpException з кодом помилки 404.
У випадку використання модулів, процес, описаний вище, буде виглядати дещо інакше. Зокрема, додаток перевірить, чи відповідає ідентифікатор контролеру всередині модуля. Якщо відповідає — спочатку буде створений екземпляр модуля, потім екземпляр контролера.
Як було згадано вище, дія — це метод, імʼя якого починається на action
.
Ще один спосіб — створити клас дії та вказати контролеру створювати
екземпляр цього класу при необхідності. Такий підхід дозволяє використовувати
дії повторно.
Для створення класу дії необхідно виконати наступне:
class UpdateAction extends CAction
{
public function run()
{
// деяка логіка дії
}
}
Щоб контролер знав про цю дію, необхідно перевизначити метод actions() у класі контролера:
class PostController extends CController
{
public function actions()
{
return array(
'edit'=>'application.controllers.post.UpdateAction',
);
}
}
У наведеному коді ми використовуємо псевдонім маршруту application.controllers.post.UpdateAction
щоб вказати на файл класу дії protected/controllers/post/UpdateAction.php
.
Створюючи дії, засновані на класах, можна організувати додаток у модульному стилі.
Наприклад структура, директорій, приведена нижче, може бути використана для розташування коду контролерів:
protected/
controllers/
PostController.php
UserController.php
post/
CreateAction.php
ReadAction.php
UpdateAction.php
user/
CreateAction.php
ListAction.php
ProfileAction.php
UpdateAction.php
Починаючи з версії 1.1.4, в Yii зʼявилася підтримка автоматичної привʼязки
параметрів для дії контролера. Тобто можна задати іменовані параметри,
в які автоматично будуть потрапляти відповідні значення із $_GET
.
Для того, щоб показати, як це працює, припустимо, що нам потрібно
реалізувати дію create
контролера PostController
. Дія вимагає двох параметрів:
category
: ID категорії, у якій буде створюватись запис. Ціле число;language
: рядок, який містить код мови, яка буде використовуватися у запису.Скоріш за все у результаті для отримання параметрів із $_GET
у нас вийде
наведений нижче нудний код:
class PostController extends CController
{
public function actionCreate()
{
if(isset($_GET['category']))
$category=(int)$_GET['category'];
else
throw new CHttpException(404,'Невірний запит');
if(isset($_GET['language']))
$language=$_GET['language'];
else
$language='en';
// … дійсно корисна частина коду …
}
}
Тепер, використовуючи параметри дій, ми можемо отримати більш охайний код:
class PostController extends CController
{
public function actionCreate($category, $language='en')
{
$category=(int)$category;
// … дійсно корисна частина коду …
}
}
Ми додаємо два параметри методу actionCreate
. Імʼя кожного повинно в точності
співпадати з одним із ключів у $_GET
. Параметру $language
задано значення
за замовчуванням en
, яке використовується тоді, коли у запиті відповідний параметр
відсутній. Так як $category
не має значення за замовчуванням, у випадку
відсутності відповідного параметру у запиті буде автоматично викликане виключення
CHttpException (із кодом помилки 400).
Починаючи із версії 1.1.5, Yii підтримує масиви як параметри дій. Використовувати їх можна наступним чином:
class PostController extends CController
{
public function actionCreate(array $categories)
{
// Yii приведе $categories до масиву
}
}
Ми додаємо ключове слово array
перед параметром $categories
.
Після цього, якщо параметр $_GET['categories']
є простим рядком, то він буде
приведений до масиву, який міститиме вихідний рядок.
Примітка: Якщо параметр оголошений без вказівки типу
array
, то він повинен бути скалярним (тобто не масивом). У цьому випадку передача масива через$_GET
-параметр приведе до виключення HTTP.
Починаючи із версії 1.1.7, автоматична привʼязка параметрів працює і з
діями, оформленими як класи. Якщо метод run()
у класі дії
описати з параметрами, то ці параметри заповнюються відповідними значеннями
із HTTP-запиту:
class UpdateAction extends CAction
{
public function run($id)
{
// $id буде заповнений значенням із $_GET['id']
}
}
Фільтр (filter) – це частина коду, що може виконуватися до або після виконання дії контролера залежно від конфігурації. Наприклад, фільтр контролю доступу може перевіряти, чи аутентифікований користувач перед тим, як буде виконана запитана дія. Фільтр, що контролює продуктивність додатку, може бути використаний для визначення часу, витраченого на виконання дії.
Дія може мати безліч фільтрів. Фільтри запускаються в такому порядку, як вони зазначені в списку фільтрів, при цьому фільтр може запобігти виконанню дії і наступних за ним фільтрів.
Фільтр може бути визначений як метод класу контролера. Імʼя методу повинне починатися на filter
.
Наприклад, метод filterAccessControl
визначає фільтр accessControl
.
Метод фільтру оформлюється у такий спосіб:
public function filterAccessControl($filterchain)
{
// для виконання наступних фільтрів і виконання дії викличте метод $filterchain->run()
}
де $filterChain
— екземпляр класу CFilterChain, який являє собою список фільтрів,
асоційованих із запитаною дією. У коді фільтра можна викликати
$filterChain->run()
для того, щоб продовжити виконання наступних фільтрів і дії.
Фільтр також може бути екземпляром класу CFilter або похідного від нього. Наступний код визначає новий клас фільтра:
class PerformanceFilter extends CFilter
{
protected function preFilter($filterChain)
{
// код, виконуваний до виконання дії
return true; // false — для випадку, коли дія не повинна бути виконана
}
protected function postFilter($filterChain)
{
// код, виконуваний після виконання дії
}
}
Для того, щоб застосувати фільтр до дії, необхідно перевизначити метод
CController::filters()
, який повертає масив конфігурацій фільтрів. Наприклад:
class PostController extends CController
{
…
public function filters()
{
return array(
'postOnly + edit, create',
array(
'application.filters.PerformanceFilter - edit, create',
'unit'=>'second',
),
);
}
}
Даний код визначає два фільтри: postOnly
і PerformanceFilter
.
Фільтр postOnly
заданий як метод (відповідний метод уже визначений в
CController), в той час як PerformanceFilter
— фільтр на базі класу.
Псевдонім application.filters.PerformanceFilter
вказує на файл класу фільтра —
protected/filters/PerformanceFilter
. Для конфігурації PerformanceFilter
використаний масив, тому можливо ініціалізувати значення властивості фільтру.
У цьому випадку властивість unit
фільтра PerformanceFilter
буде
ініціалізовано значенням 'second'
.
Використовуючи оператори '+'
і '-'
можна вказати, до яких дій повинен чи
не повинен бути застосованим фільтр. У наведеному прикладі postOnly
повинен бути
застосований до дій edit
та create
, а PerformanceFilter
— до всіх дій,
окрім edit
і create
. Якщо оператори '+'
і '-'
не зазначені, фільтр буде
застосований до всіх дій.