使用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_contains($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/loginphpapi.com/user/logout

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!