Yii2 分析Controller::behaviors 觸發過程

1 版本

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

2 示例

AccessControl是框架自帶的,位於yii\filters目錄下

class SiteController extends Controller
{
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'actions' => ['login', 'error', 'register', 'offline'],
                        'allow' => true,
                    ],
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ]
                ]
            ]
        ];
    }
}

3 客戶端請求後的運行流程

具體運行流程請參考Yii2分析運行流程
http://blog.csdn.net/alex_my/article/details/54142711

最終會在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中的流程請參考Yii理解Controller
http://blog.csdn.net/alex_my/article/details/54138744

在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);
    ...
}

AccessControl重載了beforeAction函數

// 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;
}

4 簡述

簡單的說就是會在執行controller中的action(比如SiteController::actionIndex)之前, 會先執行這些behaviors, 如果沒有通過, 則action不會繼續執行下去。

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