天天看點

yii基礎知識-

控制器

 是 CController 或其子類的執行個體。它在當使用者請求時由應用建立。 當一個控制器運作時,它執行所請求的動作,動作通常會引入所必要的模型并渲染相應的視圖。 

動作

 的最簡形式,就是一個名字以 

action

 開頭的控制器類方法。

控制器通常有一個預設的動作。當使用者的請求未指定要執行的動作時,預設動作将被執行。 預設情況下,預設的動作名為 

index

。它可以通過設定 CController::defaultAction 修改。

如下是一個控制器類所需的最簡代碼。由于此控制器未定義任何動作,對它的請求将抛出一個異常。

class SiteController extends CController
{
}      

1. 路由 

控制器和動作以 ID 識别。控制器 ID 是一種 'path/to/xyz' 的格式,對應相應的控制器類檔案

protected/controllers/path/to/XyzController.php

, 其中的标志 

xyz

 應被替換為實際的名字 (例如 

post

對應 

protected/controllers/PostController.php

). 動作 ID 是除去 

action

 字首的動作方法名。例如,如果一個控制器類含有一個名為 

actionEdit

 的方法,則相應的動作 ID 為 

edit

使用者以路由的形式請求特定的控制器和動作。路由是由控制器 ID 和動作 ID 連接配接起來的,兩者以斜線分割。 例如,路由 

post/edit

 代表 

PostController

 及其 

edit

 動作。預設情況下,URL

http://hostname/index.php?r=post/edit

 即請求此控制器和動作。

注意: 預設情況下,路由是大小寫敏感的,從版本 1.0.1 開始,可以通過設定應用配置中的CUrlManager::caseSensitive 為 false 使路由對大小寫不敏感。當在大小寫不敏感模式中時, 要確定你遵循了相應的規則約定,即:包含控制器類檔案的目錄名小寫,且 控制器映射 和 動作映射 中使用的鍵為小寫。

從 1.0.3 版本開始,應用可以含有 子產品(Module). 子產品中,控制器動作的路由格式為

moduleID/controllerID/actionID

 。 更多詳情,請閱讀 子產品相關章節.

2. 控制器執行個體化 

控制器執行個體在 CWebApplication 處理到來的請求時建立。指定了控制器 ID , 應用将使用如下規則确定控制器的類以及類檔案的位置。

  • 如果指定了 CWebApplication::catchAllRequest , 控制器将基于此屬性建立, 而使用者指定的控制器 ID 将被忽略。這通常用于将應用設定為維護狀态并顯示一個靜态提示頁面。
  • 如果在 CWebApplication::controllerMap 中找到了 ID, 相應的控制器配置将被用于建立控制器執行個體。
  • 如果 ID 為 

    'path/to/xyz'

    的格式,控制器類的名字将判斷為 

    XyzController

    , 相應的類檔案則為

    protected/controllers/path/to/XyzController.php

    。例如, 控制器 ID 

    admin/user

     将被解析為控制器類 

    UserController

    ,類檔案是 

    protected/controllers/admin/UserController.php

    。 如果類檔案不存在,将觸發一個 404 CHttpException 異常。

在使用了 子產品 (1.0.3 版後可用) 後,上述過程則稍有不同。 具體來說,應用将檢查此 ID 是否代表一個子產品中的控制器。如果是的話,子產品執行個體将被首先建立,然後建立子產品中的控制器執行個體。

3. 動作 

如前文所述,動作可以被定義為一個以 

action

 單詞作為字首命名的方法。而更進階的方式是定義一個動作類并讓控制器在收到請求時将其執行個體化。 這使得動作可以被複用,提高了可複用度。

要定義一個新動作類,可用如下代碼:

class UpdateAction extends CAction
{
    public function run()
    {
        // place the action logic here
    }
}      

為了讓控制器注意到這個動作,我們要用如下方式覆寫控制器類的actions() 方法:

class PostController extends CController
{
    public function actions()
    {
        return array(
            'edit'=>'application.controllers.post.UpdateAction',
        );
    }
}      

如上所示,我們使用了路徑别名 

application.controllers.post.UpdateAction

 指定動作類檔案為

protected/controllers/post/UpdateAction.php

.

通過編寫基于類的動作,我們可以将應用組織為子產品的風格。例如, 如下目錄結構可用于組織控制器相關代碼:

protected/
    controllers/
        PostController.php
        UserController.php
        post/
            CreateAction.php
            ReadAction.php
            UpdateAction.php
        user/
            CreateAction.php
            ListAction.php
            ProfileAction.php
            UpdateAction.php
      

動作參數綁定

從版本 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;
 
        // ... fun code starts here ...
    }
}
      

注意我們在動作方法 

actionCreate

 中添加了兩個參數。 這些參數的名字必須和我們想要從 

$_GET

 中提取的名字一緻。 當使用者沒有在請求中指定 

$language

 參數時,這個參數會使用預設值 

en

 。 由于 

$category

 沒有預設值,如果使用者沒有在 

$_GET

 中提供 

category

 參數, 将會自動抛出一個 CHttpException (錯誤代碼 400) 異常。 Starting from version 1.1.5, Yii also supports array type detection for action parameters. This is done by PHP type hinting using the syntax like the following:

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

That is, we add the keyword 

array

 in front of 

$categories

 in the method parameter declaration. By doing so, if 

$_GET['categories']

 is a simple string, it will be converted into an array consisting of that string.

Note: If a parameter is declared without the 

array

 type hint, it means the parameter must be a scalar (i.e., not an array). In this case, passing in an array parameter via 

$_GET

 would cause an HTTP exception.

4. 過濾器 

過濾器是一段代碼,可被配置在控制器動作執行之前或之後執行。例如, 通路控制過濾器将被執行以確定在執行請求的動作之前使用者已認證身份驗證;性能過濾器可用于測量控制器執行所用的時間。

一個動作可以有多個過濾器。過濾器執行順序為它們出現在過濾器清單中的順序。過濾器可以阻止動作及後面其他過濾器的執行

過濾器可以定義為一個控制器類的方法。方法名必須以 

filter

 開頭。例如,現有的 

filterAccessControl

 方法定義了一個名為 

accessControl

 的過濾器。 過濾器方法必須為如下結構:

public function filterAccessControl($filterChain)
{
    // 調用 $filterChain->run() 以繼續後續過濾器與動作的執行。
}      

其中的 

$filterChain

 (過濾器鍊)是一個 CFilterChain 的執行個體,代表與所請求動作相關的過濾器清單。在過濾器方法中, 我們可以調用 

$filterChain->run()

 以繼續執行後續過濾器和動作。

過濾器也可以是一個 CFilter 或其子類的執行個體。如下代碼定義了一個新的過濾器類:

class PerformanceFilter extends CFilter
{
    protected function preFilter($filterChain)
    {
        // 動作被執行之前應用的邏輯
        return true; // 如果動作不應被執行,此處傳回 false
    }
 
    protected function postFilter($filterChain)
    {
        // 動作執行之後應用的邏輯
    }
}      
class PostController extends CController
{
    ......
    public function filters()
    {
        return array(
            'postOnly + edit, create',
            array(
                'application.filters.PerformanceFilter - edit, create',
                'unit'=>'second',
            ),
        );
    }
}