Как использовать форму без класса данных
Дата обновления перевода 2024-07-19
Как использовать форму без класса данных
В большинстве случаев, форма привязана к объекту, а поля формы получают и сохраняют своди данные в свойствах этого объекта. Это именно то, о чём идёт речь в главной статье о формах.
Но иногда вам может быть нужно использовать форму без класса, и получить
обратно массив отправленных данных. Это на самом деле очень просто. Метод
getData()
позволяет вам делать именно это:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// src/Controller/ContactController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
// ...
class ContactController extends AbstractController
{
public function contact(Request $request): Response
{
$defaultData = ['message' => 'Type your message here'];
$form = $this->createFormBuilder($defaultData)
->add('name', TextType::class)
->add('email', EmailType::class)
->add('message', TextareaType::class)
->add('send', SubmitType::class)
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// данные - это массив с ключами "name", "email" и "message"
$data = $form->getData();
}
// ... отобразить форму
}
}
По умолчанию, форма на самом деле предполагает, что вы хотите работать с массивами данных, вместо объекта. Существует ровно два способа, чтобы изменить это поведение и привязать форму к объекту:
- Передать объект при создании форму (в качестве первого аргумента
createFormBuilder()
или второго аргументаcreateForm()
); - Объявить в вашей форме опцию
data_class
.
Если вы не сделаете ничего из этого, тогда форма будет возвращать данные
в виде массива. В этом примере, так как $defaultData
- это не объект
(и не установлена опция data_class
), $form->getData()
в конечном счёте
возвращает массив.
Tip
Вы также можете получить доступ к значениям POST (в этом случае - "name") напрямую через объект запроса, вот так:
1
$request->request->get('name');
Но имейте в виду, что в большинстве случаев, использование метода getData()
будет лучше, так как он возвращает данные (обычно в виде объекта) после того,
как они были преобразованы компонентом формы.
Добавление валидации
Единственным недостающим элементом является валидация. Обычно, когда вы вызываете
$form->handleRequest($request)
, объект валидируется путём считывания ограничений, которые вы
применили к этому классу. Если ваша форма привязана к объекту (т.е. вы используете
опцию data_class
или передаёте объект в вашу форму), то вы захотите использовать
этот подход практически всегда. Смотрите Валидация, чтобы узнать больше.
Но если форма не привязана к объекту, и вы хотите получить простой массив ваших отправленных данных, как вы можете добавить ограничения к данным вашей формы?
Ограничения на уровне поля
Один из вариантов - установить ограничения самостоятельно и присоединить их к индивидуальным полям. Этот подход детальнее рассматривается в этой статье о валидации, но вот краткий пример:
use SymfonyComponentFormExtensionCoreTypeTextType; use SymfonyComponentFormFormBuilderInterface; use SymfonyComponentValidatorConstraintsLength; use SymfonyComponentValidatorConstraintsNotBlank;
public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('firstName', TextType::class, [ 'constraints' => new Length(['min' => 3]), ]) ->add('lastName', TextType::class, [ 'constraints' => [ new NotBlank(), new Length(['min' => 3]), ], ]) ; }
Tip
Если вы используете группы валидации, вам нужно либо сослаться на
группу Default
при создании формы, или установить правильную группу
в ограничении, которое вы добавляете:
1
new NotBlank(['groups' => ['create', 'update']]);
Tip
Если форма не привязана к объекту, то каждый объект в вашем массиве
отправленных данных валидируется с использованием ограничения
Symfony
, кроме случаев, когда
вы отключаете валидацию.
Caution
Когда форма отправлена только частично (например, в запросе HTTP PATCH), будут оцениваться только ограничения из представленных полей формы.
Ограничения на уровне класса
Другой вариант - добавить ограничения на уровне класса. Это можно сделать,
установив опцию constraints
в методе configureOptions()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('firstName', TextType::class)
->add('lastName', TextType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$constraints = [
'firstName' => new Length(['min' => 3]),
'lastName' => [
new NotBlank(),
new Length(['min' => 3]),
],
];
$resolver->setDefaults([
'data_class' => null,
'constraints' => $constraints,
]);
}
Это означает, что вы также можете сделать это при использовании метода
createFormBuilder()
в вашем контроллере:
1 2 3 4 5 6 7 8 9 10 11 12
$form = $this->createFormBuilder($defaultData, [
'constraints' => [
'firstName' => new Length(['min' => 3]),
'lastName' => [
new NotBlank(),
new Length(['min' => 3]),
],
],
])
->add('firstName', TextType::class)
->add('lastName', TextType::class)
->getForm();