skip to Main Content

I was working on adding localization to my Laravel 11 project, and I created a middleware called SetLocale that consists of the codebase similar to below:

public function handle(Request $request, Closure $next): Response
    {
        App::setLocale(session()->get('locale'));
        return $next($request);
    }

I added it to my bootstrap/app.php file like this:

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__ . '/../routes/web.php',
        commands: __DIR__ . '/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->append(SetLocale::class);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

In my LocalizationController, I set the session like this:

public function setLocalization(string $locale): RedirectResponse
{
    session()->put('locale', $locale);
    App::setLocale($locale);
    return back();
}

My route in web.php looks like this:

Route::get('/locale/{locale}', [LocalizationController::class, 'setLocalization'])->name('locale.switch');

Here’s what I tried:

  1. Used the Session facade throughout the codebase, but it didn’t work.
  2. Used back()->with('locale', $locale); when returning in the setLocalization() function in the LocalizationController, but it didn’t work.
  3. Tried various changes, but I couldn’t retrieve the ‘locale’ session data in my middleware.

The only way I got it to work was by wrapping the middleware around the route like this:

Route::prefix('localization')->middleware([SetLocale::class])->group(function() {
   Route::get('/locale/{locale}', [LocalizationController::class, 'setLocalization'])->name('locale.switch');
});

Is my use of global middleware incorrect, or did Laravel change how it handles sessions for global middleware?

Just an FYI, Laravel has now moved its middleware to elsewhere. Now it’s a clean file located in the bootstrap/app.php file.

Thanks for your help.

2

Answers


  1. Global middleware run before route middleware. The middleware that starts the session is a route middleware; there is no session when the global middleware run. Add your middleware as a route middleware to the entire group of routes you want just like the web group is applied to all web routes or add this middleware to the web group.

    Login or Signup to reply.
  2. To expand on the answer provided by @lagbox, the middleware that handles the session is defined as part of the web route middleware group. It is not defined as a global middleware. As mentioned by @lagbox, the route middleware are run after the global middleware.

    The append() method you’ve used in your withMiddleware() callback will append the provided middleware to the global middleware. This is not what you want, since your new appended global middleware will run before the session middleware defined in the web route middleware group.

    To get your desired result, you can use the appendToGroup() method instead of the append() method. This will append your middleware to the specified middleware group, instead of adding it as a global middleware.

    return Application::configure(basePath: dirname(__DIR__))
        ->withRouting(
            web: __DIR__ . '/../routes/web.php',
            commands: __DIR__ . '/../routes/console.php',
            health: '/up',
        )
        ->withMiddleware(function (Middleware $middleware) {
            // Use appendToGroup() to add the middleware to the 'web' group.
            $middleware->appendToGroup('web', SetLocale::class);
        })
        ->withExceptions(function (Exceptions $exceptions) {
            //
        })->create();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search