Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

moshe-autoleadstar
Copy link
Contributor

Currently, the Router (or Route facade) and the Route are Macroable. But sometimes, some methods on the Router will give the intermediate RouteRegistrar class. That class is currently not Macroable and as such, macros can't be added across the breadth of route setup. This PR adds Macroable to RouteRegistrar so that macros can now be added and used no matter where the developer is in the route registration.

@basantashubhu
Copy link

Can you provide a use case?

@moshe-autoleadstar
Copy link
Contributor Author

moshe-autoleadstar commented Sep 4, 2025

@basantashubhu sure. for example:

Before RouteRegistrar being Macroable

Route::prefix('my-prefix')
    ->name('my-prefix.')
    ->withoutMiddleware(['throttle:api'])
    ->middleware(['throttle:my-dedicated-rate-limiter-key'])
    ->group(function () {
        Route::get('my-route', MyController::class);
        // ...
    });

After RouteRegistrar being Macroable will be able to do things like:

Route::prefixAndName('my-prefix')
    ->replaceThrottle('my-dedicated-rate-limiter-key')
    ->group(function () {
        Route::get('my-route', MyController::class);
        // ...
    });

The macro would do things like:

Illuminate\Support\Facades\Route::macro('prefixAndName', function (string $key) {
    return $this->prefix($key)->name($key . '.');
});
Illuminate\Routing\RouteRegistrar::macro('prefixAndName', function (string $key) {
    return $this->prefix($key)->name($key . '.');
});
Illuminate\Routing\Route::macro('prefixAndName', function (string $key) {
    return $this->prefix($key)->name($key . '.');
});

// and similar idea for replaceThrottle

@taylorotwell taylorotwell merged commit 20b257f into laravel:12.x Sep 4, 2025
65 checks passed
@shaedrich
Copy link
Contributor

The macro would do things like:

Illuminate\Support\Facades\Route::macro('prefixAndName', function (string $key) {
    return $this->prefix($key)->name($key . '.');
});
Illuminate\Routing\RouteRegistrar::macro('prefixAndName', function (string $key) {
    return $this->prefix($key)->name($key . '.');
});
Illuminate\Routing\Route::macro('prefixAndName', function (string $key) {
    return $this->prefix($key)->name($key . '.');
});

// and similar idea for replaceThrottle

Looks like there should be a mechanism to put macros on multiple classes at the same time πŸ€”

@ghabriel25
Copy link
Contributor

Looks like there should be a mechanism to put macros on multiple classes at the same time πŸ€”

Something like this

<?php

namespace App\Support;

class MacroRegistrar
{
    public static function register(string $methodName, callable $callback, array $targets)
    {
        foreach ($targets as $target) {
            if (method_exists($target, 'macro')) {
                $target::macro($methodName, $callback);
            }
        }
    }
}
...
use App\Support\MacroRegistrar;

MacroRegistrar::register('prefixAndName', function (string $key) {
    return $this->prefix($key)->name($key . '.');
}, [
    \Illuminate\Support\Facades\Route::class,
    \Illuminate\Routing\RouteRegistrar::class,
    \Illuminate\Routing\Route::class,
]);

@shaedrich
Copy link
Contributor

@ghabriel25 My thoughts exactly! πŸ˜πŸ‘πŸ»

This could even be turned into a helper called macro() or the like for convenience

@shaedrich
Copy link
Contributor

Other approach would be to let the facade define its "macro targets":

abstract class Facade
{
    // …

    /**
     * Get the macro targets.
     *
     * @return class-string[]
     *
     * @throws \RuntimeException
     */
    protected static function getMacroTargets(): array
    {
        throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
    }

    /**
     * @param  class-string|class-string[]|null  $macro
     */
    public static function macro(string $name, object|callable $macro, string|array|null $target = null)
    {
        $target ??= static::getMacroTargets();
        $targets = Arr::wrap($target);

        foreach ($targets as $target) {
           if (! class_exists($target) || ! in_array(Macroable::class, trait_uses_recursive($target))) {
               continue;
           }

           $target::macro($name, $macro);
        } 
    }

    // …
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants