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

Vil*_*men 6 php forms validation symfony

我正在尝试创建一个带有付款和送货地址的地址表单。检查送货地址上的复选框时,我想跳过该地址上发生的表单验证。

我在下面创建了带有切换选项的表单类型,该选项将显示和处理复选框,但是即使选中该表单,该表单仍会得到验证。

Symfony 有关于如何实现这种表单的文档,即使我几乎拥有完全相同的代码,但在检查时不会关闭验证。我没有使用验证组,所以我只是禁用默认组来禁用对实体的验证。

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"]);
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用这样的类型:

$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();
Run Code Online (Sandbox Code Playgroud)

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

为什么AddressTypeconfigureOptions 中的闭包未关闭验证?如果这不是它的工作原理,那么以整洁的方式完成部分关闭验证的更好解决方案是什么?

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

yce*_*uto 5

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

假设Address属性和约束如下所示:

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

// etc.
Run Code Online (Sandbox Code Playgroud)

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

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

一种以简洁的方式完成部分关闭验证的解决方案

应该有很多方法可以实现它,但我向您展示其中两种:

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

    $addressForm = $this
        ->createFormBuilder([...], [
            'validation_groups' => 'Form', // <--- set
        ])
    
    Run Code Online (Sandbox Code Playgroud)

    接下来,在configureOptions方法中,将Address组设置为默认值,Form如果选中“切换”则设置组,还添加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
        ]);
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

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

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

    接下来,在设置为默认组的configureOptions方法中,如果选中切换:RequiredDefault

    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
        ]);
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

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