05Контроллеры и действия
Как маршрут превращается в вызов метода, чем встроенные действия отличаются от отдельных, откуда берутся параметры и что может вернуть действие.
Контроллер принимает запрос, дёргает модели и отдаёт результат в представление. Он состоит из действий — публичных методов actionXxx() или отдельных классов. Маршрут post/view — это PostController::actionView().
Минимальный контроллер#
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(); // → страница 404
}
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]);
}
return $this->render('create', ['model' => $model]);
}
}Веб-контроллеры наследуют yii\web\Controller, консольные — yii\console\Controller.
Маршруты и имена#
Маршрут: контроллер/действие или модуль/контроллер/действие. Идентификаторы — в нижнем регистре, слова через дефис.
| ID контроллера | Класс |
|---|---|
article | app\controllers\ArticleController |
post-comment | app\controllers\PostCommentController |
admin/post-comment | app\controllers\admin\PostCommentController (подпапка без модуля) |
Пространство имён задаёт controllerNamespace приложения (по умолчанию app\controllers). Если соглашение не подходит — например, контроллер из чужой библиотеки — используйте карту:
'controllerMap' => [
'account' => 'app\controllers\UserController',
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
],Маршрут без действия → defaultAction контроллера (index); запрос без маршрута → defaultRoute приложения (site). Оба можно переопределить:
class SiteController extends Controller
{
public $defaultAction = 'home';
}Действия#
Встроенные (inline)#
Публичный метод с префиксом action. Имя метода — из ID действия: hello-world → actionHelloWorld.
Отдельные (standalone)#
Класс, унаследованный от yii\base\Action, с методом run(). Регистрируется в карте действий контроллера. Так удобно переиспользовать действия между контроллерами и в расширениях:
public function actions()
{
return [
'error' => 'yii\web\ErrorAction', // страница ошибки
'captcha' => ['class' => 'yii\captcha\CaptchaAction'],
'page' => ['class' => 'yii\web\ViewAction', 'viewPrefix' => 'pages'], // статические страницы
];
}namespace app\components;
use yii\base\Action;
class HelloWorldAction extends Action
{
public $greeting = 'Hello';
public function run($name = 'World')
{
return "{$this->greeting}, {$name}";
}
}ID отдельных действий могут быть любыми — они заданы явно в actions().
Результат действия#
| Что вернули | Что произойдёт |
|---|---|
| строка | станет телом ответа (обычно результат $this->render()) |
объект Response | отправится как есть — так работает $this->redirect() |
| массив / любые данные | попадёт в Response::data и отформатируется по Response::format (JSON, XML…) |
| число в консоли | код выхода команды |
public function actionForward()
{
return $this->redirect('https://example.com'); // redirect() возвращает Response
}
public function actionInfo()
{
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return ['message' => 'hello', 'code' => 100];
}Параметры действий#
Параметры метода заполняются из $_GET по имени (в консоли — из аргументов командной строки):
public function actionView($id, $version = null) { /* ... */ }?r=post/view&id=123→$id = '123',$version = null;?r=post/view→BadRequestHttpException— обязательный параметр не передан;?r=post/view&id[]=123→BadRequestHttpException— ожидался скаляр, пришёл массив.
Чтобы принять массив, укажите тип: public function actionView(array $id) — тогда скаляр автоматически обернётся в массив.
Жизненный цикл контроллера#
init()— контроллер создан и сконфигурирован.- Создание действия по ID: сначала карта
actions(), затем методactionXxx(), иначеInvalidRouteException. beforeAction()последовательно у приложения, модуля и контроллера. Вернулfalse— остальные пропускаются, действие не выполняется. Здесь работают фильтры.- Выполнение действия с параметрами из запроса.
afterAction()в обратном порядке: контроллер → модуль → приложение.- Результат уходит в компонент
response.
Что ещё умеет контроллер#
render($view, $params)renderPartial($view, $params)renderAjax($view, $params)renderContent($html)redirect($url, $statusCode = 302)$url может быть маршрутом-массивомgoHome(), goBack(), refresh()Url::remember()), перезагрузка текущей страницыasJson($data), asXml($data)response->format и возвращают объект ответа: его нужно вернуть из действияbehaviors()$layoutfalse — без шаблона$enableCsrfValidationТипичный CRUD#
Так выглядит контроллер, который генерирует Gii, — хороший образец «тонкого» контроллера:
use yii\filters\VerbFilter;
use yii\web\NotFoundHttpException;
class PostController extends Controller
{
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::class,
'actions' => ['delete' => ['POST']],
],
];
}
public function actionIndex()
{
$searchModel = new PostSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', compact('searchModel', 'dataProvider'));
}
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
Yii::$app->session->setFlash('success', 'Сохранено');
return $this->redirect(['view', 'id' => $model->id]);
}
return $this->render('update', ['model' => $model]);
}
public function actionDelete($id)
{
$this->findModel($id)->delete();
return $this->redirect(['index']);
}
protected function findModel($id)
{
if (($model = Post::findOne($id)) !== null) {
return $model;
}
throw new NotFoundHttpException('Запись не найдена.');
}
}app\controllers\admin\PostCommentController::actionCreateReply() — префикс до слеша трактуется как подпапка пространства имён.
Это самостоятельный класс: его можно переиспользовать в разных контроллерах, настраивать через конфигурацию и распространять в расширениях (ErrorAction, CaptchaAction, ViewAction).
Будет выброшено BadRequestHttpException (HTTP 400) ещё до выполнения действия.
Установить Yii::$app->response->format = Response::FORMAT_JSON и вернуть массив, либо вызвать return $this->asJson($data).
Приложение → модуль → контроллер; любой false останавливает цепочку.