Як викоритовувати форму без класу даних

Дата оновлення перекладу 2024-05-27

Як викоритовувати форму без класу даних

У більшості випадків, форма привʼязана до обʼєкта, а поля форми отримують та зберігають свої дані у властивостях цього обʼєкта. Це саме те, про що йдеться мова у головній статті з форм.

Але іноді вам може знадобитися використати форму без класу і отримати назад масив відправлених даних. Метод 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();
        }

        // ... відобразити форму
    }
}

За замовчуванням, форма насправді припускає, що ви хочете працювати з масивами даних, замість обʼєкта. Існує рівно два способи, щоб змінити цю поведінку та привʼязати форму до обʼєкта:

  1. Передати обʼєкт при створенні форми (в якості першого аргументу createFormBuilder() або другого аргументу createForm());
  2. Оголосити у вашій формі опцію 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\Component\Validator\Constraints\Valid, окрім випадків, коли ви відключаєте валідацію.

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();