Encodera

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

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

Оглавление

Формы

Форму в Symfony описывают классом: какие в ней поля и с какой сущностью она связана. По этому описанию фреймворк рисует разметку, заполняет объект присланными данными, проверяет их и защищает от подделки запроса.

Класс формы

php bin/console make:form PostType Post
// src/Form/PostType.php
namespace App\Form;
 
use App\Entity\Post;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
 
class PostType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('title', TextType::class, ['label' => 'Заголовок'])
            ->add('body', TextareaType::class, ['label' => 'Текст'])
            ->add('published', CheckboxType::class, [
                'label' => 'Опубликовать',
                'required' => false,
            ]);
    }
 
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults(['data_class' => Post::class]);
    }
}

data_class связывает форму с сущностью: имена полей совпадают с её свойствами.

Типы полей

ТипПоле
TextTypeСтрока
TextareaTypeМногострочный текст
EmailTypeПочта
PasswordTypeПароль
IntegerType, MoneyTypeЧисла
ChoiceTypeСписок или переключатели
EntityTypeВыбор записи из базы
DateTypeДата
FileTypeФайл

Обработка в контроллере

Один метод и показывает форму, и принимает её:

#[Route('/blog/new', name: 'blog_new')]
public function new(Request $request, EntityManagerInterface $em): Response
{
    $post = new Post();
    $form = $this->createForm(PostType::class, $post);
    $form->handleRequest($request);
 
    if ($form->isSubmitted() && $form->isValid()) {
        $em->persist($post);
        $em->flush();
 
        $this->addFlash('success', 'Статья создана');
 
        return $this->redirectToRoute('blog_show', ['id' => $post->getId()]);
    }
 
    return $this->render('blog/new.html.twig', ['form' => $form]);
}

handleRequest() записывает присланные данные в $post. Если форму ещё не отправляли или в ней ошибки, метод доходит до render() и показывает форму — с введёнными значениями и сообщениями.

Вывод

Самый короткий способ — вывести все поля разом функцией form_widget():

{{ form_start(form) }}
    {{ form_widget(form) }}
    <button type="submit">Сохранить</button>
{{ form_end(form) }}

Для своей вёрстки поля выводят по одному:

{{ form_start(form) }}
    {{ form_row(form.title) }}
 
    <div class="field">
        {{ form_label(form.body) }}
        {{ form_widget(form.body, {attr: {rows: 10}}) }}
        {{ form_errors(form.body) }}
    </div>
 
    <button type="submit">Сохранить</button>
{{ form_end(form) }}

Редактирование

Та же форма подходит для изменения записи — достаточно передать существующий объект:

#[Route('/blog/{id}/edit', name: 'blog_edit')]
public function edit(Post $post, Request $request, EntityManagerInterface $em): Response
{
    $form = $this->createForm(PostType::class, $post);
    $form->handleRequest($request);
 
    if ($form->isSubmitted() && $form->isValid()) {
        $em->flush();
 
        return $this->redirectToRoute('blog_show', ['id' => $post->getId()]);
    }
 
    return $this->render('blog/edit.html.twig', ['form' => $form]);
}

Защита от CSRF

form_end() добавляет в форму скрытое поле с токеном, и Symfony проверяет его при отправке. Отдельно ничего делать не нужно.

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

Если вывести поля вручную и забыть form_end(form), скрытое поле с токеном не попадёт на страницу — отправка закончится ошибкой The CSRF token is invalid. Всегда закрывайте форму функцией form_end(): она выводит все поля, которые вы не вывели сами.

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

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