Views a formuláře

Renderer vykreslí PHP view, funkce e() escapuje dynamický výstup a csrfField() vloží skryté pole s CSRF tokenem.

Předání dat do view

Controller načte článek z aplikační ArticleRepository a předá jej ViewRendererInterface::render() pod klíčem article. Název articles.detail vybírá PHP view z dalšího souboru; render() vrací HTML odpověď. Pokud je potřeba jen vykreslený řetězec, rozhraní má také content().

app/Controllers/ArticleController.php
<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Services\ArticleRepository;

use Lemonade\Framework\View\ViewRendererInterface;
use Psr\Http\Message\ResponseInterface;

final readonly class ArticleController
{
    public function __construct(
        private ViewRendererInterface $views,
        private ArticleRepository $articles,
    ) {}

    public function detail(string $id): ResponseInterface
    {
        return $this->views->render('articles.detail', [
            'article' => $this->articles->get($id),
        ]);
    }
}

Šablona čte pole article předané controllerem a vypisuje title a body. Helper e() escapuje obě dynamické hodnoty; typ a existence článku jsou odpovědností aplikační repository a controlleru.

app/Views/articles/detail.php
<?php

declare(strict_types=1);

/** @var array{id:string,title:string,body:string} $article */ ?>

<article>
    <h1><?= e($article['title']) ?></h1>
    <p><?= e($article['body']) ?></p>
</article>

Formulář a CSRF

Routing.php registruje GET akci pro formulář a POST akci pro odeslání. Na POST routě CsrfMiddleware ověří token před ContactController::store(); token vloží view v dalším souboru. CSRF vyžaduje nakonfigurovanou session.

Route and view
<?php

use App\Controllers\ContactController;
use Lemonade\Framework\Routing\ControllerAction;
use Lemonade\Framework\Security\Csrf\CsrfMiddleware;

$router->getNamed('contact.form', '/contact', ControllerAction::for(ContactController::class, 'form'));
$router->postNamed('contact.store', '/contact', ControllerAction::for(ContactController::class, 'store'))
    ->middleware(CsrfMiddleware::class);

View odesílá data na pojmenovanou POST route contact.store. csrfField() vloží skryté pole s tokenem a e() escapuje URL i hodnotu emailu při vykreslení; email dodává akce form().

app/Views/contact/form.php
<form method="post" action="<?= e($this->url('contact.store')) ?>">
    <?= $this->csrfField() ?>
    <label for="email">E-mail</label>
    <input id="email" name="email" value="<?= e($email) ?>">
    <button type="submit">Send</button>
</form>

Validace vstupu

ContactController zobrazuje formulář s prázdným emailem. Při POST ověří, že getParsedBody() vrátil pole, a předá ho FormValidation. Chyby vrátí přes Responses jako JSON 422; při úspěchu vrátí validated() jako JSON 200. Zprávu neodesílá ani neukládá.

Controller action
<?php

declare(strict_types=1);

namespace App\Controllers;

use Lemonade\Framework\Http\Response\Responses;
use Lemonade\Framework\Validation\FormValidation;
use Lemonade\Framework\View\ViewRendererInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

final readonly class ContactController
{
    public function __construct(
        private ViewRendererInterface $views,
        private FormValidation $validator,
        private Responses $responses,
    ) {}

    public function form(): ResponseInterface
    {
        return $this->views->render('contact.form', ['email' => '']);
    }

    public function store(ServerRequestInterface $request): ResponseInterface
    {
        $body = $request->getParsedBody();
        $data = is_array($body) ? $body : [];
        $result = $this->validator->field('email', 'E-mail')
            ->required()->email()->maxLength(150)->validate($data);
        if (!$result->isValid()) {
            return $this->responses->json(['errors' => $result->errors()], 422);
        }

        return $this->responses->json(['data' => $result->validated()], 200);
    }
}

Dokumentace validace a CSRF →

Související dokumentaceVíce informací najdete v kapitole Views a layouty v dokumentaci.

← Všechny ukázky