
Контролери є частиною архітектури MVC. Це об’єкти класів, успадкованих від yii\base\Controller та відповідають за обробку запитів і генерування відповідей. Зокрема, після отримання контролю від додатків, контролери проаналізують вхідні дані, передадуть їх у моделі, додадуть результати моделі у представлення, і на сам кінець згенерують вихідні відповіді.
Контролери складаються з дій, які є основними блоками, до яких може звертатись кінцевий користувач і запитувати виконання того або іншого функціоналу. В контролері може бути одна або декілька дій.
Наступний приклад показує контролер post з двома діями: view та create:
phpnamespace 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 https://hostname/index.php?r=site/index, то буде викликано дію index
у контролері site. Розділ Маршрутизація та створення URL містить більш детальну інформацію
про те, як маршрути співвідносяться із діями.
У веб-додатках контролери повинні бути успадкованими від класу yii\web\Controller
або його нащадків. Аналогічно для консольних додатків, контролери повинні бути
успадкованими від класу yii\console\Controller або його нащадків. Наступний код визначає контролер site:
phpnamespace 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показує яким чином ви можете розташувати контролер в під-директорії простору імен контролера. Це дуже зручно, коли ви хочете організувати свої контролери у декілька категорій і не хочете використовувати модулі.
Ви можете налаштувати мапу контролерів для того, щоб подолати описані вище обмеження іменування ідентифікаторів контролерів і назв класів. В основному, це дуже зручно, коли ви використовуєте сторонні контролери, іменування яких ви не можете контролювати.
Ви можете налаштувати мапу контролерів в налаштуваннях додатка наступним чином:
php[ 'controllerMap' => [ // оголошує контролер "account", використовуючи назву класу 'account' => 'app\controllers\UserController', // оголошує контролер "article", використовуючи масив конфігурації 'article' => [ 'class' => 'app\controllers\PostController', 'enableCsrfValidation' => false, ], ], ]
Кожний додаток має контролер за замовчуванням, вказаний через властивість yii\base\Application::defaultRoute.
Коли в запиті не вказано маршрут, то буде використано маршрут із зазначеної властивості.
Для веб-додатків це значення рівне 'site', у той час, як для
консольних додатків, це - 'help'. Таким чином, якщо вказаний URL
https://hostname/index.php, це значить, що контролер site виконає обробку запиту.
Ви можете змінити контролер за замовчуванням наступним чином в налаштуваннях додатку:
php[ 'defaultRoute' => 'main', ]
Створення дій може бути настільки ж простим, як і оголошення так званих методів дій у класі контролера. Метод дії це
публічний метод, ім’я якого починається зі слова action. Значення, яке повертається методом дії, представляє дані
відповіді, які будуть відправлені кінцевому користувачу. Наведений нижче код визначає дві дії index і hello-world:
phpnamespace 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() у вашому класі контролера, наступним чином:
phppublic function actions() { return [ // оголошує дію "error" за допомогою назви класу 'error' => 'yii\web\ErrorAction', // оголошує дію "view" за допомогою конфігураційного масиву 'view' => [ 'class' => 'yii\web\ViewAction', 'viewPrefix' => '', ], ]; }
Як ви можете бачити, метод actions() повинен повернути масив, ключами якого є ідентифікатори дій, а значеннями - відповідні
назви класів дій або конфігурації. На відміну від вбудованих дій, ідентифікатори автономних дій
можуть містити довільні символи, доки вони визначені у методі actions().
Для створення класу автономної дії, ви повинні успадкуватись від класу yii\base\Action або його нащадків, і реалізувати публічний ("public") метод run(). Роль метода run() аналогічна іншим методам дій. Наприклад,
php<?php namespace app\components; use yii\base\Action; class HelloWorldAction extends Action { public function run() { return "Hello World"; } }
Значення, що повертається від методу дії або методу run() автономної дії дуже важливе. Воно є результатом виконання відповідної дії.
Значення, що повертається, може бути об’єктом відповіді, яке буде відправлено кінцевому користувачу.
У вищенаведених прикладах всі результати дій є текстовими рядками, які будуть використані у якості тіла відповіді для відправлення кінцевому користувачу. Наступний приклад показує як дія може перенаправити браузер користувача на новий URL за допомогою повернення об’єкта відповіді (оскільки метод redirect() повертає об’єкт response):
phppublic function actionForward() { // перенаправляємо браузер користувача на https://example.com return $this->redirect('https://example.com'); }
Методи дій для вбудованих дій і методи run() для автономних дій можуть приймати, так звані,
параметри дії. Їх значення беруться із запитів. Для веб-додатків, значення кожного з
параметрів дії береться із $_GET, використовуючи назву параметра у якості ключа;
для консольних додатків - вони відповідають аргументам командного рядка.
В наступному прикладі, дія view (вбудована дія) оголошує два параметри: $id і $version.
phpnamespace app\controllers; use yii\web\Controller; class PostController extends Controller { public function actionView($id, $version = null) { // ... } }
Параметри дії будуть заповнені для різних запитів наступним чином:
https://hostname/index.php?r=post/view&id=123: параметру $id буде присвоєне значення '123', у той час,
як $version буде мати значення null, бо рядок запиту не містить параметра version.https://hostname/index.php?r=post/view&id=123&version=2: параметрам $id і $version будуть присвоєні
значення '123' і '2' відповідно.https://hostname/index.php?r=post/view: буде отримане виключення yii\web\BadRequestHttpException, оскільки
обов’язковий параметр $id не було вказано у запиті.https://hostname/index.php?r=post/view&id[]=123: буде отримане виключення yii\web\BadRequestHttpException,
оскільки параметр $id отримав невірне значення ['123'].Якщо ви хочете, щоб параметр дії приймав масив значень, ви повинні вказати тип array для параметра метода, як наведено нижче:
phppublic function actionView(array $id, $version = null) { // ... }
Тепер, якщо запит буде містити URL https://hostname/index.php?r=post/view&id[]=123, то параметр $id отримає
значення ['123']. Якщо запит буде містити URL https://hostname/index.php?r=post/view&id=123, то параметр
$id все одно отримає масив, оскільки скалярне значення '123' буде автоматично перетворено у масив.
Вищенаведені приклади в основному показують як параметри дій працюють для веб-додатків. Більше інформації про параметри консольних додатків наведено в розділі Консольні команди.
Кожний контролер містить дію за замовчуванням, визначену через властивість yii\base\Controller::defaultAction. Коли маршрут містить тільки ідентифікатор контролера, то розуміється, що було запитана дія контролера за замовчуванням.
За замовчуванням, ця дія має значення index. Для зміни цього значення необхідно просто перевизначити дану
властивість у класі контролера наступним чином:
phpnamespace app\controllers; use yii\web\Controller; class SiteController extends Controller { public $defaultAction = 'home'; public function actionHome() { return $this->render('home'); } }
При обробці запиту, додаток створить контролер, базуючись на маршруті, який було запитано. Для виконання запиту, контролер пройде через наступні етапи життєвого циклу:
beforeAction() додатка, модуля (якщо контролер належить модулю) і
самого контролера:
false, то решта невикликаних методів beforeAction будуть пропущені,
а виконання дії буде скасовано;beforeAction() викликає подію beforeAction, на яку ви можете призначити обробник.afterAction контролера, модуля (якщо контролер належить модулю) і додатка:
afterAction() викликає подію afterAction, на яку ви можете призначити обробник.В добре організованому додатку контролери, зазвичай дуже малі, з діями, що містять лише декілька рядків коду. Якщо ваш контролер дуже складний, це зазвичай означає, що вам потрібно провести його рефакторинг і перенести деякий код в інші класи.
В цілому, контролери
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,
            ]);
        }
    }
}[
    'controllerMap' => [
        // оголошує контролер "account", використовуючи назву класу
        'account' => 'app\controllers\UserController',
        // оголошує контролер "article", використовуючи масив конфігурації
        'article' => [
            'class' => 'app\controllers\PostController',
            'enableCsrfValidation' => false,
        ],
    ],
]public function actions()
{
    return [
        // оголошує дію "error" за допомогою назви класу
        'error' => 'yii\web\ErrorAction',
        // оголошує дію "view" за допомогою конфігураційного масиву
        'view' => [
            'class' => 'yii\web\ViewAction',
            'viewPrefix' => '',
        ],
    ];
}