实现类似ThinkPHP 多应用 默认应用的路由方法

meystack

这段代码还是 walkor 的auto-route代码,主要是因为,没有默认应用自己使用上不是很方便;
但是,我又不想因为一个小功能就去安装一个composer包;

默认不使用这个代码,你前端访问一样是需要手动增加路由URL地址的,否则就需要/app/controller/action的这种方式去访问!直接把这段代码粘贴复制到config/route文件中即可

代码的流程还是很简单的,如何实现默认应用?其实就是写路由,如果你已经习惯TP Laravel等框架,可忽略

1、首先你需要在config/app.php 文件中配置 default_app => index

2、遍历app下的这个应用文件夹,通过PHP反射类拿到他的函数

3、如果路由没有被设置过,则增加

注意:默认会把继承的函数都获取到,所以父类的某些功能性函数,请设置为protected function action();

代码里面我还加了注释,方便刚接触webman的同学!


$ignoreList = [];
$routes = Route::getRoutes();
// 获取已存在路由
foreach ($routes as $tmp_route) {
    $ignoreList[] = $tmp_route->getPath();
}

// 遍历默认应用文件夹
$default_app = config('app.default_app', 'index');
$files = new \RecursiveIteratorIterator(
    new \RecursiveDirectoryIterator(root_path('app/' . $default_app), \FilesystemIterator::SKIP_DOTS),
    \RecursiveIteratorIterator::CHILD_FIRST
);

// 循环处理每一个
foreach ($files as $file) {

    if ($file->isDir()) {
        continue;
    }

    // 获取文件名
    $filePath = str_replace('\\', '/', $file->getPathname());
    $fileExt = pathinfo($filePath, PATHINFO_EXTENSION);

    // 只处理PHP文件
    if (strpos(strtolower($filePath), '/controller/') === false || strtolower($fileExt) !== 'php') {
        continue;
    }

    // 获取路由URL路径
    $urlPath = str_replace(['/controller/', '/Controller/'], '/', substr(substr($filePath, strlen(app_path())), 0, -4));
    $urlPath = str_replace($default_app . '/', '', $urlPath);
    $className = str_replace('/', '\\', substr(substr($filePath, strlen(base_path())), 0, -4));
    if (!class_exists($className)) {
        continue;
    }

    /**
     * 反射获取类的方法
     * 注意:继承类会将所有父类方法也获取到
     *      所以非路由方法,请设置为protected属性
     */
    $refClass = new \ReflectionClass($className);
    $className = $refClass->name;
    $methods = $refClass->getMethods(\ReflectionMethod::IS_PUBLIC);

    // 添加路由函数
    $route = function ($uri, $action) use ($ignoreList) {
        if (in_array($uri, $ignoreList) || empty($uri)) {
            return;
        }
        Route::any($uri, $action);
        Route::any($uri . '/', $action);
    };

    // 循环处理每一个路由方法
    foreach ($methods as $item) {

        $action = $item->name;

        $magic = [
            '__construct', '__destruct', '__call', '__callStatic', '__get', '__set','__isset', '__unset', '__sleep', '__wakeup', '__toString',
            '__invoke', '__set_state', '__clone', '__autoload', '__debugInfo', 'initialize',
        ];

        // 过滤魔术方法
        if (in_array($action,$magic)) {
            continue;
        }

        // 执行路由代码
        if ($action === 'index') {
            if (strtolower(substr($urlPath, -6)) === '/index') {
                // 默认路由
                $route('/', [$className, $action]);
                $route(substr($urlPath, 0, -6), [$className, $action]);
            }
            $route($urlPath, [$className, $action]);
        }
        $route($urlPath . '/' . $action, [$className, $action]);
    }
}

默认的路由我没有转换小写,是为了我自己项目的风格统一,这个功能融合进内核也挺好的,还是期望 walkor 能考虑下!

1215 1 0
1个回答

walkor

截图
如果你有默认应用,应该用这样的目录结构。
内核里加一坨这样路由逻辑实在不合适。内核里不应该设置任何路由,很容易和用户的路由冲突。

  • meystack 2022-08-17

    由于我之前的项目写的代码太多了,所以只能用这种方式来兼容下!如果使用上述的目录结构建立一个新项目,那应用中间件要如何写?

  • meystack 2022-08-17

    看了下代码流程,可以判断app为空则为默认应用,但感觉这种会有一些不规范的感觉,我还是用自己的这种方式兼容下吧!

  • walkor 2022-08-17

    app/controller 下的控制器不属于任何应用,没有应用中间件,全局中间件对它有效。

  • meystack 2022-08-17

    那要给前端应用写一个鉴权中间件,如果不做判断就访问每个应用都会执行,这样写有点耦合

  • walkor 2022-08-17

    你可以弄个全局中间件,通过$request->app 判断是哪个应用,根据应用鉴权。

年代过于久远,无法发表回答
🔝