Skip to content

Instantly share code, notes, and snippets.

@DarkStoorM
Last active June 27, 2021 13:48
Show Gist options
  • Save DarkStoorM/fadf4297d4871e3df0d580e0e96cf8bf to your computer and use it in GitHub Desktop.
Save DarkStoorM/fadf4297d4871e3df0d580e0e96cf8bf to your computer and use it in GitHub Desktop.
Laravel Route Separation experiment

Laravel Route Separation

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

img

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   |
+----------+-------------------------------+-----------------------------------+

Conclusion

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment