Návod

Middleware

Middleware používej pro společná HTTP pravidla, připojuj ho k routám nebo skupinám a nenechávej v něm business logiku.

K čemu middleware slouží

V Lemonade je middleware PSR-15 vrstva kolem zpracování HTTP requestu. Hodí se pro podmínky nad requestem, hlavičky, CSRF nebo kontrolu přístupu před controllerem. Hranici drž jasnou: middleware = společné HTTP chování, controller = konkrétní HTTP use case a orchestrace, service = aplikační nebo business operace. Pro kompletní příklad formuláře s CSRF pokračuj na Formuláře a POST zpracování.

Připoj middleware k routě nebo skupině

Route middleware použij, když jedno pravidlo potřebuje konkrétní endpoint. Group middleware se hodí, když stejné pravidlo sdílí více rout. V obou případech registruješ třídy jménem a runtime je načte z containeru před 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);
};

Pořadí a předčasné ukončení

Middleware běží v pořadí registrace. Na pořadí záleží, protože jedna vrstva může upravit request, přidat hlavičky do response nebo pipeline ukončit dřív. Volání return $handler->handle($request); pošle request dál. Vlastní response naopak danou větev ukončí bez spuštění zbytku 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();

Napiš malý vlastní middleware

Vlastní middleware implementuje MiddlewareInterface a závislosti získává přes constructor injection. Drž ho malý a čistě zaměřený na HTTP. Jakmile začne řešit persistenci nebo znovupoužitelnou business logiku, přesuň ji do aplikační služby.

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);
    }
}