2014-12-20 09:39:42 28233次浏览 1条回答 2 悬赏 5 金钱
class CustomController extends ActiveController
{
    public $modelClass = 'app\models\Custom';
    // public $serializer = [
    //     'class' => 'yii\rest\Serializer',
    //     'collectionEnvelope' => 'items',
    // ];

    public function behaviors()
	{
	    return ArrayHelper::merge(parent::behaviors(), [
	        'authenticator' => [
	            'class' => QueryParamAuth::className(),
	        ],
	        'rateLimiter' => [
	            'class' => RateLimiter::className(),
	            'enableRateLimitHeaders' => false,
	        ],
	    ]);
	}

}

源代码中,控制器的behaviors是在哪里处理的?
比如说:QueryParamAuth对象是在哪里实例化的?并且调用了authenticator()方法。

最佳答案

  • fly020212 发布于 2014-12-20 12:29 举报

    你给的例子,其实不能完全说明 behaviors 的行为,这里是 filter 的行为,但 filteryii2yii 中的实现不一样,yii2 中的 filter 是特殊的 behavior ,被框架多加了一层的处理,这里我只说明下 filter 的调用, 普通的 behavior 我暂时还没有用到,不清楚

    一句话,QueryParamAuthauthenticator() 方法,是在 Controller 调用 beforeAction 时触发的,你可以在 Controller 复写 beforeAction 方法为空操作,看看还会不会调用。

    在底层的 Controller 中,beforeAction 执行了 $this->trigger(self::EVENT_BEFORE_ACTION, $event) 触发了 EVENT_BEFORE_ACTION 事件,在 yii\base\Componenttrigger 会首先 ensureBehaviors(),把 behaviors() 定义的行为附加到 Controller

    /**
     * Makes sure that the behaviors declared in [[behaviors()]] are attached to this component.
     */
    public function ensureBehaviors()
    {
        if ($this->_behaviors === null) {
            $this->_behaviors = [];
            foreach ($this->behaviors() as $name => $behavior) {
                $this->attachBehaviorInternal($name, $behavior);
            }
        }
    }
    /**
     * Attaches a behavior to this component.
     * @param string|integer $name the name of the behavior. If this is an integer, it means the behavior
     * is an anonymous one. Otherwise, the behavior is a named one and any existing behavior with the same name
     * will be detached first.
     * @param string|array|Behavior $behavior the behavior to be attached
     * @return Behavior the attached behavior.
     */
    private function attachBehaviorInternal($name, $behavior)
    {
        if (!($behavior instanceof Behavior)) {
            $behavior = Yii::createObject($behavior);
        }
        if (is_int($name)) {
            $behavior->attach($this);
            $this->_behaviors[] = $behavior;
        } else {
            if (isset($this->_behaviors[$name])) {
                $this->_behaviors[$name]->detach();
            }
            $behavior->attach($this);
            $this->_behaviors[$name] = $behavior;
        }
        return $behavior;
    }
    

    }

    QueryParamAuth 最终继承自 ActionFilter 的,来看看 ActionFilterattach 时会做什么

    /**
     * @inheritdoc
     */
    public function attach($owner)
    {
        $this->owner = $owner;
        $owner->on(Controller::EVENT_BEFORE_ACTION, [$this, 'beforeFilter']);
    }
    

    会在 Controller 上绑定一个 EVENT_BEFORE_ACTION 事件,行为是执行自己的 beforeFilter 方法

    /**
     * @param ActionEvent $event
     */
    public function beforeFilter($event)
    {
        if (!$this->isActive($event->action)) {
            return;
        }
    
        $event->isValid = $this->beforeAction($event->action);
        if ($event->isValid) {
            // call afterFilter only if beforeFilter succeeds
            // beforeFilter and afterFilter should be properly nested
            $this->owner->on(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter'], null, false);
        } else {
            $event->handled = true;
        }
    }
    

    到这里,你看到了,ActionFilter 最终会执行自己的 beforeAction 方法,当然这可不是 Controller 中的 beforeAction 方法,还会处理些前置check,如 exceptonly 检测,这个 beforeAction 正是你写 filter 时需要复写的一个方法,至于 QueryParamAuthauthenticator() 方法,自己可以接着走代码

    入口是 ControllerbeforeAction 方法,可以自己走一遍源代码,就这些

    , , , , 觉得很赞
    没有找到数据。
您需要登录后才可以回答。登录 | 立即注册
jayce
主管

jayce

注册时间:2014-12-10
最后登录:2015-06-09
在线时长:48小时16分
  • 粉丝5
  • 金钱175
  • 威望0
  • 积分655

热门问题