How to set the Laravel middleware order of execution?

19,604

Solution 1

The application logic resides in the controller's methods. So basically application lives in the controller's methods, not in the whole controller itself.

Middleware runs BEFORE the request enters the respective controller method. And thus, this is always OUTSIDE the real application. No controller method is executed unless all the Middlewares are passing the request.

The $this->middleware("My\Middleware"); statements that you put in the controller constructor, REGISTERS the My\Middleware for checking before the request enters the application.

If you see the code of a middleware and if the request is passing, then we send it to the next middleware using the $next($request); statement. This allows multiple middlewares to be executed for a single request. Now, if Laravel run the middleware right at the $this->middleware(...); statement, Laravel would probably not be able to know which middleware should be next checked.

So, Laravel solves this by registering all the middlewares first, then passing the request through all the middlewares one by one.

Solution 2

Another answer to cover another use case to that question

If it's related to the order between middleware it self

You can update the $middlewarePriority in your App\Kernel.

Solution 3

Set Middleware Priority in App\Http\Kernel

For example, here I need my custom auth middleware to run first (before substitute bindings), so I unshift it onto the stack:

public function __construct(Application $app, Router $router)
{
    /**
     * Because we are using a custom authentication middleware,
     * we want to ensure it's executed early in the stack.
     */
    array_unshift($this->middlewarePriority, MyCustomApiAuthMiddleware::class);

    parent::__construct($app, $router);
}

Alternatively, you could override that entire priority structure if you needed explicit control (not recommended because you'll have to pay closer attention during upgrades to see if the framework changes). Specific to this issue is the SubstituteBindings class that handles route model binding, so just make sure your auth middleware comes sometime before that.

/**
 * The priority-sorted list of middleware.
 *
 * Forces the listed middleware to always be in the given order.
 *
 * @var array
 */
protected $middlewarePriority = [
    \App\Http\Middleware\MyCustomApiAuthMiddleware::class
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \Illuminate\Auth\Middleware\Authenticate::class,
    \Illuminate\Session\Middleware\AuthenticateSession::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \Illuminate\Auth\Middleware\Authorize::class,
];

Solution 4

They updated the order of execution between middlewares, controller and controller's construct.

Previously it was:

1. The global middleware pipeline
2. The route middleware pipeline
3. The controller middleware pipeline

Now its:

1. The global middleware pipeline
2. Controller's Construct
3. The route & controller middlewares

Read more here: https://laracasts.com/discuss/channels/general-discussion/execution-order-in-controllers-constructor-whit-middleware https://laravel-news.com/controller-construct-session-changes-in-laravel-5-3

Share:
19,604

Related videos on Youtube

Samuel Shen
Author by

Samuel Shen

Updated on June 04, 2022

Comments

  • Samuel Shen
    Samuel Shen almost 2 years

    The Laravel 5 documentation describes two ways of assigning Middleware:

    1. Assign middleware to the controller's route.
    2. Specify middleware within your controller's constructor.

    However, I realised that any code written in the controllers __construct() function will run before the Middleware, even if the Middleware is declared on the first line of the controller's __construct function.

    I found a bug report for a similar issue in the Laravel github repository. However a collaborator closed the issue stating "This is the expected behaviour.".

    I am thinking that middleware should be "layers" outside the application, while the __construct function is part of the application.

    Why is the __construct function executed before the middleware (given it is declared before middleware runs)? and why this is expected?

    • Jeemusu
      Jeemusu almost 9 years
      I just did a few tests to confirm. If you want the middleware to execute before your controllers __construct() you need to assign the middleware to the route. Otherwise it will always be executed at the end of the __construct() even if assigned on the very first line of the construct().
    • Jeemusu
      Jeemusu almost 9 years
      I created a quick example to outline what you are describing, feel free to add it to your question. notehub.org/2015/6/26/say-we-have-a-controller----welcomecon‌​tr
    • Samuel Shen
      Samuel Shen almost 9 years
      @Jeemusu Thanks for your comment. Yup, I also found out this difference between the two ways of assigning middleware. However, by placing the middleware at the end of execution flow in the constructor, is it against the Request Lifecycle (laravel.com/docs/5.1/lifecycle), since Dispatch Request should be at the end?
  • Andrew Brown
    Andrew Brown about 8 years
    an interesting case with this it where the middleware runs in respect to the constructor. Any global middleware actually seems to run before the constructor, while any local middleware runs after the constructor. This inconsistency has caused me confusion and troubles in the past.
  • Shady Keshk
    Shady Keshk over 7 years
    so what runs first cause the answer is unclear for me i expect it to be as follow group route => route specified (by array order) then controler construct . is this true
  • JohnL
    JohnL over 6 years
    I too am still mystified on how laravel decides which order to run them in. Is it alphabetical?
  • Raheel Hasan
    Raheel Hasan about 5 years
    well right now in 5.7, even the global middleware is running AFTER the controller's construct!
  • Fadi Ramzi
    Fadi Ramzi over 4 years
    This should be accepted answer, such this way i can order the execution of the middlewares
  • gabelbart
    gabelbart over 2 years