Documentation · Chapitre 04

Valider, expliquer,
puis rediriger.

Une bonne validation ne se contente pas de refuser : elle conserve la saisie et indique précisément ce qu’il faut corriger.

Nous poursuivons le projet reading-list. Les données seront conservées dans la session avant d’introduire une base de données.

Injectez le Validator et la Session

Remplacez le début de BookController par ces imports et ce constructeur. Le conteneur PHPAML fournit automatiquement les objets demandés.

phpaml — zsh
use PHPAML\Http\Request;
use PHPAML\Http\Response;
use PHPAML\Mvc\Controller;
use PHPAML\Mvc\View;
use PHPAML\Session\Session;
use PHPAML\Validation\Validator;

final class BookController extends Controller
{
    public function __construct(
        View $view,
        private Session $session,
        private Validator $validator,
    ) {
        parent::__construct($view);
    }

Validez avant de conserver

phpaml — zsh
public function store(Request $request): Response
{
    $data = [
        'title' => trim((string) $request->input('title', '')),
        'author' => trim((string) $request->input('author', '')),
    ];

    $valid = $this->validator->validate($data, [
        'title' => ['required', 'string', 'min:2', 'max:120'],
        'author' => ['required', 'string', 'min:2', 'max:100'],
    ]);

    if (!$valid) {
        return $this->view('books/create.php', [
            'errors' => $this->validator->errors(),
            'old' => $data,
        ], 422);
    }

    $books = $this->session->get('books', []);
    $nextId = $books === [] ? 1 : max(array_column($books, 'id')) + 1;
    $books[] = ['id' => $nextId] + $data;
    $this->session->set('books', $books);

    return Response::redirect('/books', 303);
}

Expliquez l’échec près du champ

Ajoutez ce bloc juste après le champ title dans create.php. Faites la même chose pour author.

phpaml — zsh
<?php foreach ($errors['title'] ?? [] as $error): ?>
    <p role="alert"><?= $view->escape($error) ?></p>
<?php endforeach; ?>

Le statut 422 signifie que la requête est comprise mais que ses valeurs ne respectent pas les règles. La vue reçoit old pour ne pas obliger l’utilisateur à tout retaper.

Pourquoi rediriger avec 303 ?

Après l’enregistrement, Response::redirect('/books', 303) indique au navigateur : « l’opération est terminée; consulte maintenant la liste avec GET ». Une actualisation répète alors GET, pas le POST.

1POST/books
→
2303Location: /books
→
3GET/books