對於PHP的Yii架構中的Controller控制器的解析

來源:互聯網
上載者:User
這篇文章主要介紹了PHP的Yii架構中的Controller控制器,Yii作為MVC架構,其控制器部分的使用自然是重中之重,需要的朋友可以參考下

控制器是 MVC 模式中的一部分, 是繼承yii\base\Controller類的對象,負責處理請求和產生響應。 具體來說,控制器從應用主體接管控制後會分析請求資料並傳送到模型, 傳送模型結果到視圖,最後產生輸出響應資訊。

操作

控制器由 操作 組成,它是執行終端使用者請求的最基礎的單元,一個控制器可有一個或多個操作。

如下樣本顯示包含兩個操作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() 方法)中, 代碼首先根據請求模型ID載入 模型, 如果載入成功,會渲染名稱為view的視圖並顯示,否則會拋出一個異常。

在操作 create (定義為 actionCreate() 方法)中, 代碼相似. 先將請求資料填入模型, 然後儲存模型,如果兩者都成功,會跳轉到ID為新建立的模型的view操作,否則顯示提供使用者輸入的create視圖。

路由

終端使用者通過所謂的路由尋找到操作,路由是包含以下部分的字串:

  • 模型ID: 僅存在於控制器屬於非應用的模組;

  • 控制器ID: 同應用(或同模組如果為模組下的控制器)下唯一標識控制器的字串;

  • 操作ID: 同控制器下唯一標識操作的字串。

路由使用如下格式:

ControllerID/ActionID
如果屬於模組下的控制器,使用如下格式:

ModuleID/ControllerID/ActionID
如果使用者的請求地址為 http://hostname/index.php?r=site/index, 會執行site 控制器的index 操作。

建立控制器

在yii\web\Application網頁應用中,控制器應繼承yii\web\Controller 或它的子類。 同理在yii\console\Application控制台應用中,控制器繼承yii\console\Controller 或它的子類。 如下代碼定義一個 site 控制器:

namespace app\controllers;use yii\web\Controller;class SiteController extends Controller{}

控制器ID

通常情況下,控制器用來處理請求有關的資源類型,因此控制器ID通常為和資源有關的名詞。 例如使用article作為處理文章的控制器ID。

控制器ID應僅包含英文小寫字母、數字、底線、中橫杠和正斜杠, 例如 article 和 post-comment 是真是的控制器ID,article?, PostComment, admin\post不是控制器ID。

控制器Id可包含子目錄首碼,例如 admin/article 代表 yii\base\Application::controllerNamespace控制器命名空間下 admin子目錄中 article 控制器。 子目錄首碼可為英文大小寫字母、數字、底線、正斜杠,其中正斜杠用來區分多級子目錄(如panels/admin)。

控制器類命名

控制器ID遵循以下規則衍生控制器類名:

將用正斜杠區分的每個單詞第一個字母轉為大寫。注意如果控制器ID包含正斜杠,只將最後的正斜杠後的部分第一個字母轉為大寫;
去掉中橫杠,將正斜杠替換為反斜線;
增加Controller尾碼;
在前面增加yii\base\Application::controllerNamespace控制器命名空間.
下面為一些樣本,假設yii\base\Application::controllerNamespace控制器命名空間為 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/post2-comment應在@app/controllers/admin/Post2CommentController.php檔案中。

補充: 最後一個樣本 admin/post2-comment 表示你可以將控制器放在 yii\base\Application::controllerNamespace控制器命名空間下的子目錄中, 在你不想用 模組 的情況下給控制器分類,這種方式很有用。
控制器部署

可通過配置 yii\base\Application::controllerMap 來強制上述的控制器ID和類名對應, 通常用在使用第三方不能掌控類名的控制器上。

配置 應用配置 中的application configuration,如下所示:

[ 'controllerMap' => [  // 用類名申明 "account" 控制器  'account' => 'app\controllers\UserController',  // 用配置數組申明 "article" 控制器  'article' => [   'class' => 'app\controllers\PostController',   'enableCsrfValidation' => false,  ], ],]

預設控制器

每個應用有一個由yii\base\Application::defaultRoute屬性指定的預設控制器; 當請求沒有指定 路由,該屬性值作為路由使用。 對於yii\web\Application網頁應用,它的值為 'site', 對於 yii\console\Application控制台應用,它的值為 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'; }}

操作ID

操作通常是用來執行資源的特定操作,因此,操作ID通常為動詞,如view, update等。

操作ID應僅包含英文小寫字母、數字、底線和中橫杠,操作ID中的中橫杠用來分隔單詞。 例如view, update2, comment-post是真實的操作ID,view?, Update不是操作ID.

可通過兩種方式建立操作ID,內聯操作和獨立操作. An inline action is 內聯操作在控制器類中定義為方法;獨立操作是繼承yii\base\Action或它的子類的類。 內聯操作容易建立,在無需重用的情況下優先使用; 獨立操作相反,主要用於多個控制器重用,或重構為擴充。

內聯操作

內聯操作指的是根據我們剛描述的操作方法。

操作方法的名字是根據操作ID遵循如下規則衍生:

  • 將每個單詞的第一個字母轉為大寫;

  • 去掉中橫杠;

  • 增加action首碼.

  • 例如index 轉成 actionIndex, hello-world 轉成 actionHelloWorld。

注意: 操作方法的名字大小寫敏感,如果方法名稱為ActionIndex不會認為是操作方法, 所以請求index操作會返回一個異常,也要注意操作方法必須是公有的,私人或者受保護的方法不能定義成內聯操作。
因為容易建立,內聯操作是最常用的操作,但是如果你計劃在不同地方重用相同的操作, 或者你想重新分配一個操作,需要考慮定義它為獨立操作。

獨立操作

獨立操作通過繼承yii\base\Action或它的子類來定義。 例如Yii發布的yii\web\ViewAction和yii\web\ErrorAction都是獨立操作。

要使用獨立操作,需要通過控制器中覆蓋yii\base\Controller::actions()方法在action map中申明,如下例所示:

public function actions(){ return [  // 用類來申明"error" 操作  'error' => 'yii\web\ErrorAction',  // 用配置數組申明 "view" 操作  'view' => [   'class' => 'yii\web\ViewAction',   'viewPrefix' => '',  ], ];}

如上所示, actions() 方法返回鍵為操作ID、值為對應操作類名或數組configurations 的數組。 和內聯操作不同,獨立操作ID可包含任一字元,只要在actions() 方法中申明.

為建立一個獨立操作類,需要繼承yii\base\Action 或它的子類,並實現公有的名稱為run()的方法, run() 方法的角色和操作方法類似,例如:

<?phpnamespace app\components;use yii\base\Action;class HelloWorldAction extends Action{ public function run() {  return "Hello World"; }}

操作結果

操作方法或獨立操作的run()方法的傳回值非常重要,它表示對應操作結果。

傳回值可為 響應 對象,作為響應發送給終端使用者。

對於yii\web\Application網頁應用,傳回值可為任意資料, 它賦值給yii\web\Response::data, 最終轉換為字串來展示響應內容。
對於yii\console\Application控制台應用,傳回值可為整數, 表示命令列下執行的 yii\console\Response::exitStatus 退出狀態。
在上面的例子中,操作結果都為字串,作為響應資料發送給終端使用者,下例顯示一個操作通過 返迴響應對象(因為yii\web\Controller::redirect()方法返回一個響應對象)可將使用者瀏覽器跳轉到新的URL。

public function actionForward()

{ // 使用者瀏覽器跳轉到 http://example.com return $this->redirect('http://example.com');}

巨集指令引數

內聯操作的操作方法和獨立操作的 run() 方法可以帶參數,稱為巨集指令引數。 參數值從請求中擷取,對於yii\web\Application網頁應用, 每個巨集指令引數的值從$_GET中獲得,參數名作為鍵; 對於yii\console\Application控制台應用, 巨集指令引數對應命令列參數。

如下例,操作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']而不是字串.
如果想讓巨集指令引數接收數組值,需要指定$id為array,如下所示:

public function actionView(array $id, $version = null){ // ...}

現在如果請求為 http://hostname/index.php?r=post/view&id[]=123, 參數 $id 會使用數組值['123'], 如果請求為http://hostname/index.php?r=post/view&id=123, 參數 $id 會擷取相同數組值,因為無類型的'123'會自動轉成數組。

上述例子主要描述網頁應用的巨集指令引數,對於控制台應用,更多詳情請參閱控制台命令。

預設操作

每個控制器都有一個由 yii\base\Controller::defaultAction 屬性指定的預設操作, 當路由 只包含控制器ID,會使用所請求的控制器的預設操作。

預設操作預設為 index,如果想修改預設操作,只需簡單地在控制器類中覆蓋這個屬性,如下所示:

namespace app\controllers;use yii\web\Controller;class SiteController extends Controller{ public $defaultAction = 'home'; public function actionHome() {  return $this->render('home'); }}

控制器動作參數綁定
從版本 1.1.4 開始,Yii 提供了對自動動作參數綁定的支援。就是說,控制器動作可以定義命名的參數,參數的值將由 Yii 自動從 $_GET 填充。

為了詳細說明此功能,假設我們需要為 PostController 寫一個 create 動作。此動作需要兩個參數:

  • category:一個整數,代表文章(post)要發表在的那個分類的ID。

  • language:一個字串,代表文章所使用的語言代碼。

從 $_GET 中提取參數時,我們可以不再下面這種無聊的代碼了:

 class PostController extends CController  {    public function actionCreate()    {      if(isset($_GET['category']))       $category=(int)$_GET['category'];      else       throw new CHttpException(404,'invalid request');       if(isset($_GET['language']))       $language=$_GET['language'];      else       $language='en';       // ... fun code starts here ...    }  }

現在使用動作參數功能,我們可以更輕鬆的完成任務:

  class PostController extends CController  {    public function actionCreate($category, $language='en')    {      $category = (int)$category;      echo 'Category:'.$category.'/Language:'.$language;       // ... fun code starts here ...    }  }

注意我們在動作方法 actionCreate 中添加了兩個參數。這些參數的名字必須和我們想要從 $_GET 中提取的名字一致。當使用者沒有在請求中指定 $language 參數時,這個參數會使用預設值 en 。由於 $category 沒有預設值,如果使用者沒有在 $_GET 中提供 category 參數,將會自動拋出一個 CHttpException (錯誤碼 400) 異常。

從版本1.1.5開始,Yii已經支援數組的動作參數。使用方法如下:

  class PostController extends CController  {    public function actionCreate(array $categories)    {      // Yii will make sure $categories be an array    }  }

控制器生命週期

處理一個請求時,應用主體 會根據請求路由建立一個控制器,控制器經過以下生命週期來完成請求:

  • 在控制器建立和配置後,yii\base\Controller::init() 方法會被調用。

  • 控制器根據請求操作ID建立一個操作對象:

  • 如果操作ID沒有指定,會使用yii\base\Controller::defaultAction預設操作ID;

  • 如果在yii\base\Controller::actions()找到操作ID,會建立一個獨立操作;

  • 如果操作ID對應操作方法,會建立一個內聯操作;

  • 否則會拋出yii\base\InvalidRouteException異常。

  • 控制器按順序調用應用主體、模組(如果控制器屬於模組)、控制器的 beforeAction() 方法;

  • 如果任意一個調用返回false,後面未調用的beforeAction()會跳過並且操作執行會被取消; action execution will be cancelled.

  • 預設情況下每個 beforeAction() 方法會觸發一個 beforeAction 事件,在事件中你可以追加事件處理操作;

  • 控制器執行操作:

  • 請求資料解析和填入到巨集指令引數;

  • 控制器按順序調用控制器、模組(如果控制器屬於模組)、應用主體的 afterAction() 方法;

  • 預設情況下每個 afterAction() 方法會觸發一個 afterAction 事件,在事件中你可以追加事件處理操作;

  • 應用主體擷取操作結果並賦值給響應.

最佳實務

在設計良好的應用中,控制器很精練,包含的作業碼簡短; 如果你的控制器很複雜,通常意味著需要重構,轉移一些代碼到其他類中。

歸納起來,控制器:

  • 可訪問請求 資料;

  • 可根據請求資料調用 模型 的方法和其他服務元件;

  • 可使用視圖構造響應;

  • 不應處理應被模型處理的請求資料;

  • 應避免嵌入HTML或其他展示代碼,這些代碼最好在 視圖中處理.

以上就是本文的全部內容,希望對大家的學習有所協助,更多相關內容請關注topic.alibabacloud.com!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.