我正在构建自定义 PHP 框架。目标是让这段代码工作:
$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()
应该返回什么?也许是另一个 Router
?
最佳答案
如果您想要这种链接行为,您必须分两步执行路由:路由定义阶段,您在其中构建路由对象,路由评估 阶段,您遍历每一个并查看哪个最先匹配。
实现无限嵌套支持的最直接的方法可能是构建嵌套的 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.");
}
}
我根本没有测试这段代码,所以请谨慎行事。
关于php - URL 路由器中的组和中间件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32370657/