Yii2 理解filters

1 版本

// yii\BaseYii\getVersion
public static function getVersion()
{
    return '2.0.10';
}

2 ActionFilter

動作過濾器的基類, 有兩個重要的變量, 這兩個變量都是存儲action id

$except: 過濾器將不會應用於在這裏面出現的action,即使出現在$only中,過濾器也不會有效。
$only: 如果爲空, 該過濾器會應用於其owner下的所有過濾器。如果不爲空, 則只應用於在這裏面出現的action。

以上規則見代碼:

protected function isActive($action)
{
    $id = $this->getActionId($action);
    // 如果爲空, 過濾器判斷爲有效
    if (empty($this->only)) 
    {
        $onlyMatch = true;
    } 
    else 
    {
        // 判斷action是否出現在$only中
        $onlyMatch = false;
        foreach ($this->only as $pattern) 
        {
            if (fnmatch($pattern, $id)) 
            {
                $onlyMatch = true;
                break;
            }
        }
    }
    // --------- 攔路虎: 在這裏面出現,即使前面判斷過濾器有效, 也會變爲無效
    $exceptMatch = false;
    foreach ($this->except as $pattern) 
    {
        if (fnmatch($pattern, $id)) 
        {
            $exceptMatch = true;
            break;
        }
    }

    return !$exceptMatch && $onlyMatch;
}

3 AccessControl

該過濾器提供簡單的訪問控制

$user: 將會指向User,用於判斷玩家的情況, 比如 $user->getIsGuest()判斷玩家是否是遊客。
$denyCallback: 如果沒有通過過濾器, 將會指向denyCallback指向的回調函數, 如果沒有設置,就會讀取默認的denyAccess
protected function denyAccess($user)
{
    // 如果是遊客, 則跳珠到登陸界面
    if ($user->getIsGuest()) 
    {
        // 如果沒有定義登陸界面,則會報異常
        $user->loginRequired();
    } 
    else 
    {
        throw new ForbiddenHttpException(Yii::t('yii', 'You are not allowed to perform this action.'));
    }
}
$ruleConfig: 默認的規則,指向yii\filters\AccessRule, 這個規則在後文講述
$rules: 自定義的規則, 將會和$ruleConfig進行合併, 如果有相同項,會覆蓋$ruleConfig
// 基類Object的構造函數中調用
public function init()
{
    parent::init();
    $this->user = Instance::ensure($this->user, User::className());
    foreach ($this->rules as $i => $rule) 
    {
        if (is_array($rule)) 
        {
            // 如果沒有更改$ruleConfig變量, 這裏將rule配置一一生成AccessRule對象
            $this->rules[$i] = Yii::createObject(array_merge($this->ruleConfig, $rule));
        }
    }
}

客戶端在請求的時候,會創建$controller, $action,然後執行$controller->runAction($action, …), 在runAction中,將會先執行過濾器的beforeAction,在這裏也就是yii\filters\AccessController::beforeAction

具體流程見Yii2 分析Controller::behaviors 觸發過程
http://blog.csdn.net/alex_my/article/details/54172619

public function beforeAction($action)
{
    $user = $this->user;
    $request = Yii::$app->getRequest();

    foreach ($this->rules as $rule) 
    {
        // --------------- $rule->allows將在下文分析
        if ($allow = $rule->allows($action, $user, $request)) 
        {
            return true;
        } 
        // --------------- 如果有定義denyCallback,則調用
        // --------------- 否則調用默認的denyAccess
        elseif ($allow === false) 
        {
            if (isset($rule->denyCallback)) 
            {
                call_user_func($rule->denyCallback, $rule, $action);
            } 
            elseif ($this->denyCallback !== null)
            {
                call_user_func($this->denyCallback, $rule, $action);
            } 
            else 
            {
                $this->denyAccess($user);
            }
            return false;
        }
    }
    if ($this->denyCallback !== null) 
    {
        call_user_func($this->denyCallback, null, $action);
    } 
    else 
    {
        $this->denyAccess($user);
    }
    return false;
}

4 AccessRule

該類是AccessController的規則對象,其成員變量和AccessController中的rules合併,且相同鍵名的會被後者覆蓋

$allow: 如果爲true, 如果規則驗證通過, 則表示該規則通過驗證。如果爲false,表示該規則一定不能通過。
$actions: 表示該規則應用於哪些action中, 如果爲空, 則表示應用於所有的action中
$controllers: 表示該規則應用於哪些controller中,假設有BaseController::Controller做爲自定義的控制器基類,在BaseController::behaviors可以設置規則只用於哪些派生類中:
public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'rules' => [
                [
                    'actions' => ['login', 'error', 'register', 'offline'],
                    'allow' => true,
                    'controllers' => [
                        'site'
                    ]
                ]
            ]
        ]
    ];
$roles: 指定該規則應用於哪些角色, 比如在rules中添加roles => ['Wang']
有兩個特殊的角色:
?: 表示未登陸的遊客
@: 表示已登陸的角色
$ips: 驗證ip
$verbs: 指定該規則應用於哪些請求方法,比如GET, POST
$matchCallback: 通過調用自定義的函數來判斷規則是否通過
$denyCallback: 表示驗證未通過將會調用的函數

驗證過程:

public function allows($action, $user, $request)
{
    if ($this->matchAction($action)
        && $this->matchRole($user)
        && $this->matchIP($request->getUserIP())
        && $this->matchVerb($request->getMethod())
        && $this->matchController($action->controller)
        && $this->matchCustom($action)
    ) 
    {
        return $this->allow ? true : false;
    } 
    else 
    {
        return null;
    }
}

5 VerbFilter

用於驗證http請求的方法

public function behaviors()
{
    return [
        [
            'class' => VerbFilter::className(),
            // ---------- 指定action的訪問規則
            'actions' => [
                'create' => ['get', 'post'],
                'delete' => ['post'],
                'upload'=>['post'],
                // 其它的都是用get
                '*' => ['get']
            ]
        ]
    ];
}

該過濾器將會執行EVENT_BEFORE_ACTION,在動作執行前進行判斷, 驗證未通過,則action不會繼續執行下去。

6 其它

其餘暫未使用到, 有用到再添加

發佈了118 篇原創文章 · 獲贊 68 · 訪問量 57萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章