Компонент Form

Дата оновлення перекладу 2022-12-12

Компонент Form

Компонент Form дозволяє вам з легкістю створювати, обробляти та використовувати форми повторно.

Копомнент Form - це інструмент, покликаний допомогти вам вирішити проблему дозволу кінцевим користувачам взаємодіяти та змінювати дані у вашому додатку. І хоча традиційно це робилось через HTML-форми, компонент фокусується на обробці даних від та до вашого клієнту та додатку, незважаючи на те, це дані зі звичайного запису форми, або з API.

Установка

1
$ composer require symfony/form

Note

Якщо ви встановлюєте цей компонент поза додатком Symfony, вам потрібно підключити файл vendor/autoload.phpу вашому коді для включення механізму автозавантаження класів, наданих Composer. Детальніше можна прочитати у цій статті.

Конфігурація

See also

Ця стаття пояснює, як використовувати функції Форми як незалежного компоненту в будь-якому додатку PHP. Прочитайте статтю Форми, щоб отримати розуміння, як використовувати його в додатках Symfony.

В Symfony, форми представлено об'єктами, а ці об'єкти будуються з використанням фабрики форм. Побудувати фабрику форм просто за допомогою методу Forms::createFormFactory:

1
2
3
use Symfony\Component\Form\Forms;

$formFactory = Forms::createFormFactory();

Ця фабрика може вже бути використана для створення базових форм, але їй не вистачає підтримки для дуже важливих функцій:

  • Обробка запитів: Підтримка обробки запитів та завантаження файлів;
  • CSRF-захист: Підтримка захисту від атак міжсайтової підробки запитів (CSRF);
  • Шаблонізація: Інтеграція з рівнем шаблонізації, який дозволяє вам використовувати фрагменти HTML повторно при відображенні форми;
  • Перклад: Підтримка перекладу повідомлень про помилки, ярликів полів та інших рядків;
  • Валідація: Інтеграція з бібліотекою валідації для генерування повідомлень про помилки для відправки даних.

Компонент Symfony Form покладається на інші бібліотеки в рішенні цих проблем. В більшості випадків ви будете використовувати Twig та Symfony HttpFoundation, компоненти Translation та Validator, але ви можете замінити будь-яки з них іншою бібліотекою на власний вибір.

Наступні розділи пояснюються, як підключати ці бібліотеки в фабрику форм.

Tip

Щоб побачити робочий приклад, див. https://github.com/webmozart/standalone-forms

Обробка запитів

Шоб обробити дані форми, вам знадобиться викликати метод handleRequest():

1
$form->handleRequest();

За лаштунками використовується об'єкт NativeRequestHandler для зчитування даних з правильних суперглобальних PHP (тобто $_POST або $_GET), заснованих на HTTP-методі, сконфігурованому в формі (POST за замовчуванням).

See also

Якщо вам потрібно більше контролю над тим, коли саме відправляється ваша форма, або які дані передаються ій, використовуйте метод submit() для роботи з відправкою форм.

Якщо ви використовуєте компонент HttpFoundation, то вам необхідно додати HttpFoundationExtension у вашу фабрику форм:

1
2
3
4
5
6
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationExtension;
use Symfony\Component\Form\Forms;

$formFactory = Forms::createFormFactoryBuilder()
    ->addExtension(new HttpFoundationExtension())
    ->getFormFactory();

Тепер, коли ви обробляєте форми, ви можете передати об'єкт Request методу handleRequest():

1
$form->handleRequest($request);

Note

Щоб дізнатися більше про компонент HttpFoundation або про те, як його встановити, див. Компонент HttpFoundation.

CSRF-захист

Захист від CSRF-атак вбудобваний в компонент Form, але вам потрібно чітко включити його або замінити користувацьким рішенням. Якщо ви хочете використовувати вбудовану підтримку, для початку, встановіть компонент Security CSRF:

1
$ composer require symfony/security-csrf

Наступний відрізок додає CSRF-захист до фабрики форм:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
use Symfony\Component\Form\Forms;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Csrf\CsrfTokenManager;
use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator;
use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage;

// створює об'єкт RequestStack, використовуючи поточний запит
$requestStack = new RequestStack();
$requestStack->push($request);

$csrfGenerator = new UriSafeTokenGenerator();
$csrfStorage = new SessionTokenStorage($requestStack);
$csrfManager = new CsrfTokenManager($csrfGenerator, $csrfStorage);

$formFactory = Forms::createFormFactoryBuilder()
    // ...
    ->addExtension(new CsrfExtension($csrfManager))
    ->getFormFactory();

Внутрішньо, це розширення автоматично додасть приховане поле до кожної форми (за замочуванням, назване _token), значення якої автоматично генерується CSRF-генератором та валідується при побудові форми.

Tip

Якщо ви не використовуєте компонент HttpFoundation, то замість нього ви можете використовувати NativeSessionTokenStorage, який покладається на вбудобвану PHP-обробку сесії:

1
2
3
4
use Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage;

$csrfStorage = new NativeSessionTokenStorage();
// ...

Ви можете відключити CSRF-захист для форми, використовуючи опцію csrf_protection:

1
2
3
4
use Symfony\Component\Form\Extension\Core\Type\FormType;

$form = $formFactory->createBuilder(FormType::class, null, ['csrf_protection' => false])
    ->getForm();

Шаблонізація Twig

Якщо ви використовуєте компонент Форма для обробки HTML-форм, то вам знадобиться спосіб легко відображати вашу форму у вигляді полів HTML-форми (заповнену значеннями полів, помилками та ярликами). Якщо ви використовуєте Twig в якості шаблонізатору, то компонент Форма пропонує багату інтеграцію.

Щоб використовувати інтеграцію, вам знадобиться twig bridge, який надає інтеграцію між Twig та деякими компонентами Symfony:

1
$ composer require symfony/twig-bridge

Інтеграція TwigBridge надає вам декілька функцій Twig , які допомгають вам відображати HTML-віджет, ярлик та помилку для кожного поля (а також декілька інших речей). Щоб сконфигурувати інтеграцію, вам знадобиться запустить або отримати доступ до Twig, та додати FormExtension:

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
31
32
33
34
35
36
37
38
39
40
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Component\Form\FormRenderer;
use Symfony\Component\Form\Forms;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Twig\RuntimeLoader\FactoryRuntimeLoader;

// файл Twig, який містить всю розмітку за замовчуванням для відображення форм
// цей файл поставляються з TwigBridge
$defaultFormTheme = 'form_div_layout.html.twig';

$vendorDirectory = realpath(__DIR__.'/../vendor');
// шлях до бібліотеки TwigBridge, щоб Twig міг знайти
// файл form_div_layout.html.twig
$appVariableReflection = new \ReflectionClass('\Symfony\Bridge\Twig\AppVariable');
$vendorTwigBridgeDirectory = dirname($appVariableReflection->getFileName());
// шлях до ваших інших шаболнів
$viewsDirectory = realpath(__DIR__.'/../views');

$twig = new Environment(new FilesystemLoader([
    $viewsDirectory,
    $vendorTwigBridgeDirectory.'/Resources/views/Form',
]));
$formEngine = new TwigRendererEngine([$defaultFormTheme], $twig);
$twig->addRuntimeLoader(new FactoryRuntimeLoader([
    FormRenderer::class => function () use ($formEngine, $csrfManager) {
        return new FormRenderer($formEngine, $csrfManager);
    },
]));

// ... (див. попередній розділ CSRF-захист, щоб дізнатися більше)

// додає FormExtension в Twig
$twig->addExtension(new FormExtension());

// створює фабрику форм
$formFactory = Forms::createFormFactoryBuilder()
    // ...
    ->getFormFactory();

1.30

Twig_FactoryRuntimeLoader було представлено в Twig 1.30.

Точні деталі вашої Конфігурації Twig будуть відрізнятися, але ціль - дозволити додати FormExtension в Twig, що надає вам доступ до функції Twig для відображення форм. Щоб зробити це, спочатку вам необхідно створити TwigRendererEngine, де ви визначите ваші теми формы (тобто джерела/файлі, які визначають HTML розмітку форми).

Щоб дізнатися загальні деталі про відображення форм, див. Як налаштувати відображення форми.

Note

Якщо ви використовуєте інтеграцію Twig, прочтайте "" нижче, щоб дізнатися деталі про необхідні фільтри перекладу.

Переклад

Якщо ви використовуєте інтеграцію Twig з одним з файлів теми за замочуванням (наприклад, form_div_layout.html.twig), то існує фільтр Twig (trans), який використовується для перекладу ярликів, помилок, опціонального тексту та інших рядків форми.

Щоб додати фільтр Twig trans, ви можете або використати вбудований TranslationExtension, який інтегрується з компонентом Symfony Переклад, або додати фільтр Twig самостійно, через ваше власне розширення Twig.

Шоб використовувати вбудовану інтеграцію, переконайтесь в тому, що у вашому проекті встановлені компоненти Symfony Переклад та Конфігурація:

1
$ composer require symfony/translation symfony/config

Далі, додайте TranslationExtension до вашого екземпляру Twig\Environment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Component\Form\Forms;
use Symfony\Component\Translation\Loader\XliffFileLoader;
use Symfony\Component\Translation\Translator;

// створює Перекладача
$translator = new Translator('en');
// якось завантажує деяки переклади в нього
$translator->addLoader('xlf', new XliffFileLoader());
$translator->addResource(
    'xlf',
    __DIR__.'/path/to/translations/messages.en.xlf',
    'en'
);

// додає TranslationExtension (дає нам фільтр trans)
$twig->addExtension(new TranslationExtension($translator));

$formFactory = Forms::createFormFactoryBuilder()
    // ...
    ->getFormFactory();

В залежності від того, як завантажуються ваші переклади, ви можете тепер додати ключі рядків, наприклад, ярлики полів та їх переклади, в ваші файли перекладів.

Щоб дізнатися більше про переклади, див. Переклади.

Валідація

Компонент Form постачається з тісною (але необов'язковою) інтеграцією з комонентом Symfony Validator. Якщо ви використовуєте інше рішення для валідації - це не проблема! Просто візьміть відправлені дані вашої форми (масив чи об'єкт) та передайте їх через вашу власну систему валідації.

Щоб використовувати інтеграцію з компонентом Symfony Валідатор, спочатку переконайтеся, що він встановлений у вашому додатку:

1
$ composer require symfony/validator

Якщо ви не знайомі з цим компонентом, прочитайте більше про нього: Валідація. Компонент Форма постачається з класом ValidatorExtension, який автоматично застосовує валідацію до ваших даних. Ці помилки потім зв'язуються з відповідним полем та відображаються.

Ваша інтеграція з компонентом Валідація буд виглядати якось так:

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
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
use Symfony\Component\Form\Forms;
use Symfony\Component\Validator\Validation;

$vendorDirectory = realpath(__DIR__.'/../vendor');
$vendorFormDirectory = $vendorDirectory.'/symfony/form';
$vendorValidatorDirectory = $vendorDirectory.'/symfony/validator';

// створює валідатор - деталі будуть відрізнятися
$validator = Validation::createValidator();

// існують вбудовані переходи для базових повідомлень про помилки
$translator->addResource(
    'xlf',
    $vendorFormDirectory.'/Resources/translations/validators.en.xlf',
    'en',
    'validators'
);
$translator->addResource(
    'xlf',
    $vendorValidatorDirectory.'/Resources/translations/validators.en.xlf',
    'en',
    'validators'
);

$formFactory = Forms::createFormFactoryBuilder()
    // ...
    ->addExtension(new ValidatorExtension($validator))
    ->getFormFactory();

Щоб дізнатися більше, перейдіть до розділу .

Доступ до фабрики форм

Вашому додатку необхідна лише одна фабрика форм, і один об'єкт фабрики має бути використано для створення всіх об'єктів форми у вашому додатку. Це означає, що вам необхідно створити його в центральній частині початкового завантаження вашого додатку, а потім отримувати доступ до нього, коли вам необхідно буде будувати форму.

Note

В цьому документі, фабрика форм завжди є локальною змінною під назвою $formFactory. Суть в тому, що вам скоріш за все знадобиться створити цей об'єкт в більш "глобальному" вигляді, щоб ви могли отримати до нього доступ звідки завгодно.

Те, як саме ви отримаєте доступ до вашої фабрики фори - залежить від вас. Якщо ви використовуєте сервіс-контейнер (як наданий компонентом DependencyInjection), то вам слід додати фабрику форм в ваш контейнер та викликати її, коли вам це буде потрібно. Якщо ваш застосунок використовує глобальні або статичні змінні (зазвичай не дуже хороша ідея), то ви можете зберігати об'єкт в деякому статичному класі, або зробити щось подібне.

Створення простої форми

Tip

Якщо ви використовуєете фреймворк Symfony, то фабрика форм доступна автоматично у вигляді сервісу під назвою form.factory, ви можете впровадити її як Symfony\Component\Form\FormFactoryInterface. Крім того, базовий клас контролера за замочуванням має метод createFormBuilder(), яки є скороченням для отримання фабрики форм та виклика в ній createBuilder().

Створення форми здійснюється через об'єкт FormBuilder, де ви будуєте та конфігуруєте різні поля. Конструктор форм створюється з фабрики форм.

  • Standalone Use
  • Framework Use
1
2
3
4
5
6
7
8
9
10
11
12
13
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\DateType;

// ...

$form = $formFactory->createBuilder()
    ->add('task', TextType::class)
    ->add('dueDate', DateType::class)
    ->getForm();

var_dump($twig->render('new.html.twig', [
    'form' => $form->createView(),
]));

Як ви бачите, створення форми - це як написати рецепт: ви викликаєте add() для кожного нового поля, яке ви хочете створити. Перший аргумент add() - це ім'я вашого поля, а другий - повне ім'я класу. Компонент Форма постачається з багатьма вбудованими типами.

Тепер, коли ви побудували вашу форму, дізнайтеся, як відображати її та обробляти відправку форми .

Установка значень за замовчуванням

Якщо вам треба, щоб ваша форма завантажувалась з деякими значеннями за замовчуванням (або якщо ви будуєте форму "редагування), просто передайте дані за замовчуванням при створенні вашого конструктору форм:

  • Standalone Use
  • Framework Use
1
2
3
4
5
6
7
8
9
10
11
12
13
14
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\DateType;

// ...

$defaults = [
    'dueDate' => new \DateTime('tomorrow'),
];

$form = $formFactory->createBuilder(FormType::class, $defaults)
    ->add('task', TextType::class)
    ->add('dueDate', DateType::class)
    ->getForm();

Tip

В цьому прикладі, дані за замовчуванням - масив. Пізніше, коли ви будете використовувати опцію data_class для прив'язки даних напряму до об'єктів, ваші дані за замовчуванням будуть екземпляром цього об'єкту.

Відображення форми

Тепер, коли форма була створена, наступний крок - відобразити її. Це робиться шляхом передачі спеціального об'єкту форми "view" у ваш шаблон (відмітьте $form->createView() в контролері вище) та використання набору функцій-хелперів форми:

1
2
3
4
5
{{ form_start(form) }}
    {{ form_widget(form) }}

    <input type="submit" />
{{ form_end(form) }}

Ось і все! Надрукувавши form_widget(form), ви відобразите кожне поле форми разом з ярликом та повідомленням про помилку (якщо воно є). І хоча це і легко, але (поки) не дуже гнучко. Зазвичай, вам треба буде відображати кожне поле форми окремо, щоб ви могли контролювати те, як виглядає форма. Ви дізнаєтесь, як це зробити, в статті налаштування форми.

Зміна методу та дії форми

За замовчуванням, форма відправляє по тому ж URI, який відобразив форму з запитом HTTP POST. Цю поведінку можна змінити, використовуючи опції Поле FormType та Поле FormType (опція method також використовується handleRequest(), щоб визначити, чи була відправлена форма):

  • Standalone Use
  • Framework Use
1
2
3
4
5
6
7
8
9
10
use Symfony\Component\Form\Extension\Core\Type\FormType;

// ...

$formBuilder = $formFactory->createBuilder(FormType::class, null, [
    'action' => '/search',
    'method' => 'GET',
]);

// ...

Обробка відправок форми

Щоб обробити відправки форми, використовуйте метод handleRequest():

  • Standalone Use
  • Framework Use
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\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;

// ...

$form = $formFactory->createBuilder()
    ->add('task', TextType::class)
    ->add('dueDate', DateType::class)
    ->getForm();

$request = Request::createFromGlobals();

$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
    $data = $form->getData();

    // ... виконати деяку дію, наприклад, зберегти дані в базу даних

    $response = new RedirectResponse('/task/success');
    $response->prepare($request);

    return $response->send();
}

// ...

Caution

Метод createView() має викликатися після виклику handleRequest(). Інакше, при використанні подій форми, зміни, зроблені в подіях *_SUBMIT не будуть застосовуватися до перегляду (на кшталт помилок валідації).

Це визначає загальний "Робочий процес", який містить 3 різних можливості:

  1. В початковому запиті GET (тобто, коли користувач заходить на вашу сторінку), побудуйте вашу форму та відобразіть її;

    Якщо запит - POST, обробіть відправлені дані (через handleRequest()).

    А потім:

  2. якщо форма не валідна, відобразіть форму (яка тепер міститиме помилки);
  3. якщо форма валідна, виконайте деякі дії та перенаправте.

На щастя, вам не потрібно вирішувати, чи була відправлена форма. Просто передайте поточний запит методу handleRequest(). Далі компонент Форма зробить всю роботу за вас.

Валідація форм

Найпростіший спосіб додати валідацію до вашої форми - через опцію constraints при побудові кожного поля:

  • Standalone Use
  • Framework Use
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Type;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\DateType;

$form = $formFactory->createBuilder()
    ->add('task', TextType::class, [
        'constraints' => new NotBlank(),
    ])
    ->add('dueDate', DateType::class, [
        'constraints' => [
            new NotBlank(),
            new Type(\DateTime::class),
        ]
    ])
    ->getForm();

Коли форма прив'язана, ці обмеження валідації будуть застосовані автоматично, а помилки відобразяться поруч з полями помилок.

Note

Щоб побачити список усіх вбудобавних обмежень валідації, див. Довідник обмежень валідації.

Доступ до помилок форми

Ви можете використати метод getErrors(), щоб отримати доступ до списку помилок. Він повертає екземпляр FormErrorIterator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$form = ...;

// ...

// екземпляр FormErrorIterator, але тільки помилки, пов'язані з цим
// рівнем форми (наприклад, глобальні помилки)
$errors = $form->getErrors();

// екземпляр FormErrorIterator, але тільки помилки, пов'язані з
// полем "firstName"
$errors = $form['firstName']->getErrors();

// екземпляр FormErrorIterator в пласкій структурі
// використовувати getOrigin(), щоб визначити форму, що викликає помилку
$errors = $form->getErrors(true);

// екземпляр FormErrorIterator, що надає структуру дерева форми
$errors = $form->getErrors(true, false);

Очистка помилок форми

Всі помилки можуть бути очищені вручну методом clearErrors(). Це зручно, якщо ви хочете валідувати форму без відображення помилок валідації користувача (наприклад, при частковій відправці AJAX або динамічній модифікації форм).

Так як очистка помилок робить форму валідною, clearErrors() має викликатися лише після перевірки того, що форма валідна.

Дізнайтеся більше