From cbd8ea477ded87491a15e3003cd0b6a940bf56fa Mon Sep 17 00:00:00 2001 From: thinkphp Date: Wed, 11 May 2016 22:03:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3Relation=E7=B1=BB=20=E6=94=B9?= =?UTF-8?q?=E8=BF=9BRoute=E7=B1=BB=E7=9A=84group=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/think/Route.php | 112 +++++++++++++++++---- library/think/model/Relation.php | 6 +- tests/thinkphp/library/think/routeTest.php | 79 ++++++++------- 3 files changed, 143 insertions(+), 54 deletions(-) diff --git a/library/think/Route.php b/library/think/Route.php index 7e60af01..a0a6d511 100644 --- a/library/think/Route.php +++ b/library/think/Route.php @@ -53,6 +53,9 @@ class Route private static $pattern = []; // 域名绑定 private static $bind = []; + // 当前分组 + private static $group; + private static $option = []; // 添加URL映射规则 public static function map($map = '', $route = '') @@ -150,43 +153,118 @@ class Route } self::$rules[$type][$rule] = $result; } + } } - // 路由分组 - public static function group($name, $routes = [], $type = '*', $option = [], $pattern = []) + // 注册路由规则 + public static function rule($rule, $route = '', $type = '*', $option = [], $pattern = [], $group = '') { - self::$rules[$type][$name] = ['routes' => $routes, 'option' => $option, 'pattern' => $pattern]; + $group = $group ?: self::$group; + $option = $option ?: self::$option; + + if (strpos($type, '|')) { + foreach (explode('|', $type) as $val) { + self::rule($rule, $route, $val, $option, $pattern, $group); + } + } else { + $rules = []; + if (is_array($rule)) { + foreach ($rule as $key => $val) { + if (is_numeric($key)) { + $key = array_shift($val); + } + if (is_array($val)) { + $result = ['route' => $val[0], 'option' => $val[1], 'pattern' => isset($val[2]) ? $val[2] : []]; + } else { + $result = ['route' => $val, 'option' => $option, 'pattern' => $pattern]; + } + if ($group) { + self::$rules[$type][$group]['routes'][$key] = $result['route']; + } else { + self::$rules[$type][$key] = $result; + } + } + } else { + if ($group) { + self::$rules[$type][$group]['routes'][$rule] = $route; + } else { + self::$rules[$type][$rule] = ['route' => $route, 'option' => $option, 'pattern' => $pattern]; + } + } + } + } + + // 设置当前的路由分组 + public static function setGroup($name) + { + self::$group = $name; + } + + // 设置当前的路由分组 + public static function setOption($option) + { + self::$option = $option; + } + + // 路由分组 + public static function group($name, $routes, $option = [], $type = '*', $pattern = []) + { + if (is_array($name)) { + $option = $name; + $name = isset($option['name']) ? $option['name'] : ''; + } + if (!empty($name)) { + if ($routes instanceof \Closure) { + self::setGroup($name); + call_user_func_array($routes, []); + self::setGroup(null); + self::$rules[$type][$name]['option'] = $option; + self::$rules[$type][$name]['pattern'] = $pattern; + } else { + self::$rules[$type][$name] = ['routes' => $routes, 'option' => $option, 'pattern' => $pattern]; + } + } else { + if ($routes instanceof \Closure) { + // 闭包注册 + self::setOption($option); + call_user_func_array($routes, []); + self::setOption([]); + } else { + // 批量注册路由 + self::rule($routes, '', $type, $option, $pattern); + } + } } // 注册任意请求的路由规则 - public static function any($rule, $route = '', $option = [], $pattern = []) + public static function any($rule, $route = '', $option = [], $pattern = [], $group = '') { - self::register($rule, $route, '*', $option, $pattern); + self::rule($rule, $route, '*', $option, $pattern, $group); } // 注册get请求的路由规则 - public static function get($rule, $route = '', $option = [], $pattern = []) + public static function get($rule, $route = '', $option = [], $pattern = [], $group = '') { - self::register($rule, $route, 'GET', $option, $pattern); + self::rule($rule, $route, 'GET', $option, $pattern, $group); } // 注册post请求的路由规则 - public static function post($rule, $route = '', $option = [], $pattern = []) + public static function post($rule, $route = '', $option = [], $pattern = [], $group = '') { - self::register($rule, $route, 'POST', $option, $pattern); + self::rule($rule, $route, 'POST', $option, $pattern, $group); } // 注册put请求的路由规则 - public static function put($rule, $route = '', $option = [], $pattern = []) + public static function put($rule, $route = '', $option = [], $pattern = [], $group = '') { - self::register($rule, $route, 'PUT', $option, $pattern); + self::rule($rule, $route, 'PUT', $option, $pattern, $group); } // 注册delete请求的路由规则 - public static function delete($rule, $route = '', $option = [], $pattern = []) + public static function delete($rule, $route = '', $option = [], $pattern = [], $group = '') { - self::register($rule, $route, 'DELETE', $option, $pattern); + self::rule($rule, $route, 'DELETE', $option, $pattern, $group); } // 注册资源路由 @@ -219,7 +297,7 @@ class Route if (strpos($val[1], ':id') && isset($option['var'][$rule])) { $val[1] = str_replace(':id', ':' . $option['var'][$rule], $val[1]); } - self::register($rule . $val[1] . '$', $route . '/' . $val[2], $val[0], $option, $pattern); + self::rule($rule . $val[1] . '$', $route . '/' . $val[2], $val[0], $option, $pattern); } } } @@ -255,7 +333,7 @@ class Route // 注册未匹配路由规则后的处理 public static function miss($route, $method = '*', $option = []) { - self::register('__miss__', $route, $method, $option, []); + self::rule('__miss__', $route, $method, $option, []); } // 获取路由定义 @@ -395,8 +473,8 @@ class Route unset($rules['__miss__']); } foreach ($rules as $rule => $val) { - $option = $val['option']; - $pattern = $val['pattern']; + $option = isset($val['option']) ? $val['option'] : []; + $pattern = isset($val['pattern']) ? $val['pattern'] : []; // 参数有效性检查 if (!self::checkOption($option, $url)) { diff --git a/library/think/model/Relation.php b/library/think/model/Relation.php index 654a7b9b..ab605761 100644 --- a/library/think/model/Relation.php +++ b/library/think/model/Relation.php @@ -85,9 +85,9 @@ class Relation break; case self::BELONGS_TO_MANY: // 关联查询 - $pk = $this->parent->getPk(); - $condition['pivot.' . $foreignKey] = $this->parent->$pk; - $result = $this->belongsToManyQuery($relation, $this->middle, $foreignKey, $localKey, $condition)->select(); + $pk = $this->parent->getPk(); + $condition['pivot.' . $localKey] = $this->parent->$pk; + $result = $this->belongsToManyQuery($relation, $this->middle, $foreignKey, $localKey, $condition)->select(); foreach ($result as $set) { $pivot = []; foreach ($set->toArray() as $key => $val) { diff --git a/tests/thinkphp/library/think/routeTest.php b/tests/thinkphp/library/think/routeTest.php index eb27b456..bbe31686 100644 --- a/tests/thinkphp/library/think/routeTest.php +++ b/tests/thinkphp/library/think/routeTest.php @@ -24,60 +24,65 @@ class routeTest extends \PHPUnit_Framework_TestCase public function testRegister() { - + $request = Request::instance(); Route::get('hello/:name', 'index/hello'); Route::get(['hello/:name' => 'index/hello']); Route::post('hello/:name', 'index/post'); Route::put('hello/:name', 'index/put'); Route::delete('hello/:name', 'index/delete'); Route::any('user/:id', 'index/user'); - $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check(Request::instance(), 'hello/thinkphp')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check($request, 'hello/thinkphp')); $this->assertEquals(['hello/:name' => ['route' => 'index/hello', 'option' => [], 'pattern' => []]], Route::getRules('GET')); Route::register('type/:name', 'index/type', 'PUT|POST'); + Route::rule('type/:name', 'index/type', 'PUT|POST'); } public function testResource() { + $request = Request::instance(); Route::resource('res', 'index/blog'); Route::resource(['res' => ['index/blog']]); - $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'index']], Route::check(Request::instance(), 'res')); - $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'create']], Route::check(Request::instance(), 'res/create')); - $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'read']], Route::check(Request::instance(), 'res/8')); - $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'edit']], Route::check(Request::instance(), 'res/8/edit')); + $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'index']], Route::check($request, 'res')); + $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'create']], Route::check($request, 'res/create')); + $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'read']], Route::check($request, 'res/8')); + $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'edit']], Route::check($request, 'res/8/edit')); Route::resource('blog.comment', 'index/comment'); - $this->assertEquals(['type' => 'module', 'module' => ['index', 'comment', 'read']], Route::check(Request::instance(), 'blog/8/comment/10')); - $this->assertEquals(['type' => 'module', 'module' => ['index', 'comment', 'edit']], Route::check(Request::instance(), 'blog/8/comment/10/edit')); + $this->assertEquals(['type' => 'module', 'module' => ['index', 'comment', 'read']], Route::check($request, 'blog/8/comment/10')); + $this->assertEquals(['type' => 'module', 'module' => ['index', 'comment', 'edit']], Route::check($request, 'blog/8/comment/10/edit')); } public function testRest() { + $request = Request::instance(); Route::rest('read', ['GET', '/:id', 'look']); Route::rest('create', ['GET', '/create', 'add']); Route::rest(['read' => ['GET', '/:id', 'look'], 'create' => ['GET', '/create', 'add']]); Route::resource('res', 'index/blog'); - $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'add']], Route::check(Request::instance(), 'res/create')); - $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'look']], Route::check(Request::instance(), 'res/8')); + $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'add']], Route::check($request, 'res/create')); + $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'look']], Route::check($request, 'res/8')); } public function testRouteMap() { + $request = Request::instance(); Route::map('hello', 'index/hello'); $this->assertEquals('index/hello', Route::map('hello')); - $this->assertEquals(['type' => 'module', 'module' => ['index', 'hello', null]], Route::check(Request::instance(), 'hello')); + $this->assertEquals(['type' => 'module', 'module' => ['index', 'hello', null]], Route::check($request, 'hello')); } public function testMixVar() { + $request = Request::instance(); Route::get('hello-', 'index/hello', [], ['name' => '\w+']); - $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check(Request::instance(), 'hello-thinkphp')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check($request, 'hello-thinkphp')); Route::get('hello-', 'index/hello', [], ['name' => '\w+', 'id' => '\d+']); - $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check(Request::instance(), 'hello-thinkphp2016')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check($request, 'hello-thinkphp2016')); Route::get('hello-/[:id]', 'index/hello', [], ['name' => '\w+', 'id' => '\d+']); - $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check(Request::instance(), 'hello-thinkphp/2016')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check($request, 'hello-thinkphp/2016')); } public function testParseUrl() @@ -94,66 +99,72 @@ class routeTest extends \PHPUnit_Framework_TestCase { Route::get('hello/:name', 'index/hello'); Route::get('blog/:id', 'blog/read', [], ['id' => '\d+']); - - $this->assertEquals(false, Route::check(Request::instance(), 'test/thinkphp')); - $this->assertEquals(false, Route::check(Request::instance(), 'blog/thinkphp')); - $this->assertEquals(['type' => 'module', 'module' => [null, 'blog', 'read']], Route::check(Request::instance(), 'blog/5')); - $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check(Request::instance(), 'hello/thinkphp/abc/test')); + $request = Request::instance(); + $this->assertEquals(false, Route::check($request, 'test/thinkphp')); + $this->assertEquals(false, Route::check($request, 'blog/thinkphp')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'blog', 'read']], Route::check($request, 'blog/5')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check($request, 'hello/thinkphp/abc/test')); } public function testCheckRouteGroup() { + $request = Request::instance(); Route::pattern(['id' => '\d+', 'name' => '\w{6,25}']); Route::group('group', [':id' => 'index/hello', ':name' => 'index/say']); - $this->assertEquals(false, Route::check(Request::instance(), 'empty/think')); - $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'say']], Route::check(Request::instance(), 'group/think')); - $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check(Request::instance(), 'group/10')); - $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'say']], Route::check(Request::instance(), 'group/thinkphp')); + $this->assertEquals(false, Route::check($request, 'empty/think')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'say']], Route::check($request, 'group/think')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check($request, 'group/10')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'say']], Route::check($request, 'group/thinkphp')); } public function testRouteToModule() { + $request = Request::instance(); Route::get('hello/:name', 'index/hello'); Route::get('blog/:id', 'blog/read', [], ['id' => '\d+']); - $this->assertEquals(false, Route::check(Request::instance(), 'test/thinkphp')); - $this->assertEquals(false, Route::check(Request::instance(), 'blog/thinkphp')); - $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check(Request::instance(), 'hello/thinkphp')); - $this->assertEquals(['type' => 'module', 'module' => [null, 'blog', 'read']], Route::check(Request::instance(), 'blog/5')); + $this->assertEquals(false, Route::check($request, 'test/thinkphp')); + $this->assertEquals(false, Route::check($request, 'blog/thinkphp')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'index', 'hello']], Route::check($request, 'hello/thinkphp')); + $this->assertEquals(['type' => 'module', 'module' => [null, 'blog', 'read']], Route::check($request, 'blog/5')); } public function testRouteToController() { + $request = Request::instance(); Route::get('say/:name', '@app\index\controller\index\hello'); - $this->assertEquals(['type' => 'controller', 'controller' => 'app\index\controller\index\hello', 'params' => ['name' => 'thinkphp']], Route::check(Request::instance(), 'say/thinkphp')); + $this->assertEquals(['type' => 'controller', 'controller' => 'app\index\controller\index\hello', 'params' => ['name' => 'thinkphp']], Route::check($request, 'say/thinkphp')); } public function testRouteToMethod() { + $request = Request::instance(); Route::get('user/:name', '\app\index\service\User::get', [], ['name' => '\w+']); Route::get('info/:name', ['\app\index\model\Info', 'getInfo'], [], ['name' => '\w+']); - $this->assertEquals(['type' => 'method', 'method' => '\app\index\service\User::get', 'params' => ['name' => 'thinkphp']], Route::check(Request::instance(), 'user/thinkphp')); - $this->assertEquals(['type' => 'method', 'method' => ['\app\index\model\Info', 'getInfo'], 'params' => ['name' => 'thinkphp']], Route::check(Request::instance(), 'info/thinkphp')); + $this->assertEquals(['type' => 'method', 'method' => '\app\index\service\User::get', 'params' => ['name' => 'thinkphp']], Route::check($request, 'user/thinkphp')); + $this->assertEquals(['type' => 'method', 'method' => ['\app\index\model\Info', 'getInfo'], 'params' => ['name' => 'thinkphp']], Route::check($request, 'info/thinkphp')); } public function testRouteToRedirect() { + $request = Request::instance(); Route::get('art/:id', '/article/read/id/:id', [], ['id' => '\d+']); - $this->assertEquals(['type' => 'redirect', 'url' => '/article/read/id/8', 'status' => 301], Route::check(Request::instance(), 'art/8')); + $this->assertEquals(['type' => 'redirect', 'url' => '/article/read/id/8', 'status' => 301], Route::check($request, 'art/8')); } public function testBind() { + $request = Request::instance(); Route::bind('module', 'index/blog'); $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'read']], Route::parseUrl('read/10')); Route::get('index/blog/:id', 'index/blog/read'); - $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'read']], Route::check(Request::instance(), '10')); + $this->assertEquals(['type' => 'module', 'module' => ['index', 'blog', 'read']], Route::check($request, '10')); Route::bind('namespace', '\app\index\controller'); - $this->assertEquals(['type' => 'method', 'method' => ['\app\index\controller\blog', 'read'], 'params' => []], Route::check(Request::instance(), 'blog/read')); + $this->assertEquals(['type' => 'method', 'method' => ['\app\index\controller\blog', 'read'], 'params' => []], Route::check($request, 'blog/read')); Route::bind('class', '\app\index\controller\blog'); - $this->assertEquals(['type' => 'method', 'method' => ['\app\index\controller\blog', 'read'], 'params' => []], Route::check(Request::instance(), 'read')); + $this->assertEquals(['type' => 'method', 'method' => ['\app\index\controller\blog', 'read'], 'params' => []], Route::check($request, 'read')); } public function testSsl()