看一个过滤器的问题

今天不讲内容,仅仅分享一下混乱的beforeAction,希望对各位有所帮助。

昨天发文后,某同学私下问的一个问题,我简单描述一下。

配置yii2-admin组件的时候,有一项关于行为的配置,如下

1
2
3
4
5
6
7
'as access' => [
'class' => 'mdm\admin\components\AccessControl',
'allowActions' => [
//这里是允许访问的action
'*'
]
],

之前配置过yii2-admin组件的应该都不陌生,没配置过的也没关系,看主要问题。

在上文介绍的执行请求过程中,这个行为它是从哪一步开始执行的,mdm\admin\components\AccessControl::beforeAction为什么会自动执行,为什么我给一个继承自 yii\base\Behavior 的行为添加的beforeAction 方法不会自动执行呢?

首先能这么问,肯定思考了,动手实践了,这很好,也希望大家在阅读的过程中,多多分析,多多留言。

来看一下这个问题。

上文我们在介绍 yii\base\Controller::runAction方法时说过,调用controller级别的beforeAction事件,不知道各位还有没有印象。

这里说的controller级别的beforeAction事件,指的是yii\base\Controller::beforeAction方法内触发的 yii\base\Controller::EVENT_BEFORE_ACTION事件。

大家看一下yii\base\Controller::beforeAction 方法就明白我这话的意思了。

1
2
3
4
5
6
public function beforeAction($action)
{
$event = new ActionEvent($action);
$this->trigger(self::EVENT_BEFORE_ACTION, $event);
return $event->isValid;
}

我们回过头来看一下 mdm\admin\components\AccessControl 类的父类

1
2
3
class AccessControl extends \yii\base\ActionFilter 
{
}

yii\base\ActionFilter,一种特殊的行为类,又称为过滤器。

过滤器是怎么跟 mdm\admin\components\AccessControl::beforeAction 扯到一块的呢?

前面分析行为的时候我们说过,为应用实例 yii\web\Application 配置的行为 “as “ + 行为名称,在应用预初始化阶段,其指向的行为类的attach方法都会被自动调用,不明白我在说啥的可以回去再看看行为一节。

也就是说 mdm\admin\components\AccessControl 的父类yii\base\ActionFilter::attach方法会在应用预初始化的时候自动调用。

yii\base\ActionFilter::attach方法代码如下

1
2
3
4
5
public function attach($owner)
{
$this->owner = $owner;
$owner->on(Controller::EVENT_BEFORE_ACTION, [$this, 'beforeFilter']);
}

这里是为yii\base\Controller::EVENT_BEFORE_ACTION注册事件,对应的事件处理程序是

1
yii\base\ActionFilter::beforeFilter。

注意哦,这个阶段仅仅是为 yii\base\Controller 注册事件 EVENT_BEFORE_ACTION。

有同学好像明白了什么。

yii\base\Controller::runAction 调用controller级别的beforeAction事件 ,继而触发 yii\base\Controller::EVENT_BEFORE_ACTION 事件,即在这一步调用了 yii\base\ActionFilter::beforeFilter。

yii\base\ActionFilter::beforeFilter 做了什么,我们注意到该方法中的一句代码

1
$this->beforeAction($event->action);

$this 这里指的是 mdm\admin\components\AccessControl,所以这里就直接调用了 mdm\admin\components\AccessControl::beforeAction 。

同样,yii\base\Controller::EVENT_AFTER_ACTION 事件也是如此。

下面简单的梳理一下前后顺序:

…… => yii\base\ActionFilter::attach => …… => yii\base\Module::beforeAction => yii\base\ActionFilter::beforeFilter => mdm\admin\components\AccessControl::beforeAction => yii\web\Controller::beforeAction => yii\base\Controller::beforeAction => ……