laravel / ideas

Issues board used for Laravel internals discussions.
939 stars 28 forks source link

Allow instantiated middlewares #2194

Open brendt opened 4 years ago

brendt commented 4 years ago

Right now, middlewares can only be configured by using their class names. The reason for this, as far as I can tell, is to allow autowiring on middleware constructors. While I understand that reasoning, there are many cases I've personally encountered where manual instantiation of middlewares would be a better fit, especially concerning middleware arguments.

Right now we're only able to pass arguments to middleware using a textual syntax:

Route::middleware([
    MyMiddleware::class . ":{$foo},{$bar}",
]);

Using constants — a common use case — is even a little more cumbersome, because we cannot use string interpolation in those cases:

Route::middleware([
    MyMiddleware::class . ':' . Enum::FOO() . ',' . Enum::BAR(),
]);

People have come up with clever "middleware definition builders", such as this recent example.

I think it's possible to support this syntax though, without any breaking changes:

Route::middleware([
    new MyMiddleware(Enum::FOO(), Enum::BAR()),
]);

In my opinion, there are a few advantages to this approach:

class MyMiddleware
{
    public function __construct(Dependency $fromContainer, string $argument) { /* … */ }

    // …
}
Route::middleware([
    app()->makeWith(MyMiddleware::class, ['argument' => Enum::FOO()]),
])

Granted, using makeWith would mean there's no more type checks done on the arguments, but the possibility is there to allow it.

The same approach already is possible with validation rule classes, and I think it offers more flexibility, at least in my experience.

brendt commented 4 years ago

I've made a draft PR to show how this functionality can be added: https://github.com/laravel/framework/pull/32413