使用Symfony创建可为空的自定义表单实体

21

我的应用程序管理家庭。一个家庭由1个或N个成员组成。

我想要添加一个或两个父母以及0个或N个孩子的可能性。孩子部分工作正常,但是我在处理1或2个父母时遇到了困难。

这是我的家庭表单类型:

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

Parent和parent2是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无法验证我的表单。

如果我将这些字段(在构建器中)设置为required => false,则用户将有可能在不填写所有内容的情况下进行验证(我不想要这种情况)。

我想创建以下过程:

  • 要么我们填写成员2的所有字段以验证表单
  • 要么我们勾选复选框(单个父级),不需要任何字段,我的最终成员2将为空(或另一种解决方案)
1个回答

13

在阅读了大量的文档之后,我在这里找到了解决我的问题的方法:http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data

为了使一个实体不是必需的,你需要添加事件监听器并在提交后将数据设置为null。

第一步

向你的属性中添加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 函数,从您的字段中移除 required 属性即可。

 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 部分。这是在文档中提到的,我不知道是否有更清晰的方式来禁用该字段的验证。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接