所有的迷惑都会在源码中得到解答
来一浏览器的请求发送到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) . '".'); } }
继续看,这个createControllerpublic 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,这一部分就是我们自己编写的处理过程了