mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-05 07:44:05 +01:00
325 lines
18 KiB
Plaintext
325 lines
18 KiB
Plaintext
Контроллер
|
||
==========
|
||
`Контроллер (controller)` — это экземпляр класса [CController] или унаследованного
|
||
от него класса. Он создается объектом приложения в случае, когда пользователь его
|
||
запрашивает. При запуске контроллер выполняет соответствующее действие, что обычно
|
||
подразумевает создание соответствующих моделей и отображение необходимых представлений.
|
||
В самом простом случае `действие` — это метод класса контроллера, название
|
||
которого начинается на `action`.
|
||
|
||
У контроллера есть действие по умолчанию, которое выполняется в случае, когда
|
||
пользователь не указывает действие при запросе. По умолчанию это действие
|
||
называется `index`. Изменить его можно путём установки значения [CController::defaultAction].
|
||
|
||
Следующий код определяет контроллер `site` с действиями `index` (действие по
|
||
умолчанию) и `contact`:
|
||
|
||
~~~
|
||
[php]
|
||
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`
|
||
приведёт к вызову именно этих контроллера и действия.
|
||
|
||
> Note|Примечание: По умолчанию маршруты чувствительны к регистру.
|
||
>Это возможно изменить путём установки свойства
|
||
>[CUrlManager::caseSensitive] равным false в конфигурации приложения.
|
||
>В режиме, не чувствительном к регистру, убедитесь, что названия директорий,
|
||
>содержащих файлы классов контроллеров, указаны в нижнем регистре, а также,
|
||
>что [controller map|CWebApplication::controllerMap] и [action map|CController::actions]
|
||
>используют ключи в нижнем регистре.
|
||
|
||
Приложение может содержать [модули](/doc/guide/basics.module). Маршрут к действию
|
||
контроллера внутри модуля задаётся в формате `moduleID/controllerID/actionID`.
|
||
Более подробно это описано в [разделе о модулях](/doc/guide/basics.module).
|
||
|
||
Создание экземпляра контроллера
|
||
-------------------------------
|
||
Экземпляр контроллера создаётся, когда [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.
|
||
|
||
При использовании [модулей](/doc/guide/basics.module) процесс, описанный
|
||
выше, будет выглядеть несколько иначе. В частности, приложение проверит,
|
||
соответствует ли идентификатор контроллеру внутри модуля. Если соответствует, то
|
||
сначала будет создан экземпляр модуля, а затем экземпляр контроллера.
|
||
|
||
|
||
Действие
|
||
--------
|
||
Как было упомянуто выше, действие — это метод, имя которого начинается на `action`.
|
||
Более продвинутый способ — создать класс действия и указать контроллеру создавать
|
||
экземпляр этого класса при необходимости. Такой подход позволяет использовать
|
||
действия повторно.
|
||
|
||
|
||
Для создания класса действия необходимо выполнить следующее:
|
||
|
||
~~~
|
||
[php]
|
||
class UpdateAction extends CAction
|
||
{
|
||
public function run()
|
||
{
|
||
// некоторая логика действия
|
||
}
|
||
}
|
||
~~~
|
||
|
||
Чтобы контроллер знал об этом действии, необходимо переопределить метод
|
||
[actions()|CController::actions] в классе контроллера:
|
||
|
||
~~~
|
||
[php]
|
||
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` в контроллере нам придётся написать следующий скучный код:
|
||
|
||
~~~
|
||
[php]
|
||
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';
|
||
|
||
// … действительно полезная часть кода …
|
||
}
|
||
}
|
||
~~~
|
||
|
||
Используя параметры действий, мы можем получить более приятный код:
|
||
|
||
~~~
|
||
[php]
|
||
class PostController extends CController
|
||
{
|
||
public function actionCreate($category, $language='en')
|
||
{
|
||
$category=(int)$category;
|
||
|
||
// … действительно полезная часть кода …
|
||
}
|
||
}
|
||
~~~
|
||
|
||
Мы добавляем два параметра методу `actionCreate`. Имя каждого должно в точности
|
||
совпадать с одним из ключей в `$_GET`. Параметру `$language` задано значение
|
||
по умолчанию `en`, которое используется, если в запросе соответствующий параметр
|
||
отсутствует. Так как `$category` не имеет значения по умолчанию, в случае
|
||
отсутствия соответствующего параметра в запросе будет автоматически выброшено
|
||
исключение [CHttpException] (с кодом ошибки 400).
|
||
|
||
Начиная с версии 1.1.5, Yii поддерживает указание массивов в качестве параметров действий.
|
||
Использовать их можно следующим образом:
|
||
|
||
~~~
|
||
[php]
|
||
class PostController extends CController
|
||
{
|
||
public function actionCreate(array $categories)
|
||
{
|
||
// Yii приведёт $categories к массиву
|
||
}
|
||
}
|
||
~~~
|
||
|
||
Мы добавляем ключевое слово `array` перед параметром `$categories`.
|
||
В результате, если параметр `$_GET['categories']` является простой строкой, то он будет
|
||
приведён к массиву, содержащему исходную строку.
|
||
|
||
> Note|Примечание: Если параметр объявлен без указания типа `array`, то он должен
|
||
> быть скалярным (т.е. не массивом). В этом случае передача массива через
|
||
> `$_GET` параметр приведёт к исключению HTTP.
|
||
|
||
|
||
Начиная с версии 1.1.7, автоматическая привязка параметров работает и с
|
||
действиями, оформленными в виде классов. Если метод `run()` в классе действия
|
||
описать с параметрами, то эти параметры наполняются соответствующими значениями
|
||
из HTTP-запроса:
|
||
|
||
~~~
|
||
[php]
|
||
class UpdateAction extends CAction
|
||
{
|
||
public function run($id)
|
||
{
|
||
// $id будет заполнен значением из $_GET['id']
|
||
}
|
||
}
|
||
~~~
|
||
|
||
Фильтры
|
||
-------
|
||
Фильтр — это часть кода, которая может выполняться до или после
|
||
выполнения действия контроллера в зависимости от конфигурации. Например, фильтр
|
||
контроля доступа может проверять, аутентифицирован ли пользователь перед тем,
|
||
как будет выполнено запрошенное действие. Фильтр, контролирующий производительность,
|
||
может быть использован для определения времени, затраченного на выполнение действия.
|
||
|
||
Действие может иметь множество фильтров. Фильтры запускаются в том порядке, в котором
|
||
они указаны в списке фильтров, при этом фильтр может предотвратить выполнение
|
||
действия и следующих за ним фильтров.
|
||
|
||
Фильтр может быть определён как метод класса контроллера. Имя метода должно начинаться на `filter`.
|
||
Например, метод `filterAccessControl` определяет фильтр `accessControl`.
|
||
Метод фильтра должен выглядеть так:
|
||
|
||
~~~
|
||
[php]
|
||
public function filterAccessControl($filterChain)
|
||
{
|
||
// для выполнения последующих фильтров и выполнения действия вызовите метод $filterChain->run()
|
||
}
|
||
~~~
|
||
|
||
где `$filterChain` — экземпляр класса [CFilterChain], представляющего собой список
|
||
фильтров, ассоциированных с запрошенным действием. В коде фильтра можно вызвать
|
||
`$filterChain->run()` для того, чтобы продолжить выполнение последующих фильтров и действия.
|
||
|
||
Фильтр также может быть экземпляром класса [CFilter] или его производного.
|
||
Следующий код определяет новый класс фильтра:
|
||
|
||
~~~
|
||
[php]
|
||
class PerformanceFilter extends CFilter
|
||
{
|
||
protected function preFilter($filterChain)
|
||
{
|
||
// код, выполняемый до выполнения действия
|
||
return true; // false — для случая, когда действие не должно быть выполнено
|
||
}
|
||
|
||
protected function postFilter($filterChain)
|
||
{
|
||
// код, выполняемый после выполнения действия
|
||
}
|
||
}
|
||
~~~
|
||
|
||
Для того чтобы применить фильтр к действию, необходимо переопределить метод
|
||
`CController::filters()`, возвращающий массив конфигураций фильтров. Например:
|
||
|
||
~~~
|
||
[php]
|
||
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`. Если операторы `'+'` и `'-'` не указаны, фильтр будет
|
||
применён ко всем действиям. |