Компонент Форма

Компонент Форма

Компонент Форма позволяет вам с лёгкостью создавать, обрабатывать и использовать формы повторно.

Копомнент Форма - это инструмент, призванный помочь вам решить проблему разрешения конечным пользователям взаимодействовать и изменять данные в вашем приложении. И хотя традиционно это делалось через HTML формы, компонент фокусируется на обработке данных к и от вашего клиента и приложения, будь эти данные из обычной записи формы или из API.

Установка

Вы можете установить компонент 2 разными способами:

Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application won't be able to find the classes of this Symfony component.

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

Tip

Если вы работаете с полным фреймворком Symfony, компонент Форма уже сконфигурирован для вас. В этом случае, перейдите к Создание простой формы.

В Symfony, формы представлены объектыми, а эти объекты строятся с использованием фабрики форм. Построить фабрику форм просто:

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

$formFactory = Forms::createFormFactory();

Эта фабрика может уже быть использована для создания базовых форм, но ей не хватает поддержки для очень важных функций:

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

Компонент Форма Symfony полагается на другие библиотеки в решении этих проблем. В большинстве случаев вы будете использовать Twig и Symfony HttpFoundation, компоненты Перевод и Валидатор, но вы можете заменить любой из них другой библиотекой на ваш выбор.

Следующие разделы объясняют, как подключать эти библиотеки в фабрику форм.

Tip

Чтобы увидеть рабочий пример, см. https://github.com/webmozart/standalone-forms

Обработка запросов

Чтобы обработать даныные формы, вам понадобится вызвать метод handleRequest():

1
$form->handleRequest();

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

Если вам нужно больше контроля над тем, когда именно отправляется ваша форма, или какие данные передаются ей, вы можете использовать для этого submit(). Прочтите больше об этом Вызов Form::submit() вручную.

Если вы используете компонент HttpFoundation, то вам стоит добавить HttpFoundationExtension в вашу фабрику форм:

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

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

Теперь, когда вы обрабатываете форму, вы можете передать объект Request методу handleRequest():

1
$form->handleRequest($request);

Note

Чтобы узнать больше о компоненте HttpFoundation или о том, как его установить, см. The HttpFoundation Component.

CSRF-защита

Защита от CSRF-атак встроена в компонент Форма, но вам нужно ясно включить её или заменить пользовательским решением. Если вы хотите использовать встроенную поддержку, для начала установите компонент 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
use Symfony\Component\Form\Forms;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage;
use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator;
use Symfony\Component\Security\Csrf\CsrfTokenManager;

// создать объект сесси из компонента HttpFoundation
$session = new Session();

$csrfGenerator = new UriSafeTokenGenerator();
$csrfStorage = new SessionTokenStorage($session);
$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();
// ...

Шаблонизация 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
use Symfony\Component\Form\Forms;
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Form\TwigRenderer;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;

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

$vendorDir = realpath(__DIR__.'/../vendor');
// путь к библиотеке TwigBridge, чтобы Twig мог найти
// файл form_div_layout.html.twig
$appVariableReflection = new \ReflectionClass('\Symfony\Bridge\Twig\AppVariable');
$vendorTwigBridgeDir = dirname($appVariableReflection->getFileName());
// путь к вашим другим щаблонам
$viewsDir = realpath(__DIR__.'/../views');

$twig = new Twig_Environment(new Twig_Loader_Filesystem(array(
    $viewsDir,
    $vendorTwigBridgeDir.'/Resources/views/Form',
)));
$formEngine = new TwigRendererEngine(array($defaultFormTheme), $twig);
$twig->addRuntimeLoader(new \Twig_FactoryRuntimeLoader(array(
    TwigRenderer::class => function () use ($formEngine, $csrfManager) {
        return new TwigRenderer($formEngine, $csrfManager);
    },
)));

// ... (см. предыдущий раздел CSRF-защита, чтобы узнать больше)

// добавить FormExtension в Twig
$twig->addExtension(new FormExtension());

// создать вашу фабрику форм как обычно
$formFactory = Forms::createFormFactoryBuilder()
    // ...
    ->getFormFactory();

New in version 1.30: Twig_FactoryRuntimeLoader была представлена в Twig 1.30.

Точные детали вашей `Конфигурации Twig`_ будут отличаться, но цель - позволить добавить FormExtension в Twig, что предоставляет вам доступ к функциям Twig для отображения форм. Чтобы сделать это, вам для начала нужно создать TwigRendererEngine, где вы определите ваш form themes (т.е. источники / файлы, которые определяют HTML разметку формы).

Чтобы узнать общие детали об отображении форм, см. How to Customize Form Rendering.

Note

Если вы используете интеграцию Twig, прочтите "Перевод" ниже, чтобы узнать детали о необходимых фильтрах перевода.

Перевод

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

Чтобы добавить эти фильтры Twig, вы можете либо использовать встроенный TranslationExtension, который интегрируется с компонентом Symfony Перевод, либо добавить 2 фильтра 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\Component\Form\Forms;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\XliffFileLoader;
use Symfony\Bridge\Twig\Extension\TranslationExtension;

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

// добавить TranslationExtension (даёт нам фильтры trans и transChoice)
$twig->addExtension(new TranslationExtension($translator));

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

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

Чтобы узнать больше о переводах, см. Translations.

Валидация

Компонент Форма поставляется с тесной (но необязательной) интеграцией с компонентом Symfony Валидатор. Если вы используете другое решение для валидации - то это не проблема! Просто возьмите отправленные данные вашей формы (массив или объект) и передайте их через вашу собственную систему валидации.

Чтобы использовать интеграцию с компонентом Symfony Валидатор, для начала убедитесь, что он установлен в вашем приложении:

1
$ composer require symfony/validator

Если вы не знакомы с этим компонентом, прочтите больше о нём: Validation. Компонент Форма поставляется с классом 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\Forms;
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
use Symfony\Component\Validator\Validation;

$vendorDir = realpath(__DIR__.'/../vendor');
$vendorFormDir = $vendorDir.'/symfony/form';
$vendorValidatorDir = $vendorDir.'/symfony/validator';

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

// существуют встроенные переходы для базовых сообщений ошибок
$translator->addResource(
    'xlf',
    $vendorFormDir.'/Resources/translations/validators.en.xlf',
    'en',
    'validators'
);
$translator->addResource(
    'xlf',
    $vendorValidatorDir.'/Resources/translations/validators.en.xlf',
    'en',
    'validators'
);

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

Чтобы узнать больше, перейдите к разделу Валидация форм.

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

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

Note

В этом документе, фабрика форм всегда является локальной переменной под названием $formFactory. Суть в том, что вам скорее всего понадобится создать этот объект в более "глобальном" виде, чтобы вы могли получить к нему доступ откуда угодно.

То, как именно вы получит доступ к вашей фабрике форм - зависит от вас. Если вы используете сервис-контейнер (как предоставленный с компонентом DependencyInjection), то вам стоит добавить фабрику форм в ваш контейнер и вызывать её, когда вам будет это нужно. Если ваше приложение использует глобальные или статические перменные (обычно не очень хорошая идея), то вы можете хранить объект в некотором статичном классе или сделать что-то подобное.

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

Создание простой формы

Tip

Если вы используете фреймворк Symfony, то фабрика форм доступна автоматически в виде сервиса под названием form.factory. Кроме того, базовый класс контроллера по умолчанию имеет метод createFormBuilder(), который является шорткатом для получения фабрики форм и вызова в ней createBuilder().

Создание формы осуществляется через объект FormBuilder, где вы строите и конфигурируете разные поля. Конструктор форм создаётся из фабрики форм.

  • Standalone 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', array(
        'form' => $form->createView(),
    )));
    
  • 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
    // src/Acme/TaskBundle/Controller/DefaultController.php
    namespace Acme\TaskBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    use Symfony\Component\Form\Extension\Core\Type\DateType;
    
    class DefaultController extends Controller
    {
        public function newAction(Request $request)
        {
            // createFormBuilder - это сокращение для получения "фабрики форм"
            // и потом вызова "createBuilder()" в ней
    
            $form = $this->createFormBuilder()
                ->add('task', TextType::class)
                ->add('dueDate', DateType::class)
                ->getForm();
    
            return $this->render('AcmeTaskBundle:Default:new.html.twig', array(
                'form' => $form->createView(),
            ));
        }
    }
    

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

Теперь, когда вы построили вашу форму, узнайте, как отображать её и обрабатывать отправку формы.

Установка значений по умолчению

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

  • Standalone 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 = array(
        'dueDate' => new \DateTime('tomorrow'),
    );
    
    $form = $formFactory->createBuilder(FormType::class, $defaults)
        ->add('task', TextType::class)
        ->add('dueDate', DateType::class)
        ->getForm();
    
  • 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
    // src/Acme/TaskBundle/Controller/DefaultController.php
    namespace Acme\TaskBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    use Symfony\Component\Form\Extension\Core\Type\DateType;
    
    class DefaultController extends Controller
    {
        public function newAction(Request $request)
        {
            $defaults = array(
                '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) }}
../_images/simple-form.png

Вот и всё! Напечатав form_widget(form), вы отобразите каждое поле формы вместе с ярлыком и сообщением ошибки (если оно есть). И хоть это и легко, но (пока) не очень гибко. Обычно, вам нужно будет отображать каждое поле формы отдельно, чтобы вы могли контролировать то, как выглядит форма. Вы узнаете, как это делать в разделе "How to Control the Rendering of a Form".

Изменения метода и действия формы

По умолчанию, форма отправляет по тому же URI, который отобразил форму с запросом HTTP POST. Это поведение можно изменить используя опции action и method (опция method также используется handleRequest(), чтобы определить, была ли отправлена форма):

  • Standalone 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, array(
        'action' => '/search',
        'method' => 'GET',
    ));
    
    // ...
    
  • Framework Use
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // src/Acme/TaskBundle/Controller/DefaultController.php
    namespace Acme\TaskBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\Form\Extension\Core\Type\FormType;
    
    class DefaultController extends Controller
    {
        public function searchAction()
        {
            $formBuilder = $this->createFormBuilder(null, array(
                'action' => '/search',
                'method' => 'GET',
            ));
    
            // ...
        }
    }
    

Обработка отправок формы

Чтобы обработать отправки формы, используйте метод handleRequest():

  • Standalone 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();
    }
    
    // ...
    
  • 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
    29
    // src/Acme/TaskBundle/Controller/DefaultController.php
    namespace Acme\TaskBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\Form\Extension\Core\Type\DateType;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    
    class DefaultController extends Controller
    {
        public function newAction(Request $request)
        {
            $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');
            }
    
            // ...
        }
    }
    

Это определяет общий "Рабочий процесс", который содержит 3 разные возможности:

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

Если запрос - POST, рбработайте отправленные данные (через handleRequest()). А потом:

  1. если форма не валина, отобразите форму (которая теперь будет содержать ошибки);
  2. если форма валидна, выполните некоторые действия и перенаправьте.

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

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

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

  • Standalone 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, array(
            'constraints' => new NotBlank(),
        ))
        ->add('dueDate', DateType::class, array(
            'constraints' => array(
                new NotBlank(),
                new Type(\DateTime::class),
            )
        ))
        ->getForm();
    
  • 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
    // src/Acme/TaskBundle/Controller/DefaultController.php
    namespace Acme\TaskBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Symfony\Component\Validator\Constraints\NotBlank;
    use Symfony\Component\Validator\Constraints\Type;
    use Symfony\Component\Form\Extension\Core\Type\DateType;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    
    class DefaultController extends Controller
    {
        public function newAction(Request $request)
        {
            $form = $this->createFormBuilder()
                ->add('task', TextType::class, array(
                    'constraints' => new NotBlank(),
                ))
                ->add('dueDate', DateType::class, array(
                    'constraints' => array(
                        new NotBlank(),
                        new Type(\DateTime::class),
                    )
                ))
                ->getForm();
            // ...
        }
    }
    

Когда форма привязана, эти ограничения валидации будут применены автоматически, а ошибки отобразятся рядом с полями ошибок.

Note

Чтобы увидеть список всех встроенных ограничений валидации, см. Validation Constraints Reference.

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

Вы можете использовать метод getErrors(), чтобы получить доступ к списку ошибок. Он возвращает экземпляр FormErrorIterator:

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

// ...

// экземпляр FormErrorIterator, но только ошибки, связанные с этим
// уровнем формы (например, "global errors)
$errors = $form->getErrors();

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

// экземпляр FormErrorIterator в плоской структуре
// использовать getOrigin(), чтобы определить форму, вызывающую ошибу
$errors = $form->getErrors(true);

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

Узнайте больше

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.