Компонент Form
Дата оновлення перекладу 2024-05-02
Компонент 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() для роботи з відправкою форм.
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\RequestStack;
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): FormRenderer {
return new FormRenderer($formEngine, $csrfManager);
},
]));
// ... (див. попередній розділ CSRF-захист, щоб дізнатися більше)
// додає FormExtension в Twig
$twig->addExtension(new FormExtension());
// створює фабрику форм
$formFactory = Forms::createFormFactoryBuilder()
// ...
->getFormFactory();
Точні деталі вашої Конфігурації 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, де ви будуєте та конфігуруєте різні поля. Конструктор форм створюється з фабрики форм.
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
// src/Controller/TaskController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class TaskController extends AbstractController
{
public function new(Request $request): Response
{
// createFormBuilder - це скорочення для отримання "фабрики форм"
// и потом вызова "createBuilder()" в ней
$form = $this->createFormBuilder()
->add('task', TextType::class)
->add('dueDate', DateType::class)
->getForm();
return $this->render('task/new.html.twig', [
'form' => $form->createView(),
]);
}
}
Як ви бачите, створення форми - це як написати рецепт: ви викликаєте add()
для кожного нового поля, яке ви хочете створити. Перший аргумент add()
- це
ім'я вашого поля, а другий - повне ім'я класу. Компонент Форма постачається з
багатьма вбудованими типами.
Тепер, коли ви побудували вашу форму, дізнайтеся, як відображати її та обробляти відправку форми .
Установка значень за замовчуванням
Якщо вам треба, щоб ваша форма завантажувалась з деякими значеннями за замовчуванням (або якщо ви будуєте форму "редагування), просто передайте дані за замовчуванням при створенні вашого конструктору форм:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// src/Controller/DefaultController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends AbstractController
{
public function new(Request $request): Response
{
$defaults = [
'dueDate' => new \DateTime('tomorrow'),
];
$form = $this->createFormBuilder($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. Цю поведінку можна змінити, використовуючи опції
та (опція method
також використовується handleRequest(),
щоб визначити, чи була відправлена форма):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// src/Controller/DefaultController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends AbstractController
{
public function search(): Response
{
$formBuilder = $this->createFormBuilder(null, [
'action' => '/search',
'method' => 'GET',
]);
// ...
}
}
Обробка відправок форми
Щоб обробити відправки форми, використовуйте метод handleRequest():
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/TaskController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Response;
class TaskController extends AbstractController
{
public function new(Request $request): Response
{
$form = $this->createFormBuilder()
->add('task', TextType::class)
->add('dueDate', DateType::class)
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
// ... виконати деяку дію, наприклад, зберегти дані в базу даних
return $this->redirectToRoute('task_success');
}
// ...
}
}
Caution
Метод createView()
має викликатися після виклику handleRequest()
. Інакше,
при використанні подій форми, зміни, зроблені в подіях
*_SUBMIT
не будуть застосовуватися до перегляду (на кшталт помилок валідації).
Це визначає загальний "Робочий процес", який містить 3 різних можливості:
В початковому запиті GET (тобто, коли користувач заходить на вашу сторінку), побудуйте вашу форму та відобразіть її;
Якщо запит - POST, обробіть відправлені дані (через handleRequest()).
А потім:
- якщо форма не валідна, відобразіть форму (яка тепер міститиме помилки);
- якщо форма валідна, виконайте деякі дії та перенаправте.
На щастя, вам не потрібно вирішувати, чи була відправлена форма. Просто передайте поточний запит методу handleRequest(). Далі компонент Форма зробить всю роботу за вас.
Валідація форми
Найпростіший спосіб додати валідацію до вашої форми - через опцію
constraints
при побудові кожного поля:
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
// src/Controller/DefaultController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Type;
class DefaultController extends AbstractController
{
public function new(Request $request): Response
{
$form = $this->createFormBuilder()
->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
$form = ...;
// ...
// екземпляр FormErrorIterator, але тільки помилки, пов'язані з цим
// рівнем форми (наприклад, глобальні помилки)
$errors = $form->getErrors();
// екземпляр FormErrorIterator, але тільки помилки, пов'язані з
// полем "firstName"
$errors = $form['firstName']->getErrors();
// екземпляр FormErrorIterator в пласкій структурі
$errors = $form->getErrors(true);
// екземпляр FormErrorIterator, що надає структуру дерева форми
$errors = $form->getErrors(true, false);
Очищення помилок форми
Всі помилки можуть бути очищені вручну методом clearErrors(). Це зручно, якщо ви хочете валідувати форму без відображення помилок валідації користувача (наприклад, при частковій відправці AJAX або динамічній модифікації форм).
Так як очистка помилок робить форму валідною, clearErrors() має викликатися лише після перевірки того, що форма валідна.
Дізнайтеся більше
- Як змінити дію та метод форми
- Тема форми Bootstrap 4
- Тема форми Bootstrap 5
- Як обирати групи валідації, засновані на натиснутій кнопці
- Як створити користувацький тип поля форми
- Як створити розширення типу форми
- Як обирати групи валідації, засновані на відправлених даних
- Як і коли використовувати мапувальники даних
- Як використовувати перетворювачі даних
- Як використовувати функцію submit() для обробки відправки форм
- Як відключити валідацію відправлених даних
- Як динамічно модифікувати форми, використовуючи події форм
- Як вбудовувати форми
- Події форми
- Как вбудувати колекцію форм
- Як налаштувати відображення форми
- Як отримати доступ до сервісів або конфігурації зсередини форми
- Як працювати з темами форми
- Як зменшити дублювання коду за допомогою "inherit_data"
- Як відправити форму з декількома кнопками
- Як контролювати відображення у формі
- Тема форми Tailwind CSS
- Створення користувацького вгадувача типу
- Як проводити модульне тестування ваших форм
- Як сконфігурувати порожні дані для класу форми
- Як динамічно конфігурувати групи валідації форм
- Як визначити, які групи валідації використовувати
- Як викоритовувати форму без класу даних