Формы
Форму в 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(): она выводит все поля, которые вы не вывели сами.