Контролери ¶
Контролери є частиною архітектури MVC. Це об’єкти класів, успадкованих від yii\base\Controller та відповідають за обробку запитів і генерування відповідей. Зокрема, після отримання контролю від додатків, контролери проаналізують вхідні дані, передадуть їх у моделі, додадуть результати моделі у представлення, і на сам кінець згенерують вихідні відповіді.
Дії ¶
Контролери складаються з дій, які є основними блоками, до яких може звертатись кінцевий користувач і запитувати виконання того або іншого функціоналу. В контролері може бути одна або декілька дій.
Наступний приклад показує контролер post
з двома діями: view
та create
:
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()
) код спочатку завантажує модель,
відповідно до запитуваного ідентифікатора моделі; Якщо модель успішно завантажена, то код відобразить її за допомогою
представлення, під назвою view
. В іншому випадку - буде отримане виключення.
У дії create
(визначеній методом actionCreate()
) подібний код. Він спочатку намагається завантажити
модель за допомогою даних із запиту і зберегти модель. Якщо все пройшло успішно,
то код перенаправить браузер на дію view
із ідентифікатором щойно створеної моделі. В іншому випадку - він відобразить
представлення create
, через яке користувач зможе вказати необхідні дані.
Маршрути ¶
Кінцеві користувачі звертаються до дій з допомогою так названих маршрутів. Маршрут це текстовий рядок, який складається з наступних частин:
- ідентифікатор модуля: він існує, тільки якщо контролер належить не додатку, а модулю;
- ідентифікатор контролера: текстовий рядок, який унікально ідентифікує контролер серед всіх інших контролерів одного і того ж додатка (або одного й того ж модуля, якщо контролер належить модулю);
- ідентифікатор дії: текстовий рядок, який унікально ідентифікує дію серед всіх інших дій одного й того ж контролера.
Маршрути можуть мати наступний формат:
ControllerID/ActionID
або наступний формат, якщо контролер належить модулю:
ModuleID/ControllerID/ActionID
Таким чином, якщо користувач звертається до URL http://hostname/index.php?r=site/index
, то буде викликано дію index
у контролері site
. Розділ Маршрутизація та створення URL містить більш детальну інформацію
про те, як маршрути співвідносяться із діями.
Створення контролерів ¶
У веб-додатках контролери повинні бути успадкованими від класу yii\web\Controller
або його нащадків. Аналогічно для консольних додатків, контролери повинні бути
успадкованими від класу yii\console\Controller або його нащадків. Наступний код визначає контролер site
:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
}
Ідентифікатори контролерів ¶
Зазвичай контролер зроблений таким чином, що він повинен обробляти запити, які пов’язані з певним ресурсом.
Саме з цієї причини, ідентифікатори контролерів зазвичай є іменниками, які посилаються на ресурс, який вони обробляють.
Наприклад, ви можете використовувати article
в якості ідентифікатора контролера, який відповідає за обробку даних статей.
За замовчуванням, ідентифікатори контролерів мають містити тільки наступні символи: англійські букви в нижньому регістрі, цифри,
підкреслення, тире і слеш. Наприклад, обидва ідентифікатори контролера article
та post-comment
є прийнятними, в той час,
як article?
, PostComment
, admin\post
не є такими.
Ідентифікатор контролера також може містити префікс під-директорії. Наприклад, у admin/article
частина article
відповідає
контролеру в під-директорії admin
простору імен контролера.
Допустимими символами для префіксів під-директорій є: англійські букви в нижньому і верхньому регістрах, цифри, символи підкреслення і
слеш, де слеш використовується в якості роздільника для багаторівневих під-директорій (наприклад, panels/admin
).
Іменування класів контролерів ¶
Назви класів контролерів можуть бути отримані із ідентифікаторів контролерів наступним чином:
- Привести у верхній регістр перший символ в кожному слові, розділеному дефісами. Зверніть увагу, що, якщо ідентифікатор контролера містить слеш, то дане правило поширюється тільки на частину після останнього слеша в ідентифікаторі контролера.
- Прибрати дефіси і замінити будь-який прямий слеш на зворотний.
- Додати суфікс
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
.
Info: Останній приклад
admin/post-comment
показує яким чином ви можете розташувати контролер в під-директорії простору імен контролера. Це дуже зручно, коли ви хочете організувати свої контролери у декілька категорій і не хочете використовувати модулі.
Мапа контролерів ¶
Ви можете налаштувати мапу контролерів для того, щоб подолати описані вище обмеження іменування ідентифікаторів контролерів і назв класів. В основному, це дуже зручно, коли ви використовуєте сторонні контролери, іменування яких ви не можете контролювати.
Ви можете налаштувати мапу контролерів в налаштуваннях додатка наступним чином:
[
'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',
]
Створення дій ¶
Створення дій може бути настільки ж простим, як і оголошення так званих методів дій у класі контролера. Метод дії це
публічний метод, ім’я якого починається зі слова 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';
}
}
Ідентифікатори дій ¶
Частіше за все, дія розробляється для певної маніпуляції над ресурсом. З цієї причини ідентифікатори дій, в основному,
є дієсловами, такими як view
, update
, і т. д.
За замовчуванням, ідентифікатори дій повинні містити тільки такі символи: англійські букви в нижньому регістрі, цифри,
підкреслення і дефіси. (Дефіси можуть використовуються для поділу слів.) Наприклад, view
, update2
і
comment-post
є допустимими ідентифікаторами дій, в той час, як view?
та Update
не є такими.
Ви можете створювати дії двома способами: вбудовані дії і автономні дії. Вбудована дія є методом, визначеним в класі контролера, тоді як автономна дія є класом, успадкованим від yii\base\Action або його нащадків. Вбудовані дії вимагають менше зусиль для створення і, в основному, використовуються якщо у вас немає потреби у повторному використанні цих дій. Автономні дії, з іншого боку, в основному створюються для використання в різних контролерах або для розподілення у вигляді розширень.
Вбудовані дії ¶
Вбудовані дії це ті дії, які визначені у рамках методів контролера, як це було щойно описано.
Назви методів дій можуть бути отримані із ідентифікаторів дій наступним чином:
- Привести перший символ кожного слова в ідентифікаторі дії у верхній регістр.
- Прибрати дефіси.
- Додати префікс
action
.
Наприклад, index
перетвориться у actionIndex
, а hello-world
перетвориться у actionHelloWorld
.
Note: Назви імен методів дій є регістр-залежними. Якщо у вас є метод
ActionIndex
, то його не буде враховано як метод дії, і в результаті, запит до діїindex
призведе до отримання виключення. Також слід врахувати, що методи дій повинні бути публічними ("public"). Приватні ("private") або захищені ("protected") методи НЕ визначають вбудованих дій.
В основному використовуються вбудовані дії, оскільки для їх створення не потрібного багато зусиль. Тим не менше, якщо ви плануєте повторно використовувати деякі дії у різних місцях або якщо ви хочете перерозподілити дії, ви повинні визначити їх як автономні дії.
Автономні дії ¶
Автономні дії визначаються в якості класів, успадкованих від yii\base\Action або його нащадків. Наприклад, в релізах Yii присутні yii\web\ViewAction та yii\web\ErrorAction, обидва класи є окремими діями.
Для використання автономної дії, ви маєте вказати її у мапі дій за допомогою перевизначення методу actions() у вашому класі контролера, наступним чином:
public function actions()
{
return [
// оголошує дію "error" за допомогою назви класу
'error' => 'yii\web\ErrorAction',
// оголошує дію "view" за допомогою конфігураційного масиву
'view' => [
'class' => 'yii\web\ViewAction',
'viewPrefix' => '',
],
];
}
Як ви можете бачити, метод actions()
повинен повернути масив, ключами якого є ідентифікатори дій, а значеннями - відповідні
назви класів дій або конфігурації. На відміну від вбудованих дій, ідентифікатори автономних дій
можуть містити довільні символи, доки вони визначені у методі actions()
.
Для створення класу автономної дії, ви повинні успадкуватись від класу yii\base\Action або його нащадків, і реалізувати публічний ("public") метод yii\base\Action::run(). Роль метода yii\base\Action::run() аналогічна іншим методам дій. Наприклад,
<?php
namespace app\components;
use yii\base\Action;
class HelloWorldAction extends Action
{
public function run()
{
return "Hello World";
}
}
Результати дій ¶
Значення, що повертається від методу дії або методу yii\base\Action::run() автономної дії дуже важливе. Воно є результатом виконання відповідної дії.
Значення, що повертається, може бути об’єктом відповіді, яке буде відправлено кінцевому користувачу.
- Для веб-додатків, значення, що повертається, також може бути довільними даними, яке буде призначене до yii\web\Response::$data, а потім конвертоване у текстовий рядок, що представляє тіло відповіді.
- Для консольних додатків, значення, що повертається, також може бути числом, що представляє статус виходу виконання команди.
У вищенаведених прикладах всі результати дій є текстовими рядками, які будуть використані у якості тіла відповіді для відправлення кінцевому користувачу. Наступний приклад показує як дія може перенаправити браузер користувача на новий URL за допомогою повернення об’єкта відповіді (оскільки метод redirect() повертає об’єкт response):
public function actionForward()
{
// перенаправляємо браузер користувача на http://example.com
return $this->redirect('http://example.com');
}
Параметри дій ¶
Методи дій для вбудованих дій і методи yii\base\Action::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']
.
Якщо ви хочете, щоб параметр дії приймав масив значень, ви повинні вказати тип 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. Коли маршрут містить тільки ідентифікатор контролера, то розуміється, що було запитана дія контролера за замовчуванням.
За замовчуванням, ця дія має значення 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() буде викликаний після того, як контролер був створений і сконфігурований.
- Контролер створить об’єкт дії, базуючись на ідентифікаторі дії, яку було запитано:
- Якщо ідентифікатор дії не вказано, то буде використано ідентифікатор дії за замовчуванням;
- Якщо ідентифікатор дії знайдено у мапі дій, то буде створено автономну дію;
- Якщо ідентифікатор дії відповідає методу дії, то буде створено вбудовану дію;
- В іншому випадку, буде отримане виключення yii\base\InvalidRouteException.
- Контролер послідовно викликає метод
beforeAction()
додатка, модуля (якщо контролер належить модулю) і самого контролера:- Якщо один із методів повернув
false
, то решта невикликаних методівbeforeAction
будуть пропущені, а виконання дії буде скасовано; - За замовчуванням, кожний виклик метода
beforeAction()
викликає подіюbeforeAction
, на яку ви можете призначити обробник.
- Якщо один із методів повернув
- Контролер виконує дію:
- Параметри дії будуть проаналізовані та заповнені із даних запиту.
- Контролер послідовно викликає методи
afterAction
контролера, модуля (якщо контролер належить модулю) і додатка:- За замовчуванням, кожний виклик метода
afterAction()
викликає подіюafterAction
, на яку ви можете призначити обробник.
- За замовчуванням, кожний виклик метода
- Додаток, отримавши результат виконання дії, привласнює його об’єкту response.
Кращі практики ¶
В добре організованому додатку контролери, зазвичай дуже малі, з діями, що містять лише декілька рядків коду. Якщо ваш контролер дуже складний, це зазвичай означає, що вам потрібно провести його рефакторинг і перенести деякий код в інші класи.
В цілому, контролери
- можуть мати доступ до даних запиту;
- можуть викликати методи моделей та інших компонентів системи із даними запиту;
- можуть використовувати представлення для формування відповіді;
- НЕ повинні займатись обробкою даних - це має відбуватися на рівні моделей;
- мають уникати використання HTML або іншої розмітки - краще це робити у представленнях.