如何在Laravel应用程序中使用路由注册器

142 阅读3分钟

最近我遇到了一个独特的方法来加载路由到Laravel应用程序, 我想与你分享。它允许你创建Route Registrars类,在其中注册你的路由。我在一个由Ollie Read开发的软件包中看到了这个方法, 它引起了我的注意,因为它是一个干净而令人兴奋的注册路由的方法。

对你的标准Laravel应用程序所需的改变是相对简单的。我们对路由服务提供者做一些改变 - 并删除网络和API路由文件.app/Providers/RouteServiceProvider 我们做的第一件事是创建一个新的特质/关注点,我们可以添加到我们的MapRouteRegistrars 。在这个新的trait/concern中添加以下代码。

declare(strict_types=1);
 
namespace App\Routing\Concerns;
 
use App\Routing\Contracts\RouteRegistrar;
use Illuminate\Contracts\Routing\Registrar;
use RuntimeException;
 
trait MapRouteRegistrars
{
    protected function mapRoutes(Registrar $router, array $registrars): void
    {
        foreach ($registrars as $registrar) {
            if (! class_exists($registrar) || ! is_subclass_of($registrar, RouteRegistrar::class)) {
                throw new RuntimeException(sprintf(
                    'Cannot map routes \'%s\', it is not a valid routes class',
                    $registrar
                ));
            }
 
            (new $registrar)->map($router);
        }
    }
}

正如你所看到的,我们还需要创建一个接口/合同来使用,并确保我们所有的注册商都能实现它。在app/Routing/Contracts/RouteRegistrar 下创建这个接口,并添加以下代码。

declare(strict_types=1);
 
namespace App\Routing\Contracts;
 
use Illuminate\Contracts\Routing\Registrar;
 
interface RouteRegistrar
{
    public function map(Registrar $registrar): void;
}

现在我们已经有了特质和接口,我们可以看看我们需要对默认的路由服务提供者做出的改变。

declare(strict_types=1);
 
namespace App\Providers;
 
use App\Routing\Concerns\MapsRouteRegistrars;
use Illuminate\Contracts\Routing\Registrar;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
 
class RouteServiceProvider extends ServiceProvider
{
    use MapsRouteRegistrars;
 
    protected array $registrars = [];
 
    public function boot(): void
    {
        $this->routes(function (Registrar $router) {
            $this->mapRoutes($router, $this->registrars);
        });
    }
}

从上面的代码中,你可以看到我们给路由服务提供者添加了一个新的属性。这个属性是应用程序的路由注册器在启动方法中被注册和加载的地方。

现在我们已经让我们的应用程序准备好使用路由注册器而不是路由文件,让我们为我们的应用程序创建一个默认的路由注册器。这种方法在域驱动的设计或模块化系统中效果特别好--允许每个域或模块注册其路由。对于这个例子,我们将保持简单,以便你能理解这种方法。在app/Routing/Registrars/DefaultRegistrar.php ,创建一个新的路由注册器,并添加以下代码。

declare(strict_types=1);
 
namespace App\Routing\Registrars;
 
use App\Routing\Contracts\RouteRegistrar;
 
class DefaultRegistrar implements RouteRegistrar
{
    public function map(Registrar $registrar): void
    {
        $registrar->view('/', 'welcome');
    }
}

现在,我们的默认注册器已经创建,我们可以在我们的路由服务提供者里面注册这个,确保它被加载。

declare(strict_types=1);
 
namespace App\Providers;
 
use App\Routing\Concerns\MapsRouteRegistrars;
use App\Routing\Registrars\DefaultRegistrar;
use Illuminate\Contracts\Routing\Registrar;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
 
class RouteServiceProvider extends ServiceProvider
{
    use MapsRouteRegistrars;
 
    protected array $registrars = [
        DefaultRegistrar::class,
    ];
 
    public function boot(): void
    {
        $this->routes(function (Registrar $router) {
            $this->mapRoutes($router, $this->registrars);
        });
    }
}

现在,如果你访问/ ,你将被加载到welcome 视图,这意味着一切都被正确地连接起来。我可以想象,在我的一个应用程序中,我可能会利用这个伟大的方式,我有静态的营销路线、博客路线、管理路线,以及更多。作为一个例子,我可以想象路由服务提供者的样子如下。

declare(strict_types=1);
 
namespace App\Providers;
 
use App\Routing\Concerns\MapsRouteRegistrars;
use App\Routing\Registrars\AdminRegistrar;
use App\Routing\Registrars\BlogRegistrar;
use App\Routing\Registrars\MarketingRegistrar;
use Illuminate\Contracts\Routing\Registrar;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
 
class RouteServiceProvider extends ServiceProvider
{
    use MapsRouteRegistrars;
 
    protected array $registrars = [
        MarketingRegistrar::class, // Marketing Routes
        BlogRegistrar::class, // Blog Routes
        AdminRegistrar::class, // Admin Routes
    ];
 
    public function boot(): void
    {
        $this->routes(function (Registrar $router) {
            $this->mapRoutes($router, $this->registrars);
        });
    }
}

像这样拆分我们的路由是一种很好的方式,可以从标准的PHP路由文件转移到基于类的路由系统,允许与你的应用程序或域进行更好的封装。