События формы

События формы

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

Регистрирование слушателя событий очень простое при использовании компонента Формы.

Например, если вы хотите зарегистрировать функцию в событии FormEvents::PRE_SUBMIT, следующий код позволяет вам добавить поле, в зависимости от значений запроса:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ...

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

$listener = function (FormEvent $event) {
    // ...
};

$form = $formFactory->createBuilder()
    // ... добавить поля формы
    ->addEventListener(FormEvents::PRE_SUBMIT, $listener);

// ...

Рабочий процесс формы

1) Предварительное заполнение формы (FormEvents::PRE_SET_DATA и FormEvents::POST_SET_DATA)

Во время предварительного заполнения формы, развёртываются два события, когда вызывается метод Form::setData(): FormEvents::PRE_SET_DATA и FormEvents::POST_SET_DATA.

A) Событие FormEvents::PRE_SET_DATA

Событие FormEvents::PRE_SET_DATA развёртывается в начале метода Form::setData(). Оно может быть использовано для:

  • Изменения данных, предоставленных во время предварительного заполнения;
  • Изменения формы, в зависимости от данных предварительного заполнения (динамическое добавление или удаление полей).
??? ?????? ????????
????????? ?????? null
??????????????? ?????? null
?????? ????????? null

See also

Увидеть все события форм одномоментно вы можете в Информационной таблице о событиях форм.

Caution

Во время FormEvents::PRE_SET_DATA, Form::setData() заблокирован и будет выдавать исключение при использовании. Если вы хотите измеить данные, вместо этого вам стоит использовать FormEvent::setData().

Тип формы Symfony\Component\Form\Extension\Core\Type\CollectionType полагается на подписчика Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener, слушающего событие FormEvents::PRE_SET_DATA для того, чтобы переупорядочить поля формы, в зависимости от данных из объекта редварительного заполнения, путём удаления или добавления всех строк формы.

B) Событие FormEvents::POST_SET_DATA

Событие FormEvents::POST_SET_DATA развёртывается в конце метода Form::setData(). Это событие в основном предназначено для чтения данных после предварительного заполнения формы.

??? ?????? ????????
????????? ?????? ?????????? ????????? ??????
??????????????? ?????? ????????? ??????, ??????????????? ? ??????? ?????????? ???????????????
?????? ????????? ??????????????? ??????, ??????????????? ? ??????? ??????????????? ?????????

See also

Увидеть все события форм одномоментно вы можете в Информационной таблице о событиях форм.

Класс Symfony\Component\Form\Extension\DataCollector\EventListener\DataCollectorListener подписан для прослушивания события FormEvents::POST_SET_DATA, чтобы собирать информацию о формах из денормализированных модельных данных и данных просмотра.

2) Отправка формы (FormEvents::PRE_SUBMIT, FormEvents::SUBMIT и FormEvents::POST_SUBMIT)

При вызове метода Form::handleRequest() или Form::submit(), развёртываются три события: FormEvents::PRE_SUBMIT, FormEvents::SUBMIT, FormEvents::POST_SUBMIT.

A) Событие FormEvents::PRE_SUBMIT

Событие FormEvents::PRE_SUBMIT развёртывается в начале метода Form::submit().

Оно может быть использовано для:

  • Изменения данных из запроса, до отправки данных в форму;
  • Добавления или удаления полей формы,до отправки данных в форму.
??? ?????? ????????
????????? ?????? ????? ??, ??? ? FormEvents::POST_SET_DATA
??????????????? ?????? ????? ??, ??? ? FormEvents::POST_SET_DATA
?????? ????????? ????? ??, ??? ? FormEvents::POST_SET_DATA

See also

Увидеть все события форм одномоментно вы можете в Информационной таблице о событиях форм.

Подписчик Symfony\Component\Form\Extension\Core\EventListener\TrimListener подписывается на событие FormEvents::PRE_SUBMIT, чтобы обрезать данные запроса (для значений строк). Подписчик Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener подписывается на событие FormEvents::PRE_SUBMIT, чтобы валидировать CSRF-токен.

B) Событие FormEvents::SUBMIT

Событие FormEvents::SUBMIT развёртывается прямо перед тем, как метод Form::submit() преобразует нормализированные данные в модельные данные и данные просмотра.

Оно может быть использовано для изменения данных из нормализированного представления данных.

??? ?????? ????????
????????? ?????? ????? ??, ??? ? FormEvents::POST_SET_DATA
??????????????? ?????? ?????? ?? ??????? ??????? ??????????????? ?? ??????? ? ?????????????? ???????????????
?????? ????????? ????? ??, ??? ? FormEvents::POST_SET_DATA

See also

Увидеть все события форм одномоментно вы можете в Информационной таблице о событиях форм.

Caution

На этом этапе вы не можете добавлять или удалять поля из формы.

Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener подписывается на событие FormEvents::SUBMIT, чтобы добавить протокол по умолчаниюк полям URL, которые были отправлены без протокола.

C) Событие FormEvents::POST_SUBMIT

Событие FormEvents::POST_SUBMIT развёртывается после Form::submit(), когда были денормализированы модельные данные и данные просмотра.

Оно может быть использовано, чтобы извлекать данные после денормализации.

??? ?????? ????????
????????? ?????? ??????????????? ?????? ??????? ??????????????? ? ??????? ??????????????? ??????
??????????????? ?????? ????? ??, ??? ? FormEvents::SUBMIT
?????? ????????? ??????????????? ?????? ??????????????? ? ??????? ??????????????? ?????????

See also

Увидеть все события форм одномоментно вы можете в Информационной таблице о событиях форм.

Caution

На этом этапе вы не можете добавлять или удалять поля из формы.

Symfony\Component\Form\Extension\DataCollector\EventListener\DataCollectorListener подписывается на событие FormEvents::POST_SUBMIT, чтобы собирать информацию о формах. Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener подписывается на событие FormEvents::POST_SUBMIT, чтобы автоматически валидировать денормализованный объект.

Регистрация слушателей или подписчиков событий

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

Имя каждого события "формы" определяется как константа в классе FormEvents. Дополнительно, каждому обратному вызову события (метод слушателя или подписчика) передаётся один аргумент, который является экземпляром класса FormEvent. Объект события содержит ссылку на текущее состояние формы и текущие данные, которые обрабатываются.

??? ????????? FormEvents ?????? ???????
form.pre_set_data FormEvents::PRE_SET_DATA ????????? ??????
form.post_set_data FormEvents::POST_SET_DATA ????????? ??????
form.pre_bind FormEvents::PRE_SUBMIT ?????? ???????
form.bind FormEvents::SUBMIT ??????????????? ??????
form.post_bind FormEvents::POST_SUBMIT ?????? ?????????

Слушатели событий

Слушатель событий может быть любым типом валидного вызываемого.

Создание и привязка слушателя собыйти - это очень просто:

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
// ...

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;

$form = $formFactory->createBuilder()
    ->add('username', TextType::class)
    ->add('show_email', CheckboxType::class)
    ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
        $user = $event->getData();
        $form = $event->getForm();

        if (!$user) {
            return;
        }

        // Проверяет, выбрал ли пользователь отображать его электронную почту.
        // Если данные были отправлены ранее, дополнительное значение,
        // включённое в переменных запроса, должно быть удалено.
        if (true === $user['show_email']) {
            $form->add('email', EmailType::class);
        } else {
            unset($user['email']);
            $event->setData($user);
        }
    })
    ->getForm();

// ...

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

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/Form/SubscriptionType.php
namespace App\Form;

use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

// ...
class SubscriptionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('username', TextType::class)
            ->add('show_email', CheckboxType::class)
            ->addEventListener(
                FormEvents::PRE_SET_DATA,
                array($this, 'onPreSetData')
            )
        ;
    }

    public function onPreSetData(FormEvent $event)
    {
        // ...
    }
}

Подписчики событий

Подписчики событий имеют разные применения:

  • Улучшение читаемости;
  • Прослушивание нескольких событий;
  • Регруппировка нескольких слушателей внутри одного класса.
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
41
42
43
44
45
46
47
48
49
50
// src/Form/EventListener/AddEmailFieldListener.php
namespace App\Form\EventListener;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\EmailType;

class AddEmailFieldListener implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return array(
            FormEvents::PRE_SET_DATA => 'onPreSetData',
            FormEvents::PRE_SUBMIT   => 'onPreSubmit',
        );
    }

    public function onPreSetData(FormEvent $event)
    {
        $user = $event->getData();
        $form = $event->getForm();

        // Проверяет, выбрал ли пользователь из первоначальных данных
        // отображать свою электронную почту
        if (true === $user->isShowEmail()) {
            $form->add('email', EmailType::class);
        }
    }

    public function onPreSubmit(FormEvent $event)
    {
        $user = $event->getData();
        $form = $event->getForm();

        if (!$user) {
            return;
        }

        // Проверяет, выбрал ли пользователь отображать свою электронную почту.
        // Если данные были отправлены ранее, дополнительное значение,
        // включенное в переменных запроса, должно быть удалено.
        if (true === $user['show_email']) {
            $form->add('email', EmailType::class);
        } else {
            unset($user['email']);
            $event->setData($user);
        }
    }
}

Для того, чтобы зарегистрировать подписчика событий, используйте метод addEventSubscriber():

1
2
3
4
5
6
7
8
9
10
11
12
13
use App\Form\EventListener\AddEmailFieldListener;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;

// ...

$form = $formFactory->createBuilder()
    ->add('username', TextType::class)
    ->add('show_email', CheckboxType::class)
    ->addEventSubscriber(new AddEmailFieldListener())
    ->getForm();

// ...