Як викоритовувати форму без класу даних
Дата оновлення перекладу 2025-08-25
Як викоритовувати форму без класу даних
У більшості випадків, форма привʼязана до обʼєкта, а поля форми отримують та зберігають свої дані у властивостях цього обʼєкта. Це саме те, про що йдеться мова у головній статті з форм.
Але іноді вам може знадобитися використати форму без класу і отримати назад
масив відправлених даних. Метод 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 або передаєте обʼєкт у вашу форму), то ви
захочете використовувати цей підхід майже завжди. Дивіться Валідація,
щоб дізнатися більше.
Але якщо форма не привʼязана до обʼєкта, і ви хочете отримати простий масив ваших відправлених даних, як ви можете додати обмеження до даних вашої форми?
Відповідь - встановити обмеження самостійно та приєднати їх до індивідуальних полів. Цей підхід детальніше розглядається у цій статті про валідацію, але ось короткий приклад:
Обмеження на рівні полів
Одна з можливостей - встановити обмеження самостійно і прикріпити їх до окремих полів. Загальний підхід більш детально описано у цій статті про валідацію, але ось короткий приклад:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
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, [
'constraints' => new Length(min: 3),
])
->add('lastName', TextType::class, [
'constraints' => [
new NotBlank(),
new Length(min: 3),
],
])
;
}
Tip
Якщо ви використовуєте групи валідації, вам потрібно або послатися на групу
Default при створенні форми, або встановити правильну групу в обмеженні,
яке ви додаєте.
new NotBlank(['groups' => ['create', 'update']]);
Tip
Якщо форрма не привʼязана до обʼєкта, то кожний обʼєкт у вашому масиві
відправлених даних валідується з використанням обмеження
Symfony, окрім випадків, коли
ви відключаєте валідацію.
Warning
Коли форма відправлена лише частково (наприклад, в 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
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Collection;
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
{
$resolver->setDefaults([
'data_class' => null,
'constraints' => new Collection([
'firstName' => new Length(min: 3),
'lastName' => [
new NotBlank(),
new Length(min: 3),
],
]),
]);
}
Це означає, що ви також можете зробити це при використанні методу 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();
Обумовлені обмеження
Можливо визначити обмеження поля, які залежать від значень інших полів (наприклад,
поле має не бути порожнім, якщо інше поле має певне значення). Щоб досягнути цього,
використайте опцію expression в обмеженні When,
щоб послатися на інше поле:
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
$builder
->add('how_did_you_hear', ChoiceType::class, [
'required' => true,
'label' => 'How did you hear about us?',
'choices' => [
'Search engine' => 'search_engine',
'Friends' => 'friends',
'Other' => 'other',
],
'expanded' => true,
'constraints' => [
new Assert\NotBlank(),
]
])
// це поле є обовʼязковим лише, якщо значення поля 'how_did_you_hear' є 'other'
->add('other_text', TextType::class, [
'required' => false,
'label' => 'Please specify',
'constraints' => [
new Assert\When(
expression: 'this.getParent().get("how_did_you_hear").getData() == "other"',
constraints: [
new Assert\NotBlank(),
],
)
],
])
;