首頁  >  文章  >  後端開發  >  Yii框架官方指南系列7—基礎知識:控制器

Yii框架官方指南系列7—基礎知識:控制器

黄舟
黄舟原創
2017-02-11 09:34:181379瀏覽



控制器是 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。

注意: 在 1.0.3 版本之前,控制器 ID 的格式為 path.to.xyz ,而不是 path/to/xyz。

使用者以路由的形式請求特定的控制器和動作。路由是由控制器 ID 和動作 ID 連接起來的,兩者以斜線分割。 例如,路由post/edit 代表PostController 及其edit動作。預設情況下,URL http://www.php.cn/即請求此控制器和動作。

注意: 預設情況下,路由是大小寫敏感的,從版本 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() 

為了讓控制器注意到這個動作,我們要用以下方式覆蓋控制器類的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) 异常。从版本1.1.5开始, Yii还支持数组类型的动作参数绑定。 这是通过PHP的类型约束来实现的,语法如下:


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

也就是说我们在方法参数声明里的$categories之前添加了array关键字。这样的话,如果$_GET['categories']只是一个简单的字符串,它将会被转化为一个包含该字符串的数组。

注意: 如果参数声明没有加上 array 类型约束, 意味着参数必须是标量 (i.e., not an array)。这种情况下,通过 $_GET 传入一个数组参数将会引发HTTP异常。

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)
    {
        // 动作执行之后应用的逻辑
    }
}

要对动作应用过滤器,我们需要覆盖 CController::filters() 方法。此方法应返回一个过滤器配置数组。例如:


class PostController extends CController
{
    ......
    public function filters()
    {
        return array(
            'postOnly + edit, create',
            array(
                'application.filters.PerformanceFilter - edit, create',
                'unit'=>'second',
            ),
        );
    }
}

上述代码指定了两个过滤器: postOnly 和 PerformanceFilter。 postOnly 过滤器是基于方法的(相应的过滤器方法已在 CController 中定义); 而 performanceFilter 过滤器是基于对象的。路径别名application.filters.PerformanceFilter 指定过滤器类文件是protected/filters/PerformanceFilter。我们使用一个数组配置 PerformanceFilter ,这样它就可被用于初始化过滤器对象的属性值。此处 PerformanceFilter 的 unit 属性值将被初始为 second。

使用加减号,我们可指定哪些动作应该或不应该应用过滤器。上述代码中, postOnly 应只被应用于 edit 和 create动作,而 PerformanceFilter 应被应用于 除了 edit 和 create 之外的动作。 如果过滤器配置中没有使用加减号,则此过滤器将被应用于所有动作。

附图:控制器的run方法执行过程

Yii框架官方指南系列7—基礎知識:控制器

以上就是Yii框架官方指南系列7——基础知识:控制器的内容,更多相关内容请关注PHP中文网(www.php.cn)!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn