Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Формы и проверка данных

Форме нужны два маршрута: GET показывает пустую форму, POST принимает отправленные данные. Данным от посетителя нельзя доверять, поэтому перед сохранением их проверяют. В Slim нет встроенной проверки — её пишут сами или подключают библиотеку.

Форма

{# templates/posts/new.twig #}
{% extends 'layout.twig' %}
 
{% block content %}
    <h1>Новая статья</h1>
 
    <form method="post" action="{{ url_for('posts.store') }}">
        <input type="text" name="title" placeholder="Заголовок">
        <textarea name="body" placeholder="Текст"></textarea>
        <button type="submit">Сохранить</button>
    </form>
{% endblock %}

Действие, которое её показывает:

// src/Action/NewPostAction.php
final class NewPostAction
{
    public function __construct(private Twig $twig) {}
 
    public function __invoke(Request $request, Response $response): Response
    {
        return $this->twig->render($response, 'posts/new.twig');
    }
}

Строки namespace и use здесь и дальше опущены — они такие же, как в прежних действиях.

Маршруты

// config/routes.php
$app->get('/posts/new', NewPostAction::class)->setName('posts.new');
$app->post('/posts', CreatePostAction::class)->setName('posts.store');

По адресу /posts/new откроется форма. Кнопка пока ведёт к ошибке: второго действия ещё нет.

Проверка

Правила проверки выносят в отдельный класс в папке src/Validation/. Он получает данные и возвращает массив ошибок — пустой, если всё в порядке:

// src/Validation/PostValidator.php
namespace App\Validation;
 
final class PostValidator
{
    public function validate(array $data): array
    {
        $errors = [];
 
        if (mb_strlen(trim($data['title'] ?? '')) < 5) {
            $errors['title'] = 'Заголовок должен быть не короче 5 символов';
        }
 
        if (trim($data['body'] ?? '') === '') {
            $errors['body'] = 'Введите текст статьи';
        }
 
        return $errors;
    }
}

Приём данных

// src/Action/CreatePostAction.php
final class CreatePostAction
{
    public function __construct(
        private PostRepository $posts,
        private PostValidator $validator,
        private Twig $twig,
    ) {}
 
    public function __invoke(Request $request, Response $response): Response
    {
        $data = (array) $request->getParsedBody();
        $errors = $this->validator->validate($data);
 
        if ($errors !== []) {
            return $this->twig->render($response->withStatus(422), 'posts/new.twig', [
                'errors' => $errors,
                'old' => $data,
            ]);
        }
 
        $this->posts->create(trim($data['title']), trim($data['body']));
 
        $url = RouteContext::fromRequest($request)->getRouteParser()->urlFor('posts.index');
 
        return $response->withHeader('Location', $url)->withStatus(302);
    }
}

Если ошибки есть, форма выводится заново с кодом 422 — «данные не прошли проверку». В шаблон передаются ошибки и введённые значения. Если ошибок нет, статья сохраняется, и браузер перенаправляется на список.

Вывод ошибок

Дополните шаблон: подставьте прежние значения и сообщения об ошибках.

{# templates/posts/new.twig #}
<input type="text" name="title" value="{{ old.title }}" placeholder="Заголовок">
{% if errors.title %}
    <p class="error">{{ errors.title }}</p>
{% endif %}
 
<textarea name="body" placeholder="Текст">{{ old.body }}</textarea>
{% if errors.body %}
    <p class="error">{{ errors.body }}</p>
{% endif %}

Отправьте пустую форму — под полями появятся сообщения. При первом открытии переменных errors и old нет; Twig считает их пустыми и ничего не выводит.

Библиотеки проверки

Когда правил становится много, вместо своего класса подключают библиотеку, например respect/validation или symfony/validator. Место в проекте то же: класс в src/Validation/, который вызывается из действия.

Частая ошибка

Если после успешного сохранения не перенаправить браузер, а сразу вывести страницу, обновление этой страницы отправит форму повторно — в базе появится вторая такая же статья. После удачного POST всегда возвращайте перенаправление.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.