使用Composer从零开发一个简单的restful框架(08)-控制器命名空间
上一章支持了控制器,但控制器不一定都全部存放在一个目录,所以给路由分组添加支持命名空间。
路由
编辑core/Route.php
,添加命名空间相关成员变量和修改相关方法
private string $group; //分组
private string $nsParent; //父命名空间
private string $ns = ''; //分组命名空间
private array $routes = []; //分组下的路由, 包括分组
public function __construct(string $group, string $nsParent = '') {
$this->group = $group;
$this->nsParent = $nsParent;
}
public function getGroup(): string {
return $this->group;
}
public function getNamespace(): string {
if (!$this->nsParent && !$this->ns) return APP_CONTROLLER_NAMESPACE;
if ($this->ns) return $this->ns;
if ($this->nsParent) return $this->nsParent;
return '';
}
public function setNamespace(string $ns): void {
$this->ns = $ns;
}
public function getRoutes(): array {
return $this->routes;
}
编辑core/Router.php
,修改和添加命名空间相关方法
// 路由分组
public function group(string $group, \Closure $cb): void {
$lastRoute = $this->curr;
slash_add_head($group);
$route = new Route($group, $lastRoute->getNamespace());
$this->curr->addChild($route);
$this->curr = $route;
call_user_func($cb, $this);
$this->curr = $lastRoute;
}
// 设置命名空间
public function namespace(string $ns): void {
$this->curr->setNamespace($ns);
}
编辑core/Router.php
,修改dispatch
方法
private function dispatch(Route $route, string $method, string $uri, Request $request, Response $response): void {
$group = $route->getGroup();
// 分组不会有命名参数, 不包含直接返回
if (!str_starts_with($uri, $group)) return;
$uri = substr($uri, strlen($group));
slash_add_head($uri);
$routes = $route->getRoutes();
foreach ($routes as $item) {
if ($item instanceof RouteItem) {
if ($method == $item->method && $uri == $item->uri) {
// 全匹配路由
$this->start($item, $route->getNamespace(), $request, $response);
return;
} else if ($method == $item->method && preg_match_all('(:\w+)', $item->uri, $names)) {
// 参数路由
$pattern = preg_replace('(:\w+)', '(\w+)', $item->uri);
if (preg_match('#^' . $pattern . '$#', $uri, $matches)) {
$params = $this->mergeParams($names[0], $matches);
$request->setParams($params);
$this->start($item, $route->getNamespace(), $request, $response);
return;
}
}
} else {
$this->dispatch($item, $method, $uri, $request, $response);
}
}
}
private function start(RouteItem $item, string $namespace, Request $request, Response $response): void {
if ($item->cb instanceof \Closure) {
($item->cb)($request, $response);
} else {
[$controller, $method] = explode('@', $item->cb);
$module = "$namespace\\$controller";
new $module($method, $request, $response);
}
}
应用
app/controller
目录重命名为app/api
编辑 app/api/User.php
文件,修改命名空间
namespace app\api;
use core\Controller;
编辑route/user.php
,内容如下。其实就增加了$router->namespace('app\api');
这行设置命名空间的代码
<?php
use core\Router;
/** @var Router $router */
$router->group('user', function(Router $router) {
$router->namespace('app\api');
$router->get('login', 'User@login');
$router->get('logout', 'User@logout');
});
测试
浏览器分别访问 phpapi.com/user/login 和 phpapi.com/user/logout
本作品采用《CC 协议》,转载必须注明作者和本文链接