Przewodnik

Middleware

Używaj middleware do wspólnych reguł HTTP, przypinaj je do tras lub grup i nie przenoś do nich logiki biznesowej.

Do czego służy middleware

W Lemonade middleware to warstwa PSR-15 otaczająca obsługę requestu HTTP. Nadaje się do warunków requestu, nagłówków, CSRF lub kontroli dostępu przed controllerem. Zachowaj wyraźną granicę: middleware = wspólne zachowanie HTTP, controller = konkretny use case HTTP i orkiestracja, service = operacje aplikacyjne lub biznesowe. Pełny przykład formularza z CSRF znajdziesz w sekcji Formularze i obsługa POST.

Przypnij middleware do trasy lub grupy

Użyj route middleware, gdy jedna trasa wymaga dodatkowej reguły HTTP. Group middleware sprawdza się, gdy kilka tras współdzieli ten sam mechanizm. W obu przypadkach rejestrujesz klasy po nazwie, a runtime rozwiązuje je z containera przed controllerem.

example.php
<?php

use App\Controllers\ArticleController;
use App\Controllers\ProfileController;
use App\Http\Middleware\RequirePreviewHeaderMiddleware;
use App\Http\Middleware\RequireProfileHeaderMiddleware;
use Lemonade\Framework\Routing\Router;

return static function (Router $router): void {
    $router
        ->getNamed('articles.preview', '/articles/preview', ArticleController::class . '@preview')
        ->middleware(RequirePreviewHeaderMiddleware::class);

    $router
        ->group('/profile', static function (Router $router): void {
            $router->getNamed('profile.show', '', ProfileController::class . '@show');
            $router->postNamed('profile.update', '/edit', ProfileController::class . '@update');
        })
        ->middleware(RequireProfileHeaderMiddleware::class);
};

Kolejność i wcześniejsze zakończenie

Middleware działa w kolejności rejestracji. Kolejność ma znaczenie, ponieważ jedna warstwa może zmienić request, dodać nagłówki do response albo wcześniej zakończyć pipeline. return $handler->handle($request); przekazuje request dalej. Zwrócenie własnej response kończy daną gałąź bez uruchamiania pozostałej części pipeline.

example.php
<?php

use App\Http\Middleware\RequestIdMiddleware;
use Lemonade\Framework\Core\Context\ApplicationContextFactory;
use Lemonade\Framework\Core\KernelFactory;
use Lemonade\Framework\Http\Middleware\ErrorHandlingMiddleware;
use Lemonade\Framework\Http\Middleware\MiddlewareStack;

$context = (new ApplicationContextFactory())->fromGlobals(__DIR__);
$kernel = (new KernelFactory())->create($context);

$kernel->framework()->middleware(static function (MiddlewareStack $stack): void {
    $stack->insertAfter(ErrorHandlingMiddleware::class, RequestIdMiddleware::class);
});

$kernel->handle();

Napisz mały własny middleware

Własny middleware implementuje MiddlewareInterface i otrzymuje zależności przez constructor injection. Utrzymuj go małym i skupionym na HTTP. Jeśli zaczyna obsługiwać persistence lub współdzieloną logikę biznesową, przenieś tę pracę do usługi aplikacyjnej.

example.php
<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

final class RequirePreviewHeaderMiddleware implements MiddlewareInterface
{
    public function __construct(
        private readonly ResponseFactoryInterface $responses,
    ) {}

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        if ($request->getHeaderLine('X-Preview-Mode') !== 'allow') {
            return $this->responses->createResponse(403);
        }

        return $handler->handle($request);
    }
}