如果在Symfony中选中了复选框,请关闭表单类型的验证

时间:2017-08-16 14:07:06

标签: php forms symfony validation

我正在尝试使用付款和送货地址创建地址表单。当选中送货地址上的复选框时,我想跳过在该地址上发生的表单验证。

我创建了下面的表单类型,其中包含一个切换选项,该选项将显示并处理复选框,但即使选中该表单仍然有效。

Symfony有documentation on how to implement such a form,即使我几乎拥有完全相同的代码,检查时也不会关闭验证。我没有使用验证组,所以我只是禁用默认组来禁用实体验证。

AddressType构建Address类的表单(在NotBlankCallback等特定字段上有注释限制。)

class AddressType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        if ($options["toggle"]) {
            $builder->add("toggle", CheckboxType::class, [
                "mapped" => false,
                "required" => false,
                "label" => $options["toggle"]
            ]);
        }

        $builder
            ->add("name", TextType::class, [
                "required" => !$options["toggle"]
            ])
            ->add("address", TextType::class, [
                "required" => !$options["toggle"]
            ])
            ->add("zipcode", TextType::class, [
                "label" => "Postcode",
                "required" => !$options["toggle"]
            ])
            ->add("city", TextType::class, [
                "required" => !$options["toggle"]
            ])
            ->add("countryCode", ChoiceType::class, [
                "choices" => Address::COUNTRY_CODES
            ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            "toggle" => false,
            "data_class" => Address::class,
            "validation_groups" => function(FormInterface $form) {
                if ($form->has("toggle") && $form->get("toggle")->getData() === true) {
                    return [];
                }

                return ["Default"];
            }
        ]);

        $resolver->setAllowedTypes("toggle", ["bool", "string"]);
    }
}

我使用这样的类型:

$addressForm = $this
    ->createFormBuilder([
        "paymentAddress" => $paymentAddress,
        "shippingAddress" => $shippingAddress
    ])
    ->add("paymentAddress", AddressType::class, [
        "label" => false
    ])
    ->add("shippingAddress", AddressType::class, [
        "label" => false,
        "toggle" => "Use payment address"
    ])
    ->add("submit", SubmitType::class, [
    ])
    ->getForm();

我已经花了几个小时来讨论这个问题,但我无法推断为什么验证没有被关闭,而且我不愿意在这个小细节上填写表格。

为什么configureOptions中的闭包没有关闭AddressType的验证?如果这不是它的工作方式,那么以一种整洁的方式部分关闭验证会有什么更好的解决方案呢?

编辑:即使在默认设置中,在构建器中创建的子项中或在表单的使用中设置"validation_groups" => false,仍将进行验证。它与封闭无关。每个在线资源,包括Symfony自己的资源都表明它应该可以工作......

1 个答案:

答案 0 :(得分:2)

  

[......]所以我只是禁用默认组来禁用实体验证。

假设Address属性&约束看起来像这样:

/**
 * @Assert\NotBlank()
 */
private $name;

// etc.

"验证器"假设这些属性将使用Default组进行评估,因为他始终将空validation_groups(例如return [];)视为['Default'](因此在检查时不会关闭验证):

  

https://symfony.com/doc/current/validation/groups.html:   如果未指定任何组,则将应用属于组Default的所有约束。

以完整的方式部分关闭验证的解决方案

是否有很多方法可以实现它,但我向您展示了其中两个:

  1. 如果没有data_class设置为根表单,则Form组可用于仅验证此级别:

    $addressForm = $this
        ->createFormBuilder([...], [
            'validation_groups' => 'Form', // <--- set
        ])
    

    接下来,在configureOptions方法中,将Address组设置为默认值,将Form组设置为&#34;切换&#34;已选中,还为级联验证添加了Valid()约束:

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            // ...
            "validation_groups" => function(FormInterface $form) {
                if ($form->has("toggle") && $form->get("toggle")->getData() === true) {
                    return ['Form']; // <--- set
                }
    
                return ['Address']; // <--- set
            },
            'constraints' => [new Assert\Valid()], // <--- set
        ]);
    }
    

    这意味着,在提交时切换为关闭:FormAddress组应用于地址字段,否则,仅应用Form组。

  2. (另一种方式)在Address类中添加&#34;必需&#34;将所有约束分组,它避免使用Default组验证这些属性:

    /**
     * @Assert\NotBlank(groups={"Required"}) // <--- set
     */
    private $name;
    
    // etc.
    

    接下来,在configureOptions方法集Required作为默认组,Default如果选中切换:

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            // ...
            "validation_groups" => function(FormInterface $form) {
                if ($form->has("toggle") && $form->get("toggle")->getData() === true) {
                    return ['Default']; // <--- set
                }
    
                return ['Required']; // <--- set
            },
            'constraints' => [new Assert\Valid()], // <--- set
        ]);
    }
    

    在这种情况下,在提交时切换为关闭:DefaultRequired组应用于地址字段,否则仅应用Default组,从而跳过必填字段。

  3. 可以通过将约束选项设置为new Valid()来验证包含与根对象断开连接的对象的嵌套表单。