Подтвердить что ты не робот

Необязательный пользовательский объект формы с Symfony

Мое приложение управляет семьями. Одно семейство состоит из 1 или N членов.

Я хочу, чтобы добавить одного родителя или двух и 0 или N детей. Детская часть отлично работает, но мне трудно справляться с 1 или 2 родителями.

Вот мой тип формы семьи:

 $builder
        ... many attributes
        ->add('parent1', MemberType::class)
        ->add('parent2', MemberType::class)

Родительский и родительский 2 - это ассоциация OneToOne (от семейства к члену). Тип формы участника:

 $builder
        ->add('firstName', TextType::class, [
            'label' => 'Prénom',
            'constraints' => array(
                new NotBlank(),
                new Length(array('max' => 150))
            )
        ])
        ... many other attributes with choices or not

Я думал о флажке, который серым цветом полей родителя 2, если он не отмечен, но все значения членов требуются. Из-за этого SF2 не подтверждает мою форму.

Если я установил обязательный = > false для этих полей (в построителе), тогда у пользователя будет возможность проверить, не заполняя все (что мне не нужно).

Я хотел бы создать следующий процесс:

  • Либо мы заполняем все поля члена2, чтобы проверить форму
  • Либо мы проверяем флажок (одиночный родительский элемент), и поле не требуется, и мой последний член2 будет нулевым (или другим решением)
4b9b3361

Ответ 1

После прочтения большого количества документации я нашел решение моей проблемы здесь: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data

Чтобы сделать объект не требуемым, вы должны добавить слушателя событий и установить данные как отправку с нулевым сообщением.

Первый шаг

Добавьте параметр orphanRemoval=true к вашему атрибуту

/**
 * @ORM\OneToOne(targetEntity="AppBundle\Entity\Member", orphanRemoval=true, cascade={"persist", "remove"})
 * @ORM\JoinColumn(name="parent2_id", referencedColumnName="id",nullable=true)
 */
private $parent2;

Второй шаг

Добавить новое поле в вашу форму, не отображаемый флажок

   $builder
        ->add('parent1', MemberType::class)
        ->add('withParent2', CheckboxType::class, [
            'mapped'            => false,
            'required'          => false,
            'data'              => true
        ])
        ->add('parent2', MemberType::class, [
            'required'          => false
        ])

Мы будем использовать этот флажок, чтобы установить parent2 в null, если не отмечен.

Рядом с этим добавьте слушателей событий:

   //this event will set whether or not the checkbox should be checked
   $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
        $form = $event->getForm();
        $family = $event->getData();

        if ($family->getId()) {
            $form->add('withParent2', CheckboxType::class, [
                'mapped'        => false,
                'required'      => false,
                'data'          => $family->getParent2() ? true : false
            ]);
        }
    });

    //Event when the form is submitted, before database update
    $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {

        //if the checkbox was not checked, it means that there was not a second parent
        $withParent2 = $event->getForm()->get('withParent2')->getData();
        if (!$withParent2) {

            // we set this attribute to null, and disable the form validation
            $event->getData()->setParent2(null);
            $event->stopPropagation();
        }

    }, 900);

Третий шаг

Наша форма работает нормально, единственная проблема - проверка javascript.

Просто выполните функцию jquery, которая удалит требуемый атрибут из ваших полей.

 function toggleParent2Requirement(checked){
        if (!checked) {
            $("[id^=family_parent2]").prop("required", false);
            $("[id^=family_parent2]").attr('disabled', true);
        }
        else {
            $("[id^=family_parent2]").prop("required", true);
            $("[id^=family_parent2]").attr('disabled', false);
        }
    }

Здесь вы делаете одностороннее отношение необязательным. Единственная часть, которой я не горжусь, это часть stopPropagation. Это было в документации, и я не знаю, можем ли мы только отключить эту проверку поля более чистым способом.