Controllers are part of the MVC architecture. They are objects of classes extending from yii\base\Controller and are responsible for processing requests and generating responses. In particular, after taking over the control from applications, controllers will analyze incoming request data, pass them to models, inject model results into views, and finally generate outgoing responses.
Controllers are composed of actions which are the most basic units that end users can address and request for execution. A controller can have one or multiple actions.
The following example shows a post
controller with two actions: view
and 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,
]);
}
}
}
In the view
action (defined by the actionView()
method), the code first loads the model
according to the requested model ID; If the model is loaded successfully, it will display it using
a view named view
. Otherwise, it will throw an exception.
In the create
action (defined by the actionCreate()
method), the code is similar. It first tries to populate
a new instance of the model using the request data and save the model. If both succeed it
will redirect the browser to the view
action with the ID of the newly created model. Otherwise it will display
the create
view through which users can provide the needed input.
End users address actions through the so-called routes. A route is a string that consists of the following parts:
Routes take the following format:
ControllerID/ActionID
or the following format if the controller belongs to a module:
ModuleID/ControllerID/ActionID
So if a user requests with the URL https://hostname/index.php?r=site/index
, the index
action in the site
controller
will be executed. For more details on how routes are resolved into actions, please refer to
the Routing and URL Creation section.
In Web applications, controllers should extend from yii\web\Controller or its
child classes. Similarly in console applications, controllers should extend from
yii\console\Controller or its child classes. The following code defines a site
controller:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
}
Usually, a controller is designed to handle the requests regarding a particular type of resource.
For this reason, controller IDs are often nouns referring to the types of the resources that they are handling.
For example, you may use article
as the ID of a controller that handles article data.
By default, controller IDs should contain these characters only: English letters in lower case, digits,
underscores, hyphens, and forward slashes. For example, article
and post-comment
are both valid controller IDs,
while article?
, PostComment
, admin\post
are not.
A controller ID may also contain a subdirectory prefix. For example, admin/article
stands for an article
controller
in the admin
subdirectory under the controller namespace.
Valid characters for subdirectory prefixes include: English letters in lower and upper cases, digits, underscores, and
forward slashes, where forward slashes are used as separators for multi-level subdirectories (e.g. panels/admin
).
Controller class names can be derived from controller IDs according to the following procedure:
Controller
.The following are some examples, assuming the controller namespace
takes the default value app\controllers
:
article
becomes app\controllers\ArticleController
;post-comment
becomes app\controllers\PostCommentController
;admin/post-comment
becomes app\controllers\admin\PostCommentController
;adminPanels/post-comment
becomes app\controllers\adminPanels\PostCommentController
.Controller classes must be autoloadable. For this reason, in the above examples,
the article
controller class should be saved in the file whose alias
is @app/controllers/ArticleController.php
; while the admin/post-comment
controller should be
in @app/controllers/admin/PostCommentController.php
.
Info: The last example
admin/post-comment
shows how you can put a controller under a sub-directory of the controller namespace. This is useful when you want to organize your controllers into several categories and you do not want to use modules.
You can configure the controller map to overcome the constraints of the controller IDs and class names described above. This is mainly useful when you are using third-party controllers and you do not have control over their class names.
You may configure the controller map in the application configuration. For example:
[
'controllerMap' => [
// declares "account" controller using a class name
'account' => 'app\controllers\UserController',
// declares "article" controller using a configuration array
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
],
]
Each application has a default controller specified via the yii\base\Application::$defaultRoute property.
When a request does not specify a route, the route specified by this property will be used.
For Web applications, its value is 'site'
, while for console applications,
it is help
. Therefore, if a URL is https://hostname/index.php
, then the site
controller will handle the request.
You may change the default controller with the following application configuration:
[
'defaultRoute' => 'main',
]
Creating actions can be as simple as defining the so-called action methods in a controller class. An action method is
a public method whose name starts with the word action
. The return value of an action method represents
the response data to be sent to end users. The following code defines two actions, index
and 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';
}
}
An action is often designed to perform a particular manipulation of a resource. For this reason,
action IDs are usually verbs, such as view
, update
, etc.
By default, action IDs should contain these characters only: English letters in lower case, digits,
underscores, and hyphens (you can use hyphens to separate words). For example,
view
, update2
, and comment-post
are all valid action IDs, while view?
and Update
are not.
You can create actions in two ways: inline actions and standalone actions. An inline action is defined as a method in the controller class, while a standalone action is a class extending yii\base\Action or its child classes. Inline actions take less effort to create and are often preferred if you have no intention to reuse these actions. Standalone actions, on the other hand, are mainly created to be used in different controllers or be redistributed as extensions.
Inline actions refer to the actions that are defined in terms of action methods as we just described.
The names of the action methods are derived from action IDs according to the following procedure:
action
.For example, index
becomes actionIndex
, and hello-world
becomes actionHelloWorld
.
Note: The names of the action methods are case-sensitive. If you have a method named
ActionIndex
, it will not be considered as an action method, and as a result, the request for theindex
action will result in an exception. Also note that action methods must be public. A private or protected method does NOT define an inline action.
Inline actions are the most commonly defined actions because they take little effort to create. However, if you plan to reuse the same action in different places, or if you want to redistribute an action, you should consider defining it as a standalone action.
Standalone actions are defined in terms of action classes extending yii\base\Action or its child classes. For example, in the Yii releases, there are yii\web\ViewAction and yii\web\ErrorAction, both of which are standalone actions.
To use a standalone action, you should declare it in the action map by overriding the yii\base\Controller::actions() method in your controller classes like the following:
public function actions()
{
return [
// declares "error" action using a class name
'error' => 'yii\web\ErrorAction',
// declares "view" action using a configuration array
'view' => [
'class' => 'yii\web\ViewAction',
'viewPrefix' => '',
],
];
}
As you can see, the actions()
method should return an array whose keys are action IDs and values the corresponding
action class names or configurations. Unlike inline actions, action IDs for standalone
actions can contain arbitrary characters, as long as they are declared in the actions()
method.
To create a standalone action class, you should extend yii\base\Action or a child class, and implement
a public method named run()
. The role of the run()
method is similar to that of an action method. For example,
<?php
namespace app\components;
use yii\base\Action;
class HelloWorldAction extends Action
{
public function run()
{
return "Hello World";
}
}
The return value of an action method or of the run()
method of a standalone action is significant. It stands
for the result of the corresponding action.
The return value can be a response object which will be sent to the end user as the response.
In the examples shown above, the action results are all strings which will be treated as the response body to be sent to end users. The following example shows how an action can redirect the user browser to a new URL by returning a response object (because the redirect() method returns a response object):
public function actionForward()
{
// redirect the user browser to https://example.com
return $this->redirect('https://example.com');
}
The action methods for inline actions and the run()
methods for standalone actions can take parameters,
called action parameters. Their values are obtained from requests. For Web applications,
the value of each action parameter is retrieved from $_GET
using the parameter name as the key;
for console applications, they correspond to the command line arguments.
In the following example, the view
action (an inline action) has declared two parameters: $id
and $version
.
namespace app\controllers;
use yii\web\Controller;
class PostController extends Controller
{
public function actionView($id, $version = null)
{
// ...
}
}
The action parameters will be populated as follows for different requests:
https://hostname/index.php?r=post/view&id=123
: the $id
parameter will be filled with the value
'123'
, while $version
is still null
because there is no version
query parameter.https://hostname/index.php?r=post/view&id=123&version=2
: the $id
and $version
parameters will
be filled with '123'
and '2'
, respectively.https://hostname/index.php?r=post/view
: a yii\web\BadRequestHttpException exception will be thrown
because the required $id
parameter is not provided in the request.https://hostname/index.php?r=post/view&id[]=123
: a yii\web\BadRequestHttpException exception will be thrown
because $id
parameter is receiving an unexpected array value ['123']
.If you want an action parameter to accept array values, you should type-hint it with array
, like the following:
public function actionView(array $id, $version = null)
{
// ...
}
Now if the request is https://hostname/index.php?r=post/view&id[]=123
, the $id
parameter will take the value
of ['123']
. If the request is https://hostname/index.php?r=post/view&id=123
, the $id
parameter will still
receive the same array value because the scalar value '123'
will be automatically turned into an array.
The above examples mainly show how action parameters work for Web applications. For console applications, please refer to the Console Commands section for more details.
Each controller has a default action specified via the yii\base\Controller::$defaultAction property. When a route contains the controller ID only, it implies that the default action of the specified controller is requested.
By default, the default action is set as index
. If you want to change the default value, simply override
this property in the controller class, like the following:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $defaultAction = 'home';
public function actionHome()
{
return $this->render('home');
}
}
When processing a request, an application will create a controller based on the requested route. The controller will then undergo the following lifecycle to fulfill the request:
beforeAction()
method of the application, the module (if the controller
belongs to a module), and the controller.false
, the rest of the uncalled beforeAction()
methods will be skipped and the
action execution will be cancelled.beforeAction()
method call will trigger a beforeAction
event to which you can attach a handler.afterAction()
method of the controller, the module (if the controller
belongs to a module), and the application.afterAction()
method call will trigger an afterAction
event to which you can attach a handler.In a well-designed application, controllers are often very thin, with each action containing only a few lines of code. If your controller is rather complicated, it usually indicates that you should refactor it and move some code to other classes.
Here are some specific best practices. Controllers
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.