After poking around with route separation, I found this (a bit messy and ugly) way to keep routes in separate files without touching the RouteServiceProvider
at all - the only update is to change the web namespace to 'routes/web/main.php'
since this will be the definitions file for all routes.
This is more of an experiment, not a recommended way of doing this. You could also do this in RouteServiceProvider
in a loop with glob
.
First thing to do will be moving routes to a new directory: routes/web
, which will only contain main.php
and index.php
files - main being the definitions file which will register route groups all together .
Let's assume we have a website, where we can edit our profile and change some private account settings. The structure would be something like the example below (not ideally of course, it's just a quick example, no one would structure a page like this):
routes
├─ web
│ ├─ profile
│ │ ├─ settings
│ │ │ ├─ settings.php (shows all available settings options page)
│ │ │ ├─ billing.php (shows billing settings (or payments, wtv))
│ │ │ └─ personal.php (shows personal info settings)
│ │ └─ profile.php (shows user's profile)
│ ├─ index.php (main routes, like index|about|contact)
│ └─ main.php (routes definition file)
├─ api.php
├─ channels.php
└─ console.php
The idea is to make one file to register all groups in one place, but keep the routes (methods) in separate files.
The main.php
file. This example will be a bit messy with the comments... it applies to the above Routes directory structure.
<?php
/* -- Laravel 8.x -- */
use Illuminate\Support\Facades\Route;
/**
* Index Routes
*/
Route::prefix('/')->group(__DIR__ . '/index.php');
/**
* If you need middlewares:
* Route::prefix('/')
* ->middleware('your_middleware')
* ->group(__DIR__ . '/<file_name>.php');
*/
/**
* Profile Routes
*/
$profilePrefix = "/profile";
$profilePathPrefix = __DIR__ . $profilePrefix;
// $profilePrefix is now "/profile"
/**
* So here we define a path to the files that reside under "profile" directory,
* we also create a profile Prefix for the route
* With this we have a URL like: example.com/profile
*/
// ----------------------------------------------\/ this is important
// you pass the prefix to the group
Route::prefix($profilePrefix)->group(function () use ($profilePathPrefix, $profilePrefix) {
Route::prefix('/')->group($profilePathPrefix . '/profile.php');
/**
* IMO the convention is pretty simple:
* Route::prefix(<route_prefix>)->group(<path_prefix> . '/<file_name>');
* Middleware can also be assigned, if they have to be applied to the entire group
* It would also be nice to keep the "main" route in the current group
* named with that prefix, e.g. if we have a Profile page,
* the index of that page would point at "profile.php",
* which then defines the Routes (get/post/etc).
*/
/**
* If there are no other routes that require grouping,
* just duplicating the above will suffice. Not needed, of course
* Route::prefix('/stats')->group($profilePathPrefix . 'stats.php');
*/
// If there is a new group in the structure, we can just do the same thing
// We can define a new path and route prefixes, using the previous prefix
// This gives us the following URL: example.com/profile/settings
$profilePrefix . "/settings";
$settingsPathPrefix = __DIR__ . $profileSettingsPrefix =
// optionally pass "$profilePathPrefix" to the use() if you want to create a new group inside
Route::prefix($profileSettingsPrefix)->group(function () use ($profileSettingsPrefix, $settingsPathPrefix) {
Route::prefix('/')->group($settingsPathPrefix . '/settings.php');
// Those routes below do not need to be here, but if they don't register
// other methods than GET, they don't really need separate files, depends on preferences
Route::prefix('/account')->group($settingsPathPrefix . '/account.php');
Route::prefix('/billing')->group($settingsPathPrefix . '/billing.php');
Route::prefix('/personal')->group($settingsPathPrefix . '/personal.php');
});
});
The above might not explain much, but let's try to make something closer to a real world example with minimal amount of comments this time.
Let's say we start with a forum and we have some settings in the Admin Panel and some additional basic pages (contact/about/profile)
Now let's assume we have this basic structure:
routes
├─ web
│ ├─ admin
│ │ ├─ forum-settings
│ │ │ ├─ forum-settings.php
│ │ │ ├─ threads.php
│ │ │ ├─ posts.php
│ │ │ └─ users.php
│ │ ├─ admin.php
│ │ └─ statistics.php
│ ├─ index.php
│ └─ main.php
├─ api.php
├─ channels.php
└─ console.php
To make things a bit more clear, I treat every folder as a Route Group, which points at some index
file. Folder name is the route prefix
and that prefix also
The code under routes/web/main.php
:
// Index Routes
Route::prefix('/')->group(__DIR__ . '/index.php');
// Admin Routes Group
$adminPrefix = "/admin";
$adminPathPrefix = __DIR__ . $adminPrefix;
Route::prefix($adminPrefix)
/* Middleware can also be applied before the group, depends if you really need them */
->group(function () use ($adminPathPrefix, $adminPrefix) {
Route::prefix('/')->group($adminPathPrefix . '/admin.php');
Route::prefix('/statistics')->group($adminPathPrefix . '/statistics.php');
// Forum Settings Routes Group
$adminForumPrefix = "/forum-settings";
$adminForumPathPrefix = __DIR__ . $adminPrefix . $adminForumPrefix;
Route::prefix($adminForumPrefix)->group(function () use ($adminForumPathPrefix, $adminForumPrefix) {
Route::prefix('/')->group($adminForumPathPrefix . '/forum-settings.php');
Route::prefix('/threads')->group($adminForumPathPrefix . '/threads.php');
Route::prefix('/posts')->group($adminForumPathPrefix . '/posts.php');
Route::prefix('/users')->group($adminForumPathPrefix . '/users.php');
});
});
NOTE: the prefixes can also be extracted, if needed
The result of the above:
+----------+-------------------------------+-----------------------------------+
| Method | URI | Name |
+----------+-------------------------------+-----------------------------------+
| GET|HEAD | / | index |
| GET|HEAD | about | index-about |
| GET|HEAD | contact | index-contact |
| GET|HEAD | profile | index-profile |
| GET|HEAD | admin | admin-index |
| GET|HEAD | admin/statistics | admin-statistics |
| GET|HEAD | admin/forum-settings | admin-forum-settings-index |
| POST | admin/forum-settings | admin-forum-settings-index-post |
| GET|HEAD | admin/forum-settings/posts | admin-forum-settings-posts |
| POST | admin/forum-settings/posts | admin-forum-settings-posts-post |
| GET|HEAD | admin/forum-settings/threads | admin-forum-settings-threads |
| POST | admin/forum-settings/threads | admin-forum-settings-threads-post |
| GET|HEAD | admin/forum-settings/users | admin-forum-settings-users |
| POST | admin/forum-settings/users | admin-forum-settings-users-post |
+----------+-------------------------------+-----------------------------------+
Should you separate your routes? The answer is always: "it depends".
I have seen projects with really big web.php
file and they don't care. I have seen simple blogs with at most 9 registered routes and every group had a separate file. Whatever is more readable or more manageable to you. Routes are cached anyway.
You can always map your routes in RouteServiceProvider
, looping through glob()
results.