0 follower

Контроллер

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

У контроллера есть действие по умолчанию, которое выполняется в случае, когда пользователь не указывает действие при запросе. По умолчанию это действие называется index. Изменить его можно путем установки значения CController::defaultAction.

Ниже приведен минимальный код класса контроллера. Поскольку этот контроллер не определяет ни одного действия, обращение к нему приведет к вызову исключения.

class SiteController extends CController
{
}

1. Маршрут

Контроллеры и действия опознаются по их идентификаторам. Идентификатор контроллера — это запись формата path/to/xyz, соответствующая файлу класса контроллера protected/controllers/path/to/XyzController.php, где xyz следует заменить реальным названием класса (например, post соответствует protected/controllers/PostController.php). Идентификатор действия - это название метода без префикса action. Например, если класс контроллера содержит метод actionEdit, то идентификатор соответствующего действия - edit.

Примечание: До версии 1.0.3 идентификатор контроллера указывался как path.to.xyz вместо path/to/xyz.

Пользователь обращается к контроллеру и действию посредством маршрута (route). Маршрут формируется путем объединения идентификаторов контроллера и действия, отделенных косой чертой. Например, маршрут post/edit указывает на действие edit контроллера PostController и, по умолчанию, URL http://hostname/index.php?r=post/edit приведет к вызову именно этих контроллера и действия.

Примечание: По умолчанию маршруты чувствительны к регистру. Начиная с версии 1.0.1 это возможно изменить путем установки свойства CUrlManager::caseSensitive в конфигурации приложения равным false. В режиме нечувствительном к регистру убедитесь, что названия директорий, содержащих файлы классов контроллеров написаны в нижнем регистре, а также что controller map и action map используют ключи в нижнем регистре.

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.

В случае использование модулей (доступны, начиная с версии 1.0.3), процесс описанный выше будет выглядеть несколько иначе. В частности, приложение проверит, если идентификатор соответствует контроллеру внутри модуля. В случае, если это имеет место, будет создан экземпляр модуля вместе с экземпляром контроллера.

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

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. Если операторы '+' и '-' не указаны, фильтр будет применен ко всем действиям.