本節包含以下方面的內容
- 基本概念
- 路由
- 默認路由
- 動作的參數
- 在動作中定義參數
- 從請求(request)中獲取參數
- 獨立動作
- 動作過濾器(Action Filters)
- 捕獲所有的請求
- 自定義響應類
控制器(Control)是應用程序中最關鍵的部分之一,它決定了如何處理傳遞進來的請求(Request),以及生成相應的響應(Response)。
大部分的控制器都會處理一個Http的請求,然后返回Html或者Json或者Xml格式的數據作為響應。
1、基本概念
控制器文件一般在應用程序的controllers目錄下面,文件命名規則為XXXController.php,其中XXX可以為任意的名稱,后面的Controller是固定格式,不能少一個單詞。
一個基本的控制器的定義要從yii\web\Controller繼承,如
namespace app\controllers; use yii\web\Controller; class SiteController extends Controller { public function actionIndex() { // will render view from "views/site/index.php" return $this->render('index'); } public function actionTest() { // will just print "test" to the browser return 'test'; } }
一般來說控制器里面定義的動作都是 actionSomething格式的公共的方法。輸出的數據可以是一個字符串或者yii\web\Response的實例。
動作輸出的結果將會由 response組件處理並轉換成不同的數據格式如JSON等。默認情況下是沒有對動作的執行結果進行處理的。
2、路由
每個控制器里面的動作都有一個相對應的路由,在上面的例子中actionIndex有一個對應的site/index路由,actionTest對應的路由是site/test。在這個路由中site為控制器的id,test為動作的id。
一般情況下可以通過這個格式的URL來訪問控制器和動作。http://example.com/?r=controller/action。當然你可以完全自定義url的格式(URL Management.)。
如果控制器是在一個模塊里面,那么對應的路由格式為module/controller/action。
控制器還可以存在於應用程序或者模塊的控制器目錄下面的子目錄里。這種路由的格式前面就需要加上相應的目錄名稱。例如在controllers/admin下面有個UserController,那么動作actionIndex相應的路由為admin/user/index。admin/user為控制器的Id.
如果模塊或者控制器或者動作都沒有找到,Yii將會返回一個"not found" 頁面,並且返回的Http代碼為404。
注意:
如果模塊名稱或者控制器名稱或者動作名稱是用的駱駝格式的命名寫法,那么路由里面的每個大寫單詞之間都要用 “-”來連接。如
DateTimeController::actionFastForward 相應的路由為 date-time/fast-forward。
1、默認路由
如果一個URl沒有指定路由,如http://www.yiifans.com,那么Yii將會使用默認的路由。
Yii在應用程序里面定義了默認的路由。默認的路由為site由yii\web\Application:: $defaultRoute定義,即控制器SiteController將會被使用。
有默認的路由也就會有默認的動作了。每個控制器都有一個默認的動作。如果在URL中沒有指定動作的話,那么將會調用默認的動作。
默認的動作名為index,在yii\base\Controller:: $defaultAction中定義。
如http://www.yiifans.com/?r=site,只指定了路由為site,那么將會使用默認的動作index,即將會調用SiteController里面的actionIndex方法
3、動作參數
就像上面提到的一樣,一個簡單的動作就是一個以actionXXX格式命名的公開的方法。那么動作如何從Http的請求中獲取想要的參數呢?
1、動作中定義參數
在定義動作的時候直接定義參數。這個參數的值會直接從$_GET里面獲取對應的值。也就是說動作里面定義的參數只能從$_GET里面獲取值。
namespace app\controllers; use yii\web\Controller; class BlogController extends Controller { public function actionView($id, $version = null) { $post = Post::findOne($id); $text = $post->text; if ($version) { $text = $post->getHistory($version); } return $this->render('view', [ 'post' => $post, 'text' => $text, ]); } }
如上所示動作view定義了兩個參數$id和$version。其中$version的默認值為null。
我們可以通過http://www.yiifans.com/?r=blog/view&id=42或者http://www.yiifans.com/?r=blog/view&id=42&version=3來訪問。
在第一種情況下由於沒有version參數,將會使用在定義的時候的默認值。而在第二種情況下actionView里面將得到相應的值,$id為42,$version為3.
如果在動作里面定義的參數沒有默認值,而訪問的URL里面又沒有相對應的變量,那么會拋一個異常。如http://www.yiifans.com/?r=blog/view由於沒有在URL中指定id,在action的定義中又沒有默認的值,所以將會拋一個異常。
2、從請求(request)中獲取參數
如果要從POST中獲取參數或者GET里面的參數太多,還可以c通過Yii里面的request對象來獲取相關的參數,可以通過\Yii:: $app->request來訪問。如下代碼所示:
namespace app\controllers; use yii\web\Controller; use yii\web\HttpException; class BlogController extends Controller { public function actionUpdate($id) { $post = Post::findOne($id); if (!$post) { throw new NotFoundHttpException(); } if (\Yii::$app->request->isPost) { $post->load(Yii::$app->request->post()); if ($post->save()) { return $this->redirect(['view', 'id' => $post->id]); } } return $this->render('update', ['post' => $post]); } }
4、獨立動作(action)
如果一個動作是通用的,要想在其它的控制器中重復使用,可以把這個動作放在一個單獨的文件中實現。
創建actions/Page.php
namespace app\actions; class Page extends \yii\base\Action { public $view = 'index'; public function run() { return $this->controller->render($view); } }
使用:
class SiteController extends \yii\web\Controller { public function actions() { return [ 'about' => [ 'class' => 'app\actions\Page', 'view' => 'about', ], ]; } }
actions()返回的是一個name-value數組,name為動作(action)的名稱,class為實現的動作的類,view為action要使用的模板文件。
訪問:
http://www.yiifans.com/?r=site/about
5、動作過濾器(Action Filters)
你可能需要對控制器里面的某些動作應用一些過濾器,例如判斷對當前動作的訪問權限,對動作返回結果進一步處理等。
動作過濾器是yii\base\ActionFilter的子類的實例。
要使用動作過濾器,可以把它像行為一樣附加在控制器或者模塊上。下面這個例子實現了對index動作的緩存
public function behaviors() { return [ 'httpCache' => [ 'class' => \yii\filters\HttpCache::className(), 'only' => ['index'], 'lastModified' => function ($action, $params) { $q = new \yii\db\Query(); return $q->from('user')->max('updated_at'); }, ], ]; }
你還可以同時使用多個動作過濾器。他們將按照在behaviors()里面定義的先后順序依次執行。如果其中的任意一個過濾器取消了動作的執行,那么當前過濾器后面的所有的過濾器將不會被執行。同時這個動作也不會執行。
當附加一個過濾器到控制器的時候,這個過濾器可以應該於當前控制器里面所有的動作。如果附加到模塊或者應用程序,這個過濾器就可以應用於這個模塊或者應用程序下面的所有的動作。
要創建動作過濾器,從yii\base\ActionFilter繼承並實現beforeAction() 和afterAction()方法。beforAction將在action執行之前執行,同理afterAction將在action執行之后執行。如果beforeAction()返回false,那么當前過濾器后面的所有的過濾器都將不會被執行,並且action也不會被執行。
authorization 章節介紹了yii\filters\AccessControl 過濾器,caching章節介紹了yii\filters\PageCache和yii\filters\HttpCache過濾器。在實現自定義的過濾器的時候可以參考這些內置的過濾器的實現。
6、捕獲所有的請求
有時候用一個控制器和動作來處理所有的請求是非常有用的。例如在網站在處於維護的情況下顯示一個通知等。如果要實現這個功能只需要設置應用程序的catchAll屬性就可以了。有兩種方式可以設置catchAll屬性,動態的設置或者在配置文件里面設置。
return [ 'id' => 'basic', 'basePath' => dirname(__DIR__), // ... 'catchAll' => [ // <-- here 'offline/notice', 'param1' => 'value1', 'param2' => 'value2', ], ]
上面的例子是通過配置文件來設置的。offline/notice的意思是指使用OfflineController::actionNotice(),param1 和 param2 是傳遞給notice動作方法的參數。
7、自定義響應類
一般在動作執行完后會返回一個render之后的html內容,當然還可以返回特定的響應
namespace app\controllers; use yii\web\Controller; use app\components\web\MyCustomResponse; #extended from yii\web\Response class SiteController extends Controller { public function actionCustom() { /* * do your things here * since Response in extended from yii\base\Object, you can initialize its values by passing in * __constructor() simple array. */ return new MyCustomResponse(['data' => $myCustomData]); } }