Контролер

Контролер (controller) — це екземпляр класу CController або успадкованого від нього класу. Він створюється обʼєктом додатку тоді, коли користувач робить відповідний запит. При запуску контролер виконує відповідну дію, що зазвичай передбачає створення відповідних моделей і рендеринг необхідних представлень. У найпростішому випадку дія — це метод класу контролера, назва якого починається на action.

У контролера є дія за замовчуванням, яка виконується у випадку, коли користувач не вказує дію при запиті. За замовчуванням ця дія називається index. Змінити її можна шляхом встановлення значення CController::defaultAction.

Наступний код визначає контролер site з діями index (за замовчуванням) та contact:

class SiteController extends CController
{
    public function actionIndex()
    {
        // ...
    }
 
    public function actionContact()
    {
        // ...
    }
}

1. Маршрут

Контролери та дії розпізнаються по їхнім ідентифікаторам. Ідентифікатор контролера — це запис формату 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. Більш детальніше це описано у розділі про модулі.

2. Створення екземпляра контролера

Екземпляр контролера створюється, коли 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.

У випадку використання модулів, процес, описаний вище, буде виглядати дещо інакше. Зокрема, додаток перевірить, чи відповідає ідентифікатор контролеру всередині модуля. Якщо відповідає — спочатку буде створений екземпляр модуля, потім екземпляр контролера.

3. Дія

Як було згадано вище, дія — це метод, імʼя якого починається на 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']
    }
}

4. Фільтри

Фільтр (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. Якщо оператори '+' і '-' не зазначені, фільтр буде застосований до всіх дій.

Be the first person to leave a comment

Please to leave your comment.