改进app类和route类 支持更多的路由调度

This commit is contained in:
thinkphp
2016-01-03 22:51:25 +08:00
parent 3b67e92026
commit 4eb78d2229
2 changed files with 187 additions and 148 deletions

View File

@@ -25,7 +25,7 @@ class App
*/
public static function run()
{
// 初始化公共模块
// 初始化应用(公共模块
self::initModule(COMMON_MODULE, Config::get());
// 读取扩展配置文件
@@ -72,11 +72,125 @@ class App
Session::init($config['session']);
}
// 应用URL调度
self::dispatch($config);
// URL路由检测
$dispatch = self::route($config);
// 监听app_run
APP_HOOK && Hook::listen('app_run');
// 监听app_begin
APP_HOOK && Hook::listen('app_begin', $dispatch);
// 根据类型调度
switch ($dispatch['type']) {
case 'redirect':
// 执行重定向跳转
header('Location: ' . $dispatch['url'], true, $dispatch['status']);
break;
case 'module':
// 模块/控制器/操作
$data = self::module($dispatch['data'], $config);
break;
case 'action':
// 执行操作
$data = Loader::action($dispatch['action'], $dispatch['params']);
break;
case 'behavior':
// 执行行为
$data = \think\hook::exec($dispatch['class'], $dispatch['method'], $dispatch['params']);
break;
case 'regex_closure':
// 正则闭包
$data = self::invokeRegex($dispatch['closure'], $dispatch['params']);
break;
case 'rule_closure':
// 规则闭包
$data = self::invokeRule($dispatch['closure'], $dispatch['params']);
break;
default:
throw new Exception('dispatch type not support', 10008);
}
// 监听app_end
APP_HOOK && Hook::listen('app_end', $data);
// 输出数据到客户端
return Response::send($data, Response::type(), Config::get('response_return'));
}
// 执行正则匹配下的闭包方法 支持参数调用
private static function invokeRegex($closure, $var = [])
{
$reflect = new \ReflectionFunction($closure);
$params = $reflect->getParameters();
$args = [];
array_shift($var);
foreach ($params as $param) {
$name = $param->getName();
if (!empty($var)) {
$args[] = array_shift($var);
} elseif ($param->isDefaultValueAvailable()) {
$args[] = $param->getDefaultValue();
}
}
return $reflect->invokeArgs($args);
}
// 执行规则匹配下的闭包方法 支持参数调用
private static function invokeRule($closure, $var = [])
{
$reflect = new \ReflectionFunction($closure);
$params = $reflect->getParameters();
$args = [];
foreach ($params as $param) {
$name = $param->getName();
if (isset($var[$name])) {
$args[] = $var[$name];
} elseif ($param->isDefaultValueAvailable()) {
$args[] = $param->getDefaultValue();
}
}
return $reflect->invokeArgs($args);
}
// 执行 模块/控制器/操作
private static function module($result, $config)
{
if (APP_MULTI_MODULE) {
$module = strtolower($result[0] ?: $config['default_module']);
if ($maps = $config['url_module_map']) {
if (isset($maps[$module])) {
// 记录当前别名
define('MODULE_ALIAS', $module);
// 获取实际的项目名
$module = $maps[MODULE_ALIAS];
} elseif (array_search($module, $maps)) {
// 禁止访问原始项目
$module = '';
}
}
// 获取模块名称
define('MODULE_NAME', defined('BIND_MODULE') ? BIND_MODULE : strip_tags($module));
// 模块初始化
if (MODULE_NAME && !in_array(MODULE_NAME, $config['deny_module_list']) && is_dir(APP_PATH . MODULE_NAME)) {
APP_HOOK && Hook::listen('app_begin');
define('MODULE_PATH', APP_PATH . MODULE_NAME . DS);
define('VIEW_PATH', MODULE_PATH . VIEW_LAYER . DS);
// 初始化模块
self::initModule(MODULE_NAME, $config);
} else {
throw new Exception('module [ ' . MODULE_NAME . ' ] not exists ', 10005);
}
} else {
define('MODULE_NAME', '');
define('MODULE_PATH', APP_PATH);
define('VIEW_PATH', MODULE_PATH . VIEW_LAYER . DS);
}
// 获取控制器名
$controller = strip_tags(strtolower($result[1] ?: Config::get('default_controller')));
define('CONTROLLER_NAME', defined('BIND_CONTROLLER') ? BIND_CONTROLLER : $controller);
// 获取操作名
$action = strip_tags(strtolower($result[2] ?: Config::get('default_action')));
define('ACTION_NAME', defined('BIND_ACTION') ? BIND_ACTION : $action);
// 执行操作
if (!preg_match('/^[A-Za-z](\/|\.|\w)*$/', CONTROLLER_NAME)) {
@@ -118,10 +232,6 @@ class App
} else {
$data = $method->invoke($instance);
}
// 操作方法执行完成监听
APP_HOOK && Hook::listen('action_end', $data);
// 输出数据
return Response::send($data, Response::type(), Config::get('response_return'));
} else {
// 操作方法不是Public 抛出异常
throw new \ReflectionException();
@@ -131,14 +241,11 @@ class App
if (method_exists($instance, '_empty')) {
$method = new \ReflectionMethod($instance, '_empty');
$data = $method->invokeArgs($instance, [$action, '']);
// 操作方法执行完成监听
APP_HOOK && Hook::listen('action_end', $data);
// 输出数据
return Response::send($data, Response::type(), Config::get('response_return'));
} else {
throw new Exception('method [ ' . (new \ReflectionClass($instance))->getName() . '->' . $action . ' ] not exists ', 10002);
}
}
return $data;
}
// 操作绑定到类:模块\controller\控制器\操作类
@@ -232,15 +339,8 @@ class App
}
}
/**
* URL调度
* @access public
*
* @param $config
*
* @throws Exception
*/
public static function dispatch($config)
// 分析 PATH_INFO
private static function parsePathinfo($config)
{
if (isset($_GET[$config['var_pathinfo']])) {
// 判断URL里面是否有兼容模式参数
@@ -275,93 +375,63 @@ class App
}
}
}
}
// [模块,控制器,操作]
$result = [null, null, null];
/**
* URL路由检测
* @access public
* @param $config
* @throws Exception
*/
public static function route($config)
{
// 解析PATH_INFO
self::parsePathinfo($config);
if (empty($_SERVER['PATH_INFO'])) {
$_SERVER['PATH_INFO'] = '';
define('__INFO__', '');
define('__EXT__', '');
$result = ['type' => 'module', 'data' => [null, null, null]];
} else {
$_SERVER['PATH_INFO'] = trim($_SERVER['PATH_INFO'], '/');
define('__INFO__', $_SERVER['PATH_INFO']);
// URL后缀
define('__EXT__', strtolower(pathinfo($_SERVER['PATH_INFO'], PATHINFO_EXTENSION)));
if (__INFO__) {
if ($config['url_deny_suffix'] && preg_match('/\.(' . $config['url_deny_suffix'] . ')$/i', __INFO__)) {
throw new Exception('url suffix deny');
}
// 去除URL后缀
$_SERVER['PATH_INFO'] = preg_replace($config['url_html_suffix'] ? '/\.(' . trim($config['url_html_suffix'], '.') . ')$/i' : '/\.' . __EXT__ . '$/i', '', __INFO__);
$depr = $config['pathinfo_depr'];
// 还原劫持后真实pathinfo
$path_info =
(defined('BIND_MODULE') ? BIND_MODULE . $depr : '') .
(defined('BIND_CONTROLLER') ? BIND_CONTROLLER . $depr : '') .
(defined('BIND_ACTION') ? BIND_ACTION . $depr : '') .
$_SERVER['PATH_INFO'];
// 路由检测
if (!empty($config['url_route_on'])) {
// 开启路由 则检测路由配置
Route::register(!empty($config['route']) ? $config['route'] : null);
$result = Route::check($path_info, $depr);
if (false === $result) {
// 路由无效
if ($config['url_route_must']) {
throw new Exception('route not define ');
} else {
// 继续分析URL
$result = Route::parseUrl($path_info, $depr);
}
if ($config['url_deny_suffix'] && preg_match('/\.(' . $config['url_deny_suffix'] . ')$/i', __INFO__)) {
throw new Exception('url suffix deny');
}
// 去除URL后缀
$_SERVER['PATH_INFO'] = preg_replace($config['url_html_suffix'] ? '/\.(' . trim($config['url_html_suffix'], '.') . ')$/i' : '/\.' . __EXT__ . '$/i', '', __INFO__);
$depr = $config['pathinfo_depr'];
// 还原劫持后真实pathinfo
$path_info =
(defined('BIND_MODULE') ? BIND_MODULE . $depr : '') .
(defined('BIND_CONTROLLER') ? BIND_CONTROLLER . $depr : '') .
(defined('BIND_ACTION') ? BIND_ACTION . $depr : '') .
$_SERVER['PATH_INFO'];
// 路由检测
if (!empty($config['url_route_on'])) {
// 开启路由 则检测路由配置
Route::register(!empty($config['route']) ? $config['route'] : null);
$result = Route::check($path_info, $depr);
if (false === $result) {
// 路由无效
if ($config['url_route_must']) {
throw new Exception('route not define ');
} else {
// 继续分析URL
$result = Route::parseUrl($path_info, $depr);
}
} else {
// 分析URL地址
$result = Route::parseUrl($path_info, $depr);
}
}
}
if (APP_MULTI_MODULE) {
$module = strtolower($result[0] ?: $config['default_module']);
if ($maps = $config['url_module_map']) {
if (isset($maps[$module])) {
// 记录当前别名
define('MODULE_ALIAS', $module);
// 获取实际的项目名
$module = $maps[MODULE_ALIAS];
} elseif (array_search($module, $maps)) {
// 禁止访问原始项目
$module = '';
}
}
// 获取模块名称
define('MODULE_NAME', defined('BIND_MODULE') ? BIND_MODULE : strip_tags($module));
// 模块初始化
if (MODULE_NAME && !in_array(MODULE_NAME, $config['deny_module_list']) && is_dir(APP_PATH . MODULE_NAME)) {
APP_HOOK && Hook::listen('app_begin');
define('MODULE_PATH', APP_PATH . MODULE_NAME . DS);
define('VIEW_PATH', MODULE_PATH . VIEW_LAYER . DS);
// 初始化模块
self::initModule(MODULE_NAME, $config);
} else {
throw new Exception('module [ ' . MODULE_NAME . ' ] not exists ', 10005);
// 分析URL地址
$result = Route::parseUrl($path_info, $depr);
}
} else {
define('MODULE_NAME', '');
define('MODULE_PATH', APP_PATH);
define('VIEW_PATH', MODULE_PATH . VIEW_LAYER . DS);
}
// 获取控制器名
$controller = strip_tags(strtolower($result[1] ?: Config::get('default_controller')));
define('CONTROLLER_NAME', defined('BIND_CONTROLLER') ? BIND_CONTROLLER : $controller);
// 获取操作名
$action = strip_tags(strtolower($result[2] ?: Config::get('default_action')));
define('ACTION_NAME', defined('BIND_ACTION') ? BIND_ACTION : $action);
return $result;
}
}

View File

@@ -326,7 +326,6 @@ class Route
}
}
}
}
}
return false;
@@ -340,8 +339,7 @@ class Route
// 正则路由
if ($route instanceof \Closure) {
// 执行闭包
$result = self::invokeRegex($route, $matches);
return is_array($result) ? $result : exit($result);
return ['type' => 'regex_closure', 'closure' => $route, 'params' => $matches];
}
return self::parseRegex($matches, $route, $url);
}
@@ -351,6 +349,7 @@ class Route
*/
private static function checkRule($rule, $route, $url, $pattern)
{
$len1 = substr_count($url, '/');
$len2 = substr_count($rule, '/');
if ($len1 >= $len2 || strpos($rule, '[')) {
@@ -364,10 +363,10 @@ class Route
}
$pattern = array_merge(self::$pattern, $pattern);
if (false !== $match = self::match($url, $rule, $pattern)) {
if ($route instanceof \Closure) {
// 执行闭包
$result = self::invokeRule($route, $match);
return is_array($result) ? $result : exit($result);
return ['type' => 'rule_closure', 'closure' => $route, 'params' => $match];
}
return self::parseRule($rule, $route, $url);
}
@@ -390,41 +389,6 @@ class Route
}
}
// 执行正则匹配下的闭包方法 支持参数调用
private static function invokeRegex($closure, $var = [])
{
$reflect = new \ReflectionFunction($closure);
$params = $reflect->getParameters();
$args = [];
array_shift($var);
foreach ($params as $param) {
$name = $param->getName();
if (!empty($var)) {
$args[] = array_shift($var);
} elseif ($param->isDefaultValueAvailable()) {
$args[] = $param->getDefaultValue();
}
}
return $reflect->invokeArgs($args);
}
// 执行规则匹配下的闭包方法 支持参数调用
private static function invokeRule($closure, $var = [])
{
$reflect = new \ReflectionFunction($closure);
$params = $reflect->getParameters();
$args = [];
foreach ($params as $param) {
$name = $param->getName();
if (isset($var[$name])) {
$args[] = $var[$name];
} elseif ($param->isDefaultValueAvailable()) {
$args[] = $param->getDefaultValue();
}
}
return $reflect->invokeArgs($args);
}
// 解析模块的URL地址 [模块/控制器/操作?]参数1=值1&参数2=值2...
public static function parseUrl($url, $depr = '/')
{
@@ -436,7 +400,8 @@ class Route
if (!empty($result['var'])) {
$_GET = array_merge($result['var'], $_GET);
}
return $result['route'];
return ['type' => 'module', 'data' => $result['route']];
}
// 解析规范的路由地址
@@ -581,12 +546,13 @@ class Route
$values = array_values($matches);
$url = preg_replace('/:(\d+)/e', '$values[\\1-1]', $url);
}
header("Location: $url", true, (is_array($route) && isset($route[1])) ? $route[1] : 301);
exit;
$result = ['type' => 'redirect', 'url' => $url, 'status' => (is_array($route) && isset($route[1])) ? $route[1] : 301];
} elseif (0 === strpos($url, '\\')) {
// 路由到行为
\think\hook::exec($url, isset($route[1]) ? $route[1] : '', $matches);
exit;
// 路由到行为
$result = ['type' => 'behavior', 'class' => $url, 'method' => isset($route[1]) ? $route[1] : '', 'params' => $matches];
} elseif (0 === strpos($url, '@')) {
// 路由到控制器
$result = ['type' => 'action', 'action' => substr($url, 1), 'params' => $matches];
} else {
// 解析路由地址
$result = self::parseRoute($url);
@@ -612,9 +578,10 @@ class Route
}
$var = array_merge($var, $params);
}
$_GET = array_merge($var, $_GET);
return $result['route'];
$_GET = array_merge($var, $_GET);
$result = ['type' => 'module', 'data' => $result['route']];
}
return $result;
}
// 解析正则路由
@@ -632,12 +599,13 @@ class Route
$url = preg_replace('/:(\d+)/e', '$matches[\\1]', $url);
if (0 === strpos($url, '/') || 0 === strpos($url, 'http')) {
// 路由重定向跳转
header("Location: $url", true, (is_array($route) && isset($route[1])) ? $route[1] : 301);
exit;
$result = ['type' => 'redirect', 'url' => $url, 'status' => (is_array($route) && isset($route[1])) ? $route[1] : 301];
} elseif (0 === strpos($url, '\\')) {
// 路由到行为
\think\hook::exec($url, isset($route[1]) ? $route[1] : '', $matches);
exit;
// 路由到行为
$result = ['type' => 'behavior', 'class' => $url, 'method' => isset($route[1]) ? $route[1] : '', 'params' => $matches];
} elseif (0 === strpos($url, '@')) {
// 路由到控制器
$result = ['type' => 'action', 'action' => substr($url, 1), 'params' => $matches];
} else {
// 解析路由地址
$result = self::parseRoute($url);
@@ -658,9 +626,10 @@ class Route
}
$var = array_merge($var, $params);
}
$_GET = array_merge($var, $_GET);
return $result['route'];
$_GET = array_merge($var, $_GET);
$result = ['type' => 'module', 'data' => $result['route']];
}
return $result;
}
// 根据路由别名和参数获取URL地址