
In this article I explain how to declare your routes cleanly, by creating a Route Registrers class in which you register them. It is a clean and easy way to declare routes.
The changes to make to your Laravel application are fairly simple. We adjust the route service provider and delete the web and API route files. The first thing we do is create a new trait/concern we can add to our app/Providers/RouteServiceProvider, called MapRouteRegistrers. Add the following code to that new trait/concern.
namespace App\Routing\Concerns;
use App\Routing\Contracts\RouteRegistrer;
use Illuminate\Contracts\Routing\Registrer;
use RuntimeException;
trait MapRouteRegistrers
{
protected function mapRoutes(Registrer $router, array $registrers): void
{
foreach ($registrers as $registrer) {
if (! class_exists($registrer) || ! is_subclass_of($registrer, RouteRegistrer::class)) {
throw new RuntimeException(sprintf(
'Cannot map routes \'%s\', it is not a valid routes class',
$registrer
));
}
(new $registrer)->map($router);
}
}
}As you can see, we also need an interface/contract to work against, and every one of our Registrers has to implement it.
Create it under App/Routing/Contracts/RouteRegistrer and add the following code.
namespace App\Routing\Contracts;
use Illuminate\Contracts\Routing\Registrer;
interface RouteRegistrer
{
public function map(Registrer $registrer): void;
}Now that the trait and the interface are in place, we can look at the changes we need to make to the default routing service provider.
namespace App\Providers;
use App\Routing\Concerns\MapsRouteRegistrers;
use Illuminate\Contracts\Routing\Registrer;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
use MapsRouteRegistrers;
protected array $registrers = [];
public function boot(): void
{
$this->routes(function (Registrer $router) {
$this->mapRoutes($router, $this->registrers);
});
}
}In the code above you can see that we have added a new property to our route service provider. That property is where the application’s route registrers are declared, and it is loaded in the boot method.
Now that our application is ready to use route registrers instead of route files, let us create a default one. This approach works exceptionally well in a modular system or a domain-driven design, every domain or module registers its own routes. For this example we will keep things simple so the approach stays clear. Create a new route registrer in app/Routing/Registrers/DefaultRegistrer.php and add the following code.
namespace App\Routing\Registrers;
use App\Routing\Contracts\RouteRegistrer;
class DefaultRegistrer implements RouteRegistrer
{
public function map(Registrer $registrer): void
{
$registrer->view('/', 'welcome');
}
}Now that our default registrer exists, we can declare it in our Route Service Provider so that it gets loaded.
namespace App\Providers;
use App\Routing\Concerns\MapsRouteRegistrers;
use App\Routing\Registrers\DefaultRegistrer;
use Illuminate\Contracts\Routing\Registrer;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
use MapsRouteRegistrers;
protected array $registrers = [
DefaultRegistrer::class,
];
public function boot(): void
{
$this->routes(function (Registrer $router) {
$this->mapRoutes($router, $this->registrers);
});
}
}
If you now visit “/”, you will be served the “welcome” view, which means everything is wired up correctly. In my own example I have static marketing, blog and admin routes, among others:
namespace App\Providers;
use App\Routing\Concerns\MapsRouteRegistrers;
use App\Routing\Registrers\AdminRegistrer;
use App\Routing\Registrers\BlogRegistrer;
use App\Routing\Registrers\MarketingRegistrer;
use Illuminate\Contracts\Routing\Registrer;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
use MapsRouteRegistrers;
protected array $registrers = [
MarketingRegistrer::class, // Marketing Routes
BlogRegistrer::class, // Blog Routes
AdminRegistrer::class, // Admin Routes
];
public function boot(): void
{
$this->routes(function (Registrer $router) {
$this->mapRoutes($router, $this->registrers);
});
}
}Splitting your routes this way is an excellent way to move from a plain PHP routes file to class-based routing, which gives you far better encapsulation within your application or domain.


