首页 > 解决方案 > 如何正确扩展 Laravel 5.7 路由器?

问题描述

这个问题已经在这里这里这里讨论过很多次,但没有提到优雅的解决方案。

一个特殊的用例是允许使用 Laravel 加载和路由旧的 PHP 文件。例如,我正在将一个非常古老(> 20 年)的代码库迁移到 Laravel 中,并且大多数页面都是常规的 PHP 文件,我想将它们呈现到特定的 Blade 模板中。

要做到这一点,这样做会很优雅:

Router::php('/some/route/{id}', base_path('legacy/some/page.php'));

在幕后,我需要的只是将捕获的变量传递给 PHP 页面,评估并获取它的内容并最终返回一个视图实例。

由于 Laravel 声称自己是一个 SOLID 框架,我认为扩展路由器是微不足道的,所以我写了这个:

命名空间应用\服务;

class Router extends \Illuminate\Routing\Router
{
    public function php($uri, $filename, $template='default') {
        ...
        return view(...
    }
}

然后我尝试用这个扩展我的 Http Kernel:

namespace App\Http;

use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Http\Kernel as HttpKernel;

use App\Services\Router;

class Kernel extends HttpKernel
{
    public function __construct(Application $app, Router $router) {
        return parent::__construct($app, $router);
    }
}

但它不起作用,似乎应用程序正在构建具有错误依赖关系的内核。在Application@registerCoreContainerAliases我看到核心别名router是硬编码的,因为这个方法是在应用程序的构造函数中调用的,我注定要失败。

剩下的唯一解决方案是在加载内核之前覆盖路由器,如下所示:

$app = new Application($_ENV['APP_BASE_PATH'] ?? dirname(__DIR__));

$app->singleton('router', \App\Services\Router::class);

$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);

但这看起来有点难看。有没有更好的方法来实现这一目标?

标签: phplaravel

解决方案


由于Router类是可的,您可以执行以下操作:

Router::macro('php', function ($uri, $filepath) {
    return $this->addRoute(['GET', 'POST', etc...], $uri, function () use ($filepath) {
        // here you might use the blade compiler to render the raw php along with any variables.
        // 
        // See: https://laravel.com/api/5.7/Illuminate/View/Compilers/Concerns/CompilesRawPhp.html
        //

        $contents = file_get_contents($filepath);

        // return compiled $contents...
    });
});

推荐阅读