Middleware
Com funcionen els middleware a Laravel: middleware global, de grups i personalitzats.
Què és un middleware?#
Un middleware és una capa de codi que s'executa entre la recepció d'una petició HTTP i l'execució del controlador. Pensa en els middleware com a filtres: cada petició ha de passar per ells abans d'arribar al seu destí, i cada middleware pot inspeccionar la petició, modificar-la, bloquejar-la o deixar-la continuar.
Un exemple pràctic: el middleware auth de Laravel comprova si l'usuari està autenticat. Si ho està, la petició continua cap al controlador. Si no, redirigeix l'usuari a la pàgina de login.
Crear un middleware#
Per crear un middleware personalitzat, utilitza la comanda Artisan:
php artisan make:middleware CheckAgeAixò genera un fitxer a app/Http/Middleware/CheckAge.php amb un mètode handle(). Aquest mètode rep la petició i un closure $next que representa el següent pas de la cadena:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckAge
{
public function handle(Request $request, Closure $next)
{
if ($request->age < 18) {
return redirect('home');
}
return $next($request);
}
}Cridar $next($request) passa la petició al següent middleware o al controlador. Si no el crides, la petició queda bloquejada a aquest punt. Això és el que passa quan fas un redirect() o un abort(): la petició no continua.
Registrar middleware#
A Laravel 11, els middleware es registren al fitxer bootstrap/app.php. Pots registrar-los de manera global (s'executen a totes les peticions) o com un alias que després assignes a rutes concretes:
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
// Middleware global: s'executa a totes les peticions
$middleware->append(CheckAge::class);
// Alias: per usar a rutes específiques
$middleware->alias([
'check.age' => CheckAge::class,
]);
})Els middleware globals són adequats per a funcionalitats que afecten tota l'aplicació, com el manteniment de sessions o la protecció CSRF. Els alias et permeten aplicar middleware de manera selectiva.
Assignar middleware a rutes#
Un cop registrat amb un alias, pots assignar un middleware a una ruta concreta o a un grup de rutes:
// A una ruta individual
Route::get('/adult', function () {
// Només accessible si passa el middleware
})->middleware('check.age');
// Múltiples middleware
Route::get('/admin', function () {
// ...
})->middleware(['auth', 'admin']);Per aplicar el mateix middleware a diverses rutes, pots fer servir un grup:
Route::middleware(['auth'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::get('/perfil', [ProfileController::class, 'show']);
Route::get('/configuracio', [SettingsController::class, 'index']);
});Totes les rutes dins del grup compartiran el middleware auth, de manera que qualsevol usuari no autenticat serà redirigit al login.
Middleware amb paràmetres#
Els middleware també poden rebre paràmetres addicionals. Això és útil per crear middleware reutilitzables que es comporten diferent segons el context:
class CheckRole
{
public function handle(Request $request, Closure $next, string $role)
{
if ($request->user()->role !== $role) {
abort(403);
}
return $next($request);
}
}A les rutes, passes el paràmetre separat per dos punts:
Route::get('/admin', function () {
// Només per a administradors
})->middleware('role:admin');
Route::get('/editor', function () {
// Només per a editors
})->middleware('role:editor');El valor admin o editor arriba al tercer paràmetre del mètode handle(). Així, un sol middleware serveix per controlar l'accés a múltiples rols.
Middleware terminables#
Alguns middleware necessiten fer feina després que la resposta s'ha enviat al navegador. Per exemple, desar logs o alliberar recursos. Per a això, pots definir un mètode terminate():
class LogResponse
{
public function handle(Request $request, Closure $next)
{
return $next($request);
}
public function terminate(Request $request, $response)
{
// S'executa després d'enviar la resposta
Log::info('Petició processada', [
'url' => $request->url(),
'status' => $response->status(),
]);
}
}El mètode terminate() s'executa un cop la resposta ja ha estat enviada al client, de manera que no afecta el temps de càrrega de la pàgina.