Návod

Middleware

Middleware používaj na spoločné HTTP pravidlá, pripájaj ho k routám alebo skupinám a nenechávaj v ňom business logiku.

Na čo middleware slúži

V Lemonade je middleware PSR-15 vrstva okolo spracovania HTTP requestu. Hodí sa na podmienky nad requestom, hlavičky, CSRF alebo kontrolu prístupu pred controllerom. Hranicu drž jasnú: middleware = spoločné HTTP správanie, controller = konkrétny HTTP use case a orchestration, service = aplikačné alebo business operácie. Kompletný príklad formulára s CSRF nájdeš vo Formulároch a POST spracovaní.

Pripoj middleware k route alebo skupine

Route middleware použi, keď jedno pravidlo potrebuje konkrétny endpoint. Group middleware sa hodí, keď rovnaké pravidlo zdieľa viac rout. V oboch prípadoch registruješ triedy menom a runtime ich načíta z containeru pred controllerom.

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

Poradie a predčasné ukončenie

Middleware beží v poradí registrácie. Na poradí záleží, pretože jedna vrstva môže upraviť request, pridať hlavičky do response alebo pipeline ukončiť skôr. Volanie return $handler->handle($request); pošle request ďalej. Vlastná response naopak danú vetvu ukončí bez spustenia zvyšku 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();

Napíš malý vlastný middleware

Vlastný middleware implementuje MiddlewareInterface a závislosti získava cez constructor injection. Drž ho malý a zameraný na HTTP. Keď začne riešiť persistenciu alebo znovupoužiteľnú business logiku, presuň ju do aplikačnej 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);
    }
}