Php URL路由器中的组和中间件
我正在构建一个定制的PHP框架。目标是使此代码正常工作:Php URL路由器中的组和中间件,php,url-routing,Php,Url Routing,我正在构建一个定制的PHP框架。目标是使此代码正常工作: $app = new Router(); $app->group("/admin", function($app) { $app->group("/pages", function($app) { $app->get("/home", "AdminPages@home") ->before("before_home1") ->bef
$app = new Router();
$app->group("/admin", function($app) {
$app->group("/pages", function($app) {
$app->get("/home", "AdminPages@home")
->before("before_home1")
->before("before_home2")
->after("after_home1")
->after("after_home2");
})->before("before_pages1")->before("before_pages2")->after("after_pages1")->after("after_pages2");
})->before("before_admin1")->before("before_admin2")->after("after_admin1")->after("after_admin2");
现在,Router::get()
返回一个Route
对象,这样我就可以添加前置和后置中间件(使用before()
和after()
,它将它们保存到Route::$before[]
和Route::$after[]
),但我不知道如何继续
问题是函数的顺序(在两个数组中)应该是
before_admin1
before_admin2
before_pages1
before_pages2
before_home1
before_home2
AdminPages@home
after_home1
after_home2
after_pages1
after_pages2
after_admin1
after_admin2
但是上面代码中的执行顺序是
before_home1
before_home2
before_pages1
before_pages2
before_admin1
before_admin2
AdminPages@home
after_home1
after_home2
after_pages1
after_pages2
after_admin1
after_admin2
按这种顺序放置中间件可调用项的最简单方法是什么?
Router::group()
应该返回什么?可能还有另一个路由器
?如果你想拥有这种链接行为,你必须分两个步骤执行你的路由:一个是路由定义阶段,你在其中构建你的路由对象,另一个是路由评估阶段,你在其中检查每一个,看哪一个首先匹配
实现对无限嵌套的支持的最直接的方法可能是构建嵌套的Route
对象,并让递归解决所有“执行顺序”问题
这应该让你开始:
class Route
{
protected $method;
protected $pattern;
protected $controller;
protected $parent = null;
protected $before = array();
protected $after = array();
public function __construct($method, $pattern, $controller)
{
$this->method = $method;
$this->pattern = $pattern;
$this->controller = $controller;
}
public function setParent($parent)
{
$this->parent = $parent;
}
public function before($controller)
{
$this->before[] = $controller;
}
public function after($controller)
{
$this->after[] = $controller;
}
/* Returns itself if the provided method and URI match this route,
otherwise returns null */
public function match($method, $uri)
{
/* Match on simple equality for the sake of simplicity */
return $uri === $this->getFullPattern() && $method === $this->method ?
$this : null;
}
protected function getFullPattern()
{
/* Recursively concatenate all parent patterns */
return is_null($this->parent) ?
$this->pattern :
$this->parent->getFullPattern() . $this->pattern;
}
public function dispatch()
{
$this->runBefore();
/* Call controller function */
$this->runAfter();
}
public function runBefore()
{
/* Run the before filters on the parent first */
if(!is_null($this->parent))
{
$this->parent->runBefore();
}
foreach($this->before as $controller)
{
/* Execute before filter */
}
}
public function runAfter()
{
foreach($this->after as $controller)
{
/* Execute after filter */
}
/* Run the after filters on the parent next */
if(!is_null($this->parent))
{
$this->parent->runAfter();
}
}
}
/* A router is considered a special "group" route */
class Router extends Route
{
protected $routes = array();
public function __construct($pattern = "")
{
parent::__construct(null, $pattern, null);
}
public function addChild($route)
{
$this->routes[] = $route;
$route->setParent($this);
return $route;
}
public function group($pattern, $func)
{
$child = new Router($pattern);
$this->addChild($child);
call_user_func($func, $child);
return $child;
}
public function get($pattern, $controller)
{
return $this->addChild(new Route("GET", $pattern, $controller));
}
/* And the same goes for POST, PUT, DELETE, etc. */
/* Returns the child route that matches the provided parameters,
or null if there is no match; since we are calling 'match' on
each child, we perform a recursive matching */
public function match($method, $uri)
{
foreach($this->routes as $route)
{
$result = $route->match($method, $uri);
if($result instanceof Route)
{
return $result;
}
}
return null;
}
public function dispatch()
{
throw new Exception("Group routes cannot be dispatched.");
}
}
我根本没有测试这段代码,所以请谨慎行事