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:
- Used the Session facade throughout the codebase, but it didn’t work.
- Used
back()->with('locale', $locale);
when returning in thesetLocalization()
function in the LocalizationController, but it didn’t work. - 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
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 theweb
group.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 yourwithMiddleware()
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 theweb
route middleware group.To get your desired result, you can use the
appendToGroup()
method instead of theappend()
method. This will append your middleware to the specified middleware group, instead of adding it as a global middleware.