Yii2 理解filters

    • 版本
    • ActionFilter
    • AccessControl
    • AccessRule
    • VerbFilter
    • 其它

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 其它

其余暂未使用到, 有用到再添加

你可能感兴趣的:(Yii2 理解filters)