Kontrolyor ¶
Kontrolyor MVC arxitekturasining bir qismi hisoblanadi. Bu yii\base\Controller klassidan voris qilib yaratilgan klass obyektlaridir, ushbu obyektlar so'rovlarni (request) qayta ishlash va javoblarni (response) tayyorlash uchun mo'ljallangan. Ilova (application) so'rovlarni qayta ishlagandan so'ng, so'rovlarga mos kontrolyor obyektlarini yaratadi va bu obyektlar kiruvchi ma'lumotlarni tahlil qiladi hamda ushbu ma'lumotlarni modelga jo'natadi so'ng modeldan olingan natijalarni namoyish (view)ga joylashtiradi va oxirgi natijani hosil qiladi.
Amallar ¶
Kontrolyorlar amallar (action)dan tashkil topadi, amallar asosiy bloklar hisoblanib, foydalanuvchilar amallarga murojaat qilishi mumkin va ma'lum buyruqlar bajarilib natija hosil qilinadi hamda natija foydalanuvchiga qaytariladi. Bitta kontrolyorda bitta va undan ortiq amal bo'lishi mumkin.
Quyidagi misolda ikkita amaldan (view
va create
) tashkil topgan post
kontrolyori keltirilgan:
namespace app\controllers;
use Yii;
use app\models\Post;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
class PostController extends Controller
{
public function actionView($id)
{
$model = Post::findOne($id);
if ($model === null) {
throw new NotFoundHttpException;
}
return $this->render('view', [
'model' => $model,
]);
}
public function actionCreate()
{
$model = new Post;
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
}
В действии view
(определенном методом actionView()
), код сначала загружает модель
согласно запрошенному ID модели; Если модель успешно загружена, то код отобразит ее с помощью представления
под названием view
. В противном случае будет брошено исключение.
В действии create
(определенном методом actionCreate()
), код аналогичен. Он сначала пытается загрузить модель
с помощью данных из запроса и сохранить модель. Если все прошло успешно, то код перенаправляет браузер на действие view
с ID только
что созданной модели. В противном случае он отобразит представление create
, через которое пользователь может заполнить нужные данные.
Маршруты ¶
Конечные пользователи обращаются к действиям через так называемые маршруты. Маршрут это строка, состоящая из следующих частей:
- ID модуля: он существует, только если контроллер принадлежит не приложению, а модулю;
- ID контроллера: строка, которая уникально идентифицирует контроллер среди всех других контроллеров одного и того же приложения (или одного и того же модуля, если контроллер принадлежит модулю);
- ID действия: строка, которая уникально идентифицирует действие среди всех других действия одного и того же контроллера.
Маршруты могут иметь следующий формат:
ControllerID/ActionID
или следующий формат, если контроллер принадлежит модулю:
ModuleID/ControllerID/ActionID
Таким образом, если пользователь запрашивает URL http://hostname/index.php?r=site/index
, то index
действие в site
контроллере будет вызвано.
Секция Маршрутизация содержит более подробную информацию о том как маршруты сопоставляются с действиями.
Создание контроллеров ¶
В Веб приложениях, контроллеры должны быть унаследованы от yii\web\Controller или его потомков.
Аналогично для консольных приложений, контроллеры должны быть унаследованы от yii\console\Controller или
его потомков. Следующий код определяет site
контроллер:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
}
ID контроллеров ¶
Обычно контроллер сделан таким образом, что он должен обрабатывать запросы, связанные с определенным ресурсом.
Именно по этим причинам, ID контроллеров обычно являются существительные, ссылающиеся на ресурс, который они обрабатывают.
Например, вы можете использовать article
в качестве ID контроллера, которые отвечает за обработку данных статей.
По-умолчанию, ID контроллеров должны содержать только следующие символы: Английские буквы в нижнем регистре, цифры, подчеркивания,
тире и слэш. Например, оба article
и post-comment
являются допустимыми ID контроллеров, в то время как article?
, PostComment
,
admin\post
не являются таковыми.
ID контроллеров также могут содержать префикс подпапки. Например, в admin/article
часть article
является контроллером в
подпапке admin
в пространстве имен контроллеров.
Допустимыми символами для префиксов подпапок являются: Английские буквы в нижнем и верхнем регистре, символы подчеркивания и
слэш, где слэш используется в качестве разграничителя для многовложенных подпапок (например panels/admin
).
Правила наименования классов контроллеров ¶
Названия классов контроллеров могут быть получены из ID контроллеров следующими способами:
- Привести в верхний регистр первый символ в каждом слове, разделенном дефисами. Обратите внимание что, если ID контроллера содержит слэш, то данное правило распространяется только на часть после последнего слэша в ID контроллера;
- Убрать дефисы и заменить любой прямой слэш на обратный;
- Добавить суффикс
Controller
; - Добавить в начало пространство имен контроллеров.
Ниже приведены несколько примеров, с учетом того, что пространство имен контроллеров
имеет значение по умолчанию равное app\controllers
:
article
соответствуетapp\controllers\ArticleController
;post-comment
соответствуетapp\controllers\PostCommentController
;admin/post-comment
соответствуетapp\controllers\admin\PostCommentController
;adminPanels/post-comment
соответствуетapp\controllers\adminPanels\PostCommentController
.
Классы контроллеров должны быть автозагружаемыми. Именно по этой причине, в вышеприведенном примере,
контроллер article
должен быть сохранен в файл, псевдоним которого @app/controllers/ArticleController.php
;
в то время как контроллер admin/post-comment
должен находиться в файле @app/controllers/admin/PostCommentController.php
.
Информация: Последний пример
admin/post-comment
показывает каким образом вы можете расположить контроллер в подпапке пространства имен контроллеров. Это очень удобно, когда вы хотите организовать свои контроллеры в несколько категорий и не хотите использовать модули.
Карта контроллеров ¶
Вы можете сконфигурировать карту контроллеров для того, чтобы преодолеть описанные выше ограничения именования ID контроллеров и названий классов. В основном это очень удобно, когда вы используете сторонние контроллеры, именование которых вы не можете контролировать.
Вы можете сконфигурировать карту контроллеров в настройках приложения следующим образом:
[
'controllerMap' => [
[
// объявляет "account" контроллер, используя название класса
'account' => 'app\controllers\UserController',
// объявляет "article" контроллер, используя массив конфигурации
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
],
],
]
Контроллер по умолчанию ¶
Каждое приложение имеет контроллер по умолчанию, указанный через свойство yii\base\Application::$defaultRoute.
Когда в запросе не указан маршрут, тогда будет использован маршрут указанный в данном свойстве.
Для Веб приложений, это значение 'site'
, в то время как для консольных приложений,
это 'help'
. Таким образом, если задан URL http://hostname/index.php
, это означает, что контроллер site
выполнит обработку запроса.
Вы можете изменить контроллер по умолчанию следующим образом в настройках приложения:
[
'defaultRoute' => 'main',
]
Создание действий ¶
Создание действий не представляет сложностей также как и объявление так называемых методов действий в классе контроллера. Метод действия
это public метод, имя которого начинается со слова action
. Возвращаемое значение метода действия представляет собой ответные данные,
которые будут высланы конечному пользователю. Приведенный ниже код определяет два действия index
и hello-world
:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function actionIndex()
{
return $this->render('index');
}
public function actionHelloWorld()
{
return 'Hello World';
}
}
ID действий ¶
В основном действие разрабатывается для какой-либо конкретной обработки ресурса. По этой причине, ID действий в основном
являются глаголами, такими как view
, update
, и т. д.
По-умолчанию, ID действия должен содержать только следующие символы: Английские буквы в нижнем регистре, цифры,
подчеркивания и дефисы. Дефисы в ID действий используются для разделения слов. Например, view
, update2
, comment-post
являются
допустимыми ID действий, в то время как view?
, Update
не являются таковыми.
Вы можете создавать действия двумя способами: встроенные действия и отдельные действия. Встроенное действие является методом, определенным в классе контроллера, в то время как отдельное действие является экземпляром класса, унаследованного от yii\base\Action или его потомков. Встроенные действия требуют меньше усилий для создания и в основном используются если у вас нет надобности в повторном использовании действий. Отдельные действия, с другой стороны, в основном создаются для использования в различных контроллерах или при использовании в расширениях.
Встроенные действия ¶
Встроенные действия это те действия, которые определены в рамках методов контроллера, как мы это уже обсудили.
Названия методов действий могут быть получены из ID действий следующим образом:
- Привести первый символ каждого слова в ID действия в верхний регистр;
- Убрать дефисы;
- Добавить префикс
action
.
Например, index
соответствует actionIndex
, а hello-world
соответствует actionHelloWorld
.
Примечание: Названия имен действий являются регистрозависимыми. Если у вас есть метод
ActionIndex
, он не будет учтен как метод действия, таким образом, запрос к действиюindex
приведет к выбросу исключению. Также следует учесть, что методы действий должны иметь область видимости public. Методы имеющие область видимости private или protected НЕ определяют методы встроенных действий.
Встроенные действия в основном используются, потому что для их создания не нужного много усилий. Тем не менее, если вы планируете повторно использовать некоторые действия в различных местах, или если вы хотите перераспределить действия, вы должны определить его как отдельной действие.
Отдельные действия ¶
Отдельные действия определяются в качестве классов, унаследованных от yii\base\Action или его потомков. Например, в Yii релизах, присутствуют yii\web\ViewAction и yii\web\ErrorAction, оба из которых являются отдельными действиями.
Для использования отдельного действия, вы должны указать его в карте действий, с помощью переопределения метода yii\base\Controller::actions() в вашем классе контроллера, следующим образом:
public function actions()
{
return [
// объявляет "error" действие с помощью названия класса
'error' => 'yii\web\ErrorAction',
// объявляет "view" действие с помощью конфигурационного массива
'view' => [
'class' => 'yii\web\ViewAction',
'viewPrefix' => '',
],
];
}
Как вы можете видеть, метод actions()
должен вернуть массив, ключами которого являются ID действий, а значениями - соответствующие
названия класса действия или конфигурация. В отличие от встроенных действий, ID отдельных действий могут
содержать произвольные символы, до тех пор пока они определены в методе actions()
.
Для создания отдельного действия, вы должны наследоваться от класса yii\base\Action или его потомков, и реализовать
метод run()
с областью видимости public. Роль метода run()
аналогична другим методам действий. Например,
<?php
namespace app\components;
use yii\base\Action;
class HelloWorldAction extends Action
{
public function run()
{
return "Hello World";
}
}
Результаты действий ¶
Возвращаемое значение методов действий или метода run()
отдельного действия очень важно. Оно является результатом
выполнения соответствующего действия.
Возвращаемое значение может быть объектом response, который будет отослан конечному пользователю в качестве ответа.
- Для Веб приложений, возвращаемое значение также может быть произвольными данными, которые будут присвоены yii\web\Response::$data, а затем сконвертированы в строку, представляющую тело ответа.
- Для Консольных приложений, возвращаемое значение также может быть числом, представляющим статус выхода исполнения команды.
В вышеприведенных примерах, все результаты действий являются строками, которые будут использованы в качестве тела ответа, высланного пользователю. Следующий пример, показывает действие может перенаправить браузер пользователя на новый URL, с помощью возврата response объекта (т. к. redirect() метод возвращает response объект):
public function actionForward()
{
// перенаправляем браузер пользователя на http://example.com
return $this->redirect('http://example.com');
}
Параметры действий ¶
Методы действий для встроенных действий и методы run()
для отдельных действий могут принимать параметры,
называемые параметры действий. Их значения берутся из запросов. Для Веб приложений,
значение каждого из параметров действия берется из $_GET
, используя название параметра в качестве ключа;
для консольных приложений, они соответствуют аргументам командной строки.
В приведенном ниже примере, действие view
(встроенное действие) определяет два параметра: $id
и $version
.
namespace app\controllers;
use yii\web\Controller;
class PostController extends Controller
{
public function actionView($id, $version = null)
{
// ...
}
}
Для разных запросов параметры действий будут определены следующим образом:
http://hostname/index.php?r=post/view&id=123
: параметр$id
будет присвоено значение'123'
, в то время как$version
будет иметь значениеnull
, т. к. строка запроса не содержит параметраversion
;http://hostname/index.php?r=post/view&id=123&version=2
: параметрам$id
и$version
будут присвоены значения'123'
и'2'
соответственно;http://hostname/index.php?r=post/view
: будет брошено исключение yii\web\BadRequestHttpException, т. к. обязательный параметр$id
не был указан в запросе;http://hostname/index.php?r=post/view&id[]=123
: будет брошено исключение yii\web\BadRequestHttpException, т. к. параметр$id
получил неверное значение['123']
.
Если вы хотите, чтобы параметр действия принимал массив значений, вы должны использовать type-hint значение array
, как показано ниже:
public function actionView(array $id, $version = null)
{
// ...
}
Теперь, если запрос будет содержать URL http://hostname/index.php?r=post/view&id[]=123
, то параметр $id
примет значение
['123']
. Если запрос будет содержать URL http://hostname/index.php?r=post/view&id=123
, то параметр $id
все равно будет
содержать массив, т. к. скалярное значение '123'
будет автоматически сконвертировано в массив.
Вышеприведенные примеры в основном показывают как параметры действий работают для Веб приложений. Больше информации о параметрах консольных приложений представлено в секции Консольные команды.
Действие по умолчанию ¶
Каждый контроллер имеет действие, указанное через свойство yii\base\Controller::$defaultAction. Когда маршрут содержит только ID контроллера, то подразумевается, что действие контроллера по умолчанию было запрошено.
По-умолчанию, это действие имеет значение index
. Если вы хотите изменить это значение, просто переопределите данное
свойство в классе контроллера следующим образом:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $defaultAction = 'home';
public function actionHome()
{
return $this->render('home');
}
}
Жизненный цикл контроллера ¶
При обработке запроса, приложение создаст контроллер, основываясь на запрошенном маршруте. Для выполнения запроса, контроллер пройдет через следующие этапы жизненного цикла:
- Метод yii\base\Controller::init() будет вызван после того как контроллер будет создан и сконфигурирован;
- Контроллер создает объект действия, основываясь на запрошенном ID действия:
- Если ID действия не указан, то будет использовано ID действия по умолчанию;
- Если ID действия найдено в карте действий, то отдельное действие будет создано;
- Если ID действия соответствует методу действия, то встроенное действие будет создано;
- В противном случае, будет выброшено исключение yii\base\InvalidRouteException.
- Контроллер последовательно вызывает метод
beforeAction()
приложения, модуля (если контроллер принадлежит модулю) и самого контроллера.- Если один из методов вернул
false
, то остальные, не вызванные методыbeforeAction
будут пропущены, а выполнение действия будет отменено; - По-умолчанию, каждый вызов метода
beforeAction()
вызовет событиеbeforeAction
, на которое вы можете назначить обработчики.
- Если один из методов вернул
- Контроллер запускает действие:
- Параметры действия будут проанализированы и заполнены из данных запроса.
- Контроллер последовательно вызывает методы
afterAction
контроллера, модуля (если контроллер принадлежит модулю) и приложения.- По-умолчанию, каждый вызов метода
afterAction()
вызовет событиеafterAction
, на которое вы можете назначить обработчики.
- По-умолчанию, каждый вызов метода
- Приложение, получив результат выполнения действия, присвоит его объекту response.
Лучшие практики ¶
В хорошо организованных приложениях контроллеры обычно очень тонкие и содержат лишь несколько строк кода. Если ваш контроллер слишком сложный, то обычно это означает, что вам надо провести его рефакторинг и перенести часть кода в другие места.
В целом, контроллеры
- могут иметь доступ к данным запроса;
- могут вызывать методы моделей и других компонентов системы с данными запроса;
- могут использовать представления для формирования ответа;
- не должны заниматься обработкой данных, это должно происходить в слое моделей;
- должны избегать использования HTML или другой разметки, лучше это делать в представлениях.