Yii2 运行流程分析之 Controller 的 behaviors() 函数

1. 示例
class SiteController extends Controller
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'actions' => ['login', 'error', 'register', 'offline'],
                        'allow' => true,
                    ],
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ]
                ]
            ]
        ];
    }
}
2. 客户端请求后的运行流程

具体运行流程请参考 《Yii2 运行流程分析之 Application》

最终会在 yii\base\Module::runAction 中创建 controller, action
然后执行 $controller->runAction

public function runAction($route, $params = [])
{
    $parts = $this->createController($route);
    if (is_array($parts)) 
    {
        list($controller, $actionID) = $parts;
        Yii::$app->controller = $controller;
        $result = $controller->runAction($actionID, $params);
        ...
    }
    ...
}

runAction() 中的流程请参考 《Yii2 运行流程分析之 Controller》

yii\base\Controller::runAction
会执行 this->beforeAction() -> this->ensureBehaviors()
SiteController::behaviors() 中的行为绑定到 SiteController 上。

public function ensureBehaviors()
{
    if ($this->_behaviors === null) {
        $this->_behaviors = [];
        foreach ($this->behaviors() as $name => $behavior) {
            $this->attachBehaviorInternal($name, $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();
        }
        
        // 这个名为 access 的行为将会执行到这里
        $behavior->attach($this);
        $this->_behaviors[$name] = $behavior;
    }
    
    return $behavior;
}

$behaviors 实际上是 AccessControl 的对象,attach 是其基类 ActionFilter 中的函数。

# yii\base\ActionFilter::attach

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

将会执行 ActionFilter::beforeFilter

public function beforeFilter($event)
{
    ...
    $event->isValid = $this->beforeAction($event->action);
    ...
}
# yii\filters\AccessControl::beforeAction

public function beforeAction($action)
{
    $user = $this->user;
    $request = Yii::$app->getRequest();
    
    // 这些就是在 SiteController 中定义的规则
    foreach ($this->rules as $rule) 
    {
        if ($allow = $rule->allows($action, $user, $request)) 
        {
            return true;
        } 
        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;
}
3. 简述

简单的说就是会在执行 controller 中的 action (比如SiteController::actionIndex)之前,会先执行这些 behaviors, 如果没有通过, 则 action 不会继续执行下去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值