Middleware

League Route підтримує PSR-15 middleware. Ядро не постачає власних middleware-класів — CSRF, session, flash живуть у extensions / App. Навіщо так: Core лишається тонким; поведінка запиту оголошується там, де її видно — у route file на маршруті чи групі.

RouteStrategy викликається після middleware-ланцюжка League. Тому middleware — місце для request/response pipeline (заголовки, short-circuit 401, модифікація response). Якщо потрібен лише check за ім’ям маршруту без відповіді — див. Route interceptors.

Контракт PSR-15

Класичний onion: або пропускаєте далі через $handler->handle(), або повертаєте власний response. Приклад нижче — вимірювання часу: змінює response після handler, не чіпаючи бізнес-логіку controller-а.

use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

final class TimingMiddleware implements MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler,
    ): ResponseInterface {
        $start = microtime(true);
        $response = $handler->handle($request);
        return $response->withHeader('X-Response-Time', (string) (microtime(true) - $start));
    }
}

Клас має бути доступний контейнеру — League Route створює його через DI при lazyMiddleware() / lazyMiddlewares(). Залежності (FlashBag, CSRF) інжектить у constructor, не через globals.

Реєстрація

На одному маршруті — коли правило унікальне. На групі — коли однакова історія запиту (усі HTML-форми, усі API з auth). Порядок у масиві — частина контракту UX (спочатку previous URL, потім validation, потім CSRF — як у рецептах).

// На одному маршруті
$router->get('/ping', [PingHandler::class, 'ping'])
    ->lazyMiddleware(TimingMiddleware::class);

// На групі
$router->group('/api', function(RouteGroup $router): void {
    $router->get('/status', [StatusHandler::class, 'show']);
})->lazyMiddlewares([TimingMiddleware::class]);

Порядок

Middleware у масиві виконуються у порядку оголошення: перший отримує request першим; перед handler викликається весь ланцюжок. Це не «список плагінів», а історія запиту — міняйте порядок лише свідомо (інакше redirectBack / flash легко зламати).

Middleware і interceptors

Middleware — PSR-15 ланцюжок League Route до RouteStrategy::invokeRouteCallable(): може повернути response і змінити його. Route interceptors — хуки всередині RouteStrategy після middleware: глобальний pre-check за метаданими маршруту, зазвичай через exception. Оберіть інструмент за тим, чи потрібен response pipeline.

404 (not found)

Коли matched route немає, League кидає NotFoundException. HttpKernelServiceProvider приймає опційний notFoundMiddleware — PSR-15 middleware: instance або Closure(ContainerInterface): MiddlewareInterface (не class-string). Передається в RouteStrategy::getNotFoundDecorator(). Навіщо в constructor kernel, а не «глобальний 404»: щоб збірка явно вирішувала, чи є кастомна сторінка, чи лишається дефолт League.