Framework: [5.0] Ability to add Kernel middleware at runtime

Created on 24 Oct 2014  路  30Comments  路  Source: laravel/framework

I need to add middleware to the kernel at runtime from a service provider. Something along the lines of:

public function addMiddleware($middleware)
{
    $this->middlware[] = $middlware;
}

Most helpful comment

It is great that we now have the ability to add dynamic global middleware with

// Register Middleware
$kernel = $this->app->make('Illuminate\Contracts\Http\Kernel');
$kernel->pushMiddleware('Mrcore\Modules\Wiki\Http\Middleware\AnalyzeRoute');

BUT we still need the ability to define route based middleware as well. This is critical with adding packages that require their own custom middleware. Without this feature, the packages has to resort back to using Laravel 4 Filters.

Started a new issues about this at https://github.com/laravel/framework/issues/8917

All 30 comments

Just call the middleware method on the router class.

Thats not the same. That middleware doesn't run on every request, right?

Ahh, yes. I see what you mean now.

It would be really cool to have a way to do this because the current way to do it relies on modifying the Kernel class.

By the time the service provider is called, seems to late to add anything into the kernel.

Right now, you have to add both a service provider & the middleware config. Would be nice to just add the 1 & have it work.

Yeh, I agree.

I don't know this work or not, I think it's possible though. Maybe something like this:

$this->app['events']->listen('router.matched', function($route, $request)
{
    $middleware = array_pluck($route->middleware(), 'yourmiddleware');

    $routeAction =  $route->getAction();
    //replace with your middleware
    $routeAction['middleware'] = $middleware;

       //replace route actions
    $route->setAction($routeAction);
});

I would also like this. This is actually possible in L4, so I'm assuming this request is for L5?

In my case, I use a Middleware for https://github.com/barryvdh/laravel-debugbar and https://github.com/barryvdh/laravel-cors because Middleware is run also on errors, and the after-filter isn't. But haven't looked into L5.0 much, so not sure if this isn't possible yet.

Anyone found a way around this yet from a service provider, until hopefully it's added back in?

This would be useful for packages that need to add middleware. +1 from me.

I added a method addMiddleware() to my App\Http\Kernel class.
Now I can add middlewares in my ServiceProviders. At least in my own Projects.
For package development this method should be part of the core.

$this->app['Illuminate\Contracts\Http\Kernel']->addMiddleware('Middleware');

The bootstrap happens before the request get send through the middleware stack.

See. Illuminate\Foundation\Http\Kernel.php

protected function sendRequestThroughRouter($request)
    {
        $this->app->instance('request', $request);

        $this->bootstrap();

        return (new Pipeline($this->app))
                    ->send($request)
                    ->through($this->middleware)
                    ->then($this->dispatchToRouter());
    }

+1 for this feature from me.

@barryvdh, from above duplicate issue:

Yes, would like that too.
I think the argument against that was that it would be difficult to manage the order of the middleware.

There is already limited control of the ordering of things. First global middleware, then before filters, then route middleware, etc.

If your ordering matters, you can always consider _not_ to add the global middleware through your MyServiceProvider@boot method, but ask implementers to add them to the kernel manually.

so is there no solution?

None that I'm aware of.

So far I've only come up with a workaround that only partially solves the issue of ordering.
By all means I do not recommend this for everyone it's highly dependant on your situation.

What currently solves my problems is that I'm using an event handler on router.matches (called after the global middleware and before the route middleware). This event handler does a last minute modification of the _route middleware_ to add mine. You can think of your own algorithm of how to add it, but I went with: add it as first middleware _unless it's already defined_. Meaning a programmer can override the location, but the default is auto-addition to the front.

I'm going to submit a pull for this. I agree with the above statement in that if ordering really matters then it can be added manually.

Best to probably check in the addMiddleware method if the middleware already exists and if so skip it. That way the end-user of the package can adjust the order if required.

FYI, this has been added (see above PR)
https://github.com/laravel/framework/blob/v5.0.14/src/Illuminate/Foundation/Http/Kernel.php#L154-L184

This issue can be closed.

Thanks @barryvdh.

And @jasonlewis. :)

is there a way to add $routeMiddelware at runtime?

I'm trying to figure out where's the best place to add a call to prependMiddleware for a service provider that is only necessary for a development environment.

To be precise, I have a project with the clockwork package installed for debugging reasons.
I've extracted the binding of the package's serviceProvider and I've placed it in the App\Providers\AppServiceProvider.php.

But to be honest, I'm struggling to find the correct place to add the next piece of code (or whatever is needed to accomplish this action...):

if (config('app.debug'))
{
    $kernel->prependMiddleware('Clockwork\Support\Laravel\ClockworkServiceProvider');
}

Basically I don't know when/where is the best moment, during the request lifecycle...
@GrahamCampbell @barryvdh @anybody any suggestion?

Btw, I've tried this example but I get an error...

Please ask on the forums.

Any plans on getting this fixed for package maintainers in 5.1?

It has been added we are already using the fix our packages, recheck barrys commit which adds the methods.

You're right, I was using App\Http\Kernel which doesn't work, my apologies.

It is great that we now have the ability to add dynamic global middleware with

// Register Middleware
$kernel = $this->app->make('Illuminate\Contracts\Http\Kernel');
$kernel->pushMiddleware('Mrcore\Modules\Wiki\Http\Middleware\AnalyzeRoute');

BUT we still need the ability to define route based middleware as well. This is critical with adding packages that require their own custom middleware. Without this feature, the packages has to resort back to using Laravel 4 Filters.

Started a new issues about this at https://github.com/laravel/framework/issues/8917

Maybe this one can help you guys.
This code is for route middleware
Add this code to any service provider

$this->app['router']->middleware('yourroutermiddleware','Your\Class\Middleware');

change the yourroutermiddleware, etc. backendauth
change the Your\Class\Middleware to your Middleware class, etc. Example\Vendor\MyMiddleware

sample router

Route::get("yoururl",["middleware" => "backendauth",function(){}]);

This code is tested and working.

Yes that is what crynobone's replied in https://github.com/laravel/framework/issues/8917 and it works. So we can dynamically add both global middleware with prependMiddleware() and pushMiddleware() and route based middleware with

public function boot(\Illuminate\Routing\Router $router) {
    $router->middleware('name', 'MiddlewareClass');
}

@GrahamCampbell
in 5.2 there is Middleware groups
need to push and prependMiddleware to a group say "web"
https://github.com/laravel/framework/issues/12141

Was this page helpful?
0 / 5 - 0 ratings

Related issues

RomainSauvaire picture RomainSauvaire  路  3Comments

SachinAgarwal1337 picture SachinAgarwal1337  路  3Comments

lzp819739483 picture lzp819739483  路  3Comments

felixsanz picture felixsanz  路  3Comments

digirew picture digirew  路  3Comments