Контроллер (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
.
Например, метод 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
. Если операторы '+'
и '-'
не указаны, фильтр будет
применён ко всем действиям.
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.