如何正确扩展Laravel 5.7路由器?

时间:2018-12-31 20:54:26

标签: php laravel

这个问题已被hereherehere多次讨论,但没有提及优雅的解决方案。

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

要做到这一点,做起来很优雅:

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

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

由于Laravel声称自己是SOLID框架,所以我认为扩展Router很简单,所以我这样写:

命名空间App \ Services;

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
);

但这看起来有点丑陋。有没有更好的方法可以做到这一点?

1 个答案:

答案 0 :(得分:1)

由于Router类是macroable,因此您可以执行以下操作:

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...
    });
});