?
本文檔使用 php中文網(wǎng)手冊 發(fā)布
控制器是?MVC?模式中的一部分, 是繼承yii\base\Controller類的對象,負(fù)責(zé)處理請求和生成響應(yīng)。 具體來說,控制器從應(yīng)用主體接管控制后會分析請求數(shù)據(jù)并傳送到模型, 傳送模型結(jié)果到視圖,最后生成輸出響應(yīng)信息。
控制器由?操作?組成,它是執(zhí)行終端用戶請求的最基礎(chǔ)的單元,一個控制器可有一個或多個操作。
如下示例顯示包含兩個操作view
?and?create
?的控制器post
:
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()
?方法)中, 代碼首先根據(jù)請求模型ID加載?模型, 如果加載成功,會渲染名稱為view
的視圖并顯示,否則會拋出一個異常。
在操作?create
?(定義為?actionCreate()
?方法)中, 代碼相似. 先將請求數(shù)據(jù)填入模型, 然后保存模型,如果兩者都成功,會跳轉(zhuǎn)到ID為新創(chuàng)建的模型的view
操作,否則顯示提供用戶輸入的create
視圖。
終端用戶通過所謂的路由尋找到操作,路由是包含以下部分的字符串:
路由使用如下格式:
ControllerID/ActionID
如果屬于模塊下的控制器,使用如下格式:
ModuleID/ControllerID/ActionID
如果用戶的請求地址為?http://hostname/index.php?r=site/index
, 會執(zhí)行site
?控制器的index
?操作。 更多關(guān)于處理路由的詳情請參閱?路由?一節(jié)。
在yii\web\Application網(wǎng)頁應(yīng)用中,控制器應(yīng)繼承yii\web\Controller 或它的子類。 同理在yii\console\Application控制臺應(yīng)用中,控制器繼承yii\console\Controller 或它的子類。 如下代碼定義一個?site
?控制器:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller{
}
通常情況下,控制器用來處理請求有關(guān)的資源類型,因此控制器ID通常為和資源有關(guān)的名詞。 例如使用article
作為處理文章的控制器ID。
控制器ID應(yīng)僅包含英文小寫字母、數(shù)字、下劃線、中橫杠和正斜杠, 例如?article
?和?post-comment
?是真是的控制器ID,article?
,PostComment
,?admin\post
不是控制器ID。
控制器Id可包含子目錄前綴,例如?admin/article
?代表 yii\base\Application::controllerNamespace控制器命名空間下?admin
子目錄中article
?控制器。 子目錄前綴可為英文大小寫字母、數(shù)字、下劃線、正斜杠,其中正斜杠用來區(qū)分多級子目錄(如?panels/admin
)。
控制器ID遵循以下規(guī)則衍生控制器類名:
Controller
后綴;下面為一些示例,假設(shè)yii\base\Application::controllerNamespace控制器命名空間為?app\controllers
:
article
?對應(yīng)?app\controllers\ArticleController
;post-comment
?對應(yīng)?app\controllers\PostCommentController
;admin/post-comment
?對應(yīng)?app\controllers\admin\PostCommentController
;adminPanels/post-comment
?對應(yīng)?app\controllers\adminPanels\PostCommentController
.控制器類必須能被?自動加載,所以在上面的例子中, 控制器article
?類應(yīng)在?別名?為@app/controllers/ArticleController.php
的文件中定義, 控制器admin/post2-comment
應(yīng)在@app/controllers/admin/Post2CommentController.php
文件中。
補充: 最后一個示例?
admin/post2-comment
?表示你可以將控制器放在 yii\base\Application::controllerNamespace控制器命名空間下的子目錄中, 在你不想用?模塊?的情況下給控制器分類,這種方式很有用。
可通過配置 yii\base\Application::controllerMap 來強制上述的控制器ID和類名對應(yīng), 通常用在使用第三方不能掌控類名的控制器上。
配置?應(yīng)用配置?中的application configuration,如下所示:
[
'controllerMap' => [
// 用類名申明 "account" 控制器
'account' => 'app\controllers\UserController',
// 用配置數(shù)組申明 "article" 控制器
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
],
]
每個應(yīng)用有一個由yii\base\Application::defaultRoute屬性指定的默認(rèn)控制器; 當(dāng)請求沒有指定?路由,該屬性值作為路由使用。 對于yii\web\Application網(wǎng)頁應(yīng)用,它的值為?'site'
, 對于 yii\console\Application控制臺應(yīng)用,它的值為?help
, 所以URL為http://hostname/index.php
?表示由?site
?控制器來處理。
可以在?應(yīng)用配置?中修改默認(rèn)控制器,如下所示:
[
'defaultRoute' => 'main',
]
創(chuàng)建操作可簡單地在控制器類中定義所謂的?操作方法?來完成,操作方法必須是以action
開頭的公有方法。 操作方法的返回值會作為響應(yīng)數(shù)據(jù)發(fā)送給終端用戶,如下代碼定義了兩個操作?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';
}
}
操作通常是用來執(zhí)行資源的特定操作,因此,操作ID通常為動詞,如view
,?update
等。
操作ID應(yīng)僅包含英文小寫字母、數(shù)字、下劃線和中橫杠,操作ID中的中橫杠用來分隔單詞。 例如view
,?update2
,?comment-post
是真實的操作ID,view?
,?Update
不是操作ID.
可通過兩種方式創(chuàng)建操作ID,內(nèi)聯(lián)操作和獨立操作. An inline action is 內(nèi)聯(lián)操作在控制器類中定義為方法;獨立操作是繼承yii\base\Action或它的子類的類。 內(nèi)聯(lián)操作容易創(chuàng)建,在無需重用的情況下優(yōu)先使用; 獨立操作相反,主要用于多個控制器重用,或重構(gòu)為擴展。
內(nèi)聯(lián)操作指的是根據(jù)我們剛描述的操作方法。
操作方法的名字是根據(jù)操作ID遵循如下規(guī)則衍生:
action
前綴.例如index
?轉(zhuǎn)成?actionIndex
,?hello-world
?轉(zhuǎn)成?actionHelloWorld
。
注意: 操作方法的名字大小寫敏感,如果方法名稱為
ActionIndex
不會認(rèn)為是操作方法, 所以請求index
操作會返回一個異常,也要注意操作方法必須是公有的,私有或者受保護的方法不能定義成內(nèi)聯(lián)操作。
因為容易創(chuàng)建,內(nèi)聯(lián)操作是最常用的操作,但是如果你計劃在不同地方重用相同的操作, 或者你想重新分配一個操作,需要考慮定義它為獨立操作。
獨立操作通過繼承yii\base\Action或它的子類來定義。 例如Yii發(fā)布的yii\web\ViewAction和yii\web\ErrorAction都是獨立操作。
要使用獨立操作,需要通過控制器中覆蓋yii\base\Controller::actions()方法在action map中申明,如下例所示:
public function actions(){
return [
// 用類來申明"error" 操作
'error' => 'yii\web\ErrorAction',
// 用配置數(shù)組申明 "view" 操作
'view' => [
'class' => 'yii\web\ViewAction',
'viewPrefix' => '',
],
];
}
如上所示,?actions()
?方法返回鍵為操作ID、值為對應(yīng)操作類名或數(shù)組configurations?的數(shù)組。 和內(nèi)聯(lián)操作不同,獨立操作ID可包含任意字符,只要在actions()
?方法中申明.
為創(chuàng)建一個獨立操作類,需要繼承yii\base\Action 或它的子類,并實現(xiàn)公有的名稱為run()
的方法,?run()
?方法的角色和操作方法類似,例如:
<?phpnamespace app\components;
use yii\base\Action;
class HelloWorldAction extends Action{
public function run()
{
return "Hello World";
}
}
操作方法或獨立操作的run()
方法的返回值非常重要,它表示對應(yīng)操作結(jié)果。
返回值可為?響應(yīng)?對象,作為響應(yīng)發(fā)送給終端用戶。
在上面的例子中,操作結(jié)果都為字符串,作為響應(yīng)數(shù)據(jù)發(fā)送給終端用戶,下例顯示一個操作通過 返回響應(yīng)對象(因為yii\web\Controller::redirect()方法返回一個響應(yīng)對象)可將用戶瀏覽器跳轉(zhuǎn)到新的URL。
public function actionForward(){
// 用戶瀏覽器跳轉(zhuǎn)到 http://example.com
return $this->redirect('http://example.com');
}
內(nèi)聯(lián)操作的操作方法和獨立操作的?run()
?方法可以帶參數(shù),稱為操作參數(shù)。 參數(shù)值從請求中獲取,對于yii\web\Application網(wǎng)頁應(yīng)用, 每個操作參數(shù)的值從$_GET
中獲得,參數(shù)名作為鍵; 對于yii\console\Application控制臺應(yīng)用, 操作參數(shù)對應(yīng)命令行參數(shù)。
如下例,操作view
?(內(nèi)聯(lián)操作) 申明了兩個參數(shù)?$id
?和?$version
。
namespace app\controllers;
use yii\web\Controller;
class PostController extends Controller{
public function actionView($id, $version = null)
{
// ...
}
}
操作參數(shù)會被不同的參數(shù)填入,如下所示:
http://hostname/index.php?r=post/view&id=123
:?$id
?會填入'123'
,$version
?仍為 null 空因為沒有version
請求參數(shù);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 異常 因為請求沒有提供參數(shù)給必須賦值參數(shù)$id
;http://hostname/index.php?r=post/view&id[]=123
: 會拋出yii\web\BadRequestHttpException 異常 因為$id
?參數(shù)收到數(shù)字值['123']
而不是字符串.如果想讓操作參數(shù)接收數(shù)組值,需要指定$id為array
,如下所示:
public function actionView(array $id, $version = null){
// ...
}
現(xiàn)在如果請求為?http://hostname/index.php?r=post/view&id[]=123
, 參數(shù)?$id
?會使用數(shù)組值['123']
, 如果請求為http://hostname/index.php?r=post/view&id=123
, 參數(shù)?$id
?會獲取相同數(shù)組值,因為無類型的'123'
會自動轉(zhuǎn)成數(shù)組。
上述例子主要描述網(wǎng)頁應(yīng)用的操作參數(shù),對于控制臺應(yīng)用,更多詳情請參閱控制臺命令。
每個控制器都有一個由 yii\base\Controller::defaultAction 屬性指定的默認(rèn)操作, 當(dāng)路由?只包含控制器ID,會使用所請求的控制器的默認(rèn)操作。
默認(rèn)操作默認(rèn)為?index
,如果想修改默認(rèn)操作,只需簡單地在控制器類中覆蓋這個屬性,如下所示:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller{
public $defaultAction = 'home';
public function actionHome()
{
return $this->render('home');
}
}
處理一個請求時,應(yīng)用主體?會根據(jù)請求路由創(chuàng)建一個控制器,控制器經(jīng)過以下生命周期來完成請求:
beforeAction()
?方法;
beforeAction()
會跳過并且操作執(zhí)行會被取消; action execution will be cancelled.beforeAction()
?方法會觸發(fā)一個?beforeAction
?事件,在事件中你可以追加事件處理操作;afterAction()
?方法;
afterAction()
?方法會觸發(fā)一個?afterAction
?事件,在事件中你可以追加事件處理操作;在設(shè)計良好的應(yīng)用中,控制器很精練,包含的操作代碼簡短; 如果你的控制器很復(fù)雜,通常意味著需要重構(gòu),轉(zhuǎn)移一些代碼到其他類中。
歸納起來,控制器