所有的迷惑都会在源码中得到解答
来一浏览器的请求发送到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'] 这一层层跟的火大。
如果你的请求是 http://localhost:801/yii2/frontend/web/index.php?r=site/login&m=1
返回的值就是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,这一部分就是我们自己编写的处理过程了