Session brick

Flash після redirect, CSRF-токен, «попередній URL» — усе це потребує стану між запитами. Без session web-форма лишається stateless: після POST з помилкою немає куди покласти errors/old, а CSRF не має де жити. addSession() на ConceptStack вмикає Symfony session, flash bag і (opt-in) CSRF token manager. Повертає SessionBuilder. Рецепт — Session і CSRF.

Навіщо не підтягувати Session автоматично з Http: API-треки часто мають лишатися без cookie. Capability явна — немає «сюрпризу» у контейнері. CSRF — не окремий top-level brick: withCsrf() на Session, бо без session token manager не має сенсу. Middleware (VerifyCsrfTokenMiddleware, …) лишаються в routes/*.php — Stack їх не реєструє: порядок pipeline — історія запиту.

Методи SessionBuilder:

Метод Параметри Опис Залежність
setOptions() array<string, mixed> $options Native session options (cookie_*, use_strict_mode, …) —
setHandlerFactory() Closure(): SessionHandlerInterface Фабрика handler-а (glue передає шлях до storage явно) —
withCsrf() — Opt-in: CsrfTokenManagerInterface у контейнері — (middleware — у routes)

setOptions()

$stack->addSession()
    ->setOptions([
        'cookie_lifetime' => 0,
        'cookie_path' => '/',
        'cookie_httponly' => true,
        'cookie_samesite' => 'Lax',
    ]);

Cookie lifetime, SameSite, httponly — це політика безпеки й UX, не «внутрішня деталь пакета». Опції йдуть у NativeSessionStorage (extension-session-symfony), як у Symfony — без окремого config brick на ранніх кроках рецепта.

setHandlerFactory()

use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler;

$stack->addSession()
    ->setHandlerFactory(function () use ($rootPath) {
        return new NativeFileSessionHandler($rootPath . 'storage/sessions');
    });

Stack навмисно не вгадує шлях до storage: у Docker, CLI і shared hosting корені різні. Glue передає factory, що повертає SessionHandlerInterface. Без setHandlerFactory() — NativeFileSessionHandler() з PHP defaults (часто незручно в контейнері). Каталог storage/sessions має бути writable.

withCsrf()

$stack->addSession()
    ->setHandlerFactory(function () use ($rootPath) {
        return new NativeFileSessionHandler($rootPath . 'storage/sessions');
    })
    ->withCsrf();

Opt-in, коли є HTML-форми з POST: реєструє CsrfServiceProvider, token у session (extension-csrf). Сам brick не перевіряє POST — це робота middleware у route file, наприклад:

$router->lazyMiddlewares([
    HandleCsrfExceptionMiddleware::class,
    VerifyCsrfTokenMiddleware::class,
]);

Поле форми: _csrf_token (CsrfField::NAME). Ключі flash і URL для redirect back — у Concept\App\Http\SessionKey (див. крок 5 і крок 7). На ранніх кроках рецепта token у view передають явно з controller; пізніше (Обробка помилок) централізуємо через ShareViewDataMiddleware → VIEW_PAYLOAD, щоб не копіювати csrf/flashes/errors у кожному action.

Що реєструє brick

  • SessionServiceProvider → SessionInterface, FlashBagInterface
  • З withCsrf(): CsrfServiceProvider → CsrfTokenManagerInterface

Session стартує при першому resolve SessionInterface (lazy) — немає cookie на чистих API-маршрутах, якщо їх не торкались. Flash і CSRF використовують той самий session store.

Рецепт — Session і CSRF. Каталог bricks — Bricks і addX().