yii2 請求處理過程解析

所有的迷惑都會在源碼中得到解答
來一瀏覽器的請求發送到yii時是如何被變更爲對應的controller=>action進行處理的呢??
一言不合上代碼,清除處理主要在web\application類中處理的


public function handleRequest($request)
{
    if (empty($this->catchAll)) {
        list ($route, $params) = $request->resolve();
    } else {
        $route = $this->catchAll[0];
        $params = $this->catchAll;
        unset($params[0]);
    }
    try {
        Yii::trace("Route requested: '$route'", __METHOD__);
        $this->requestedRoute = $route;
        $result = $this->runAction($route, $params);
        if ($result instanceof Response) {
            return $result;
        } else {
            $response = $this->getResponse();
            if ($result !== null) {
                $response->data = $result;
            }

            return $response;
        }
    } catch (InvalidRouteException $e) {
        throw new NotFoundHttpException(Yii::t('yii', 'Page not found.'), $e->getCode(), $e);
    }
}

而對於解析則是在$request->resolve當中進行的

public function resolve()
{
    $result = Yii::$app->getUrlManager()->parseRequest($this);

    if ($result !== false) {
        list ($route, $params) = $result;
        if ($this->_queryParams === null) {
            $_GET = $params + $_GET; // preserve numeric keys
        } else {
            $this->_queryParams = $params + $this->_queryParams;
        }
        return [$route, $this->getQueryParams()];
    } else {
        throw new NotFoundHttpException(Yii::t('yii', 'Page not found.'));
    }
}

看到了吧,還得繼續跟,解析是在parseRequest中進行的,這個parseRequest函數很長,不過我們不用看前半部分哈哈

public function parseRequest($request)
{
    if ($this->enablePrettyUrl) {
        $pathInfo = $request->getPathInfo();
        /* @var $rule UrlRule */
        foreach ($this->rules as $rule) {
            if (($result = $rule->parseRequest($this, $request)) !== false) {
                return $result;
            }
        }

        if ($this->enableStrictParsing) {
            return false;
        }

        Yii::trace('No matching URL rules. Using default URL parsing logic.', __METHOD__);

        // Ensure, that $pathInfo does not end with more than one slash.
        if (strlen($pathInfo) > 1 && substr_compare($pathInfo, '//', -2, 2) === 0) {
            return false;
        }

        $suffix = (string) $this->suffix;
        if ($suffix !== '' && $pathInfo !== '') {
            $n = strlen($this->suffix);
            if (substr_compare($pathInfo, $this->suffix, -$n, $n) === 0) {
                $pathInfo = substr($pathInfo, 0, -$n);
                if ($pathInfo === '') {
                    // suffix alone is not allowed
                    return false;
                }
            } else {
                // suffix doesn't match
                return false;
            }
        }

        return [$pathInfo, []];
    } else {
        Yii::trace('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__);
        //我們需要看的就這一點了!!!
        $route = $request->getQueryParam($this->routeParam, '');
        if (is_array($route)) {
            $route = '';
        }

        return [(string) $route, []];
    }
}

就快要到了,這裏需要mark一下,注意傳遞進去的參數是$this->routeParam就是"r"看下getQueryParam函數的處理

public function getQueryParam($name, $defaultValue = null)
{
    $params = $this->getQueryParams();
    return isset($params[$name]) ? $params[$name] : $defaultValue;
}
public function getQueryParams()
{
    if ($this->_queryParams === null) {
        return $_GET;
    }
    return $this->_queryParams;
}
好了,終於跟到底了,發現了嗎?getQueryParam做了什麼???就是把$_GET請求中明爲$this->touteParam的參數取了出來!!!!!
其實取得就是$_GET['r'] 這一層層跟的火大。
返回的值就是site/login這下知道了吧
好了,繼續看handleRequest還沒執行完呢,接下來看的是web\application的runAction,傳遞進去的參數就是site\login
public function runAction($route, $params = [])
{
    $parts = $this->createController($route);
    if (is_array($parts)) {
        /* @var $controller Controller */
        list($controller, $actionID) = $parts;
        $oldController = Yii::$app->controller;
        Yii::$app->controller = $controller;

        $result = $controller->runAction($actionID, $params);

        Yii::$app->controller = $oldController;

        return $result;
    } else {
        $id = $this->getUniqueId();
        throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".');
    }
}

繼續看,這個createController
public function createController($route)
{
    if ($route === '') {
        $route = $this->defaultRoute;
    }


    // double slashes or leading/ending slashes may cause substr problem
    $route = trim($route, '/');
    if (strpos($route, '//') !== false) {
        return false;
    }

    if (strpos($route, '/') !== false) {
        list ($id, $route) = explode('/', $route, 2);
    } else {
        $id = $route;
        $route = '';
    }

    // module and controller map take precedence
    if (isset($this->controllerMap[$id])) {
        //如果在controllerMap中定義了該controller Id,則直接創建對應的對象,也即r對應的值不一定是controller的類的名字
        $controller = Yii::createObject($this->controllerMap[$id], [$id, $this]);
        return [$controller, $route];
    }
    $module = $this->getModule($id);
    if ($module !== null) {
        return $module->createController($route);
    }

    if (($pos = strrpos($route, '/')) !== false) {
        $id .= '/' . substr($route, 0, $pos);
        $route = substr($route, $pos + 1);
    }

    $controller = $this->createControllerByID($id);
    if ($controller === null && $route !== '') {
        $controller = $this->createControllerByID($id . '/' . $route);
        $route = '';
    }

    return $controller === null ? false : [$controller, $route];
}
返回的是controller對象和actionId,前兩個if就是判斷合法性,第三個if將字符串進行了根據/進行了分離 $id  ="site"  $route="login"
如果controllerMap中沒有定義key的'site'的配置,這裏可以由我們自己進行處理,那麼就使用siteController類作爲本次處理的controller,而$route則是action的操作了返回之後再module的runAction當中的runAction是調用創建的controller的runAction,這一部分就是我們自己編寫的處理過程了




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章