Inject Validator and Session
Replace the beginning of BookController with these imports and constructor. The PHPAML container automatically supplies the requested objects.
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);
}Validate before storing
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);
}Explain failure near the field
Add this block immediately after the title field in create.php. Do the same for author.
<?php foreach ($errors['title'] ?? [] as $error): ?>
<p role="alert"><?= $view->escape($error) ?></p>
<?php endforeach; ?>Status 422 means the request is understood but its values do not follow the rules. The view receives old so the user does not have to retype everything.
Why redirect with 303?
After saving, Response::redirect('/books', 303) tells the browser: “the operation is complete; now read the list with GET.” A refresh then repeats GET, not POST.
/booksLocation: /books/books