草庐IT

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

coder 2024-04-18 原文

我正在尝试创建一个包含付款和送货地址的地址表。选中送货地址上的复选框后,我想跳过对该地址进行的表单验证。

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

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

AddressTypeAddress 类构建表单(它对某些字段有注释约束,如 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();

我已经研究了几个小时了,但我无法推断出为什么没有关闭验证,而且我不愿意因为这个小细节而搞砸表格。

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

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

最佳答案

[...] so I just disable the default group to disable validation on the entity.

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

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

// etc.

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

https://symfony.com/doc/current/validation/groups.html: If no groups are specified, all constraints that belong to the group Default will be applied.

整洁地完成部分关闭验证的解决方案

是不是应该有很多种实现方式,我给大家展示其中两种:

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

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

    接下来,在 configureOptions 方法中,将 Address 组设置为默认值,如果选中“toggle”,则将 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
        ]);
    }
    

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

  2. (另一种方式)在 Address 类中将“Required”组添加到所有约束,它避免使用 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 组,跳过因此是必填字段。

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

关于php - 如果在 Symfony 中选中了复选框,则关闭表单类型的验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45715796/

有关php - 如果在 Symfony 中选中了复选框,则关闭表单类型的验证的更多相关文章

  1. ruby-on-rails - Rails 编辑表单不显示嵌套项 - 2

    我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib

  2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  3. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  4. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  5. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  6. ruby-on-rails - 如果我将 ruby​​ 版本 2.5.1 与 rails 版本 2.3.18 一起使用会怎样? - 2

    如果我使用ruby​​版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby​​1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更

  7. ruby - 如何关闭 ruby​​ gem "Spreadsheet?"中的文件 - 2

    下面的代码在我第一次运行它时就可以正常工作:require'rubygems'require'spreadsheet'book=Spreadsheet.open'/Users/me/myruby/Mywks.xls'sheet=book.worksheet0row=sheet.row(1)putsrow[1]book.write'/Users/me/myruby/Mywks.xls'当我再次运行它时,我会收到更多消息,例如:/Library/Ruby/Gems/1.8/gems/spreadsheet-0.6.5.9/lib/spreadsheet/excel/reader.rb:11

  8. ruby - 如果它是标点符号,我怎么能从字符串中删除最后一个字符,在 ruby​​ 中? - 2

    啊,正则表达式有点困惑。我正在尝试删除字符串末尾所有可能的标点符号:ifstr[str.length-1]=='?'||str[str.length-1]=='.'||str[str.length-1]=='!'orstr[str.length-1]==','||str[str.length-1]==';'str.chomp!end我相信有更好的方法来做到这一点。有什么指点吗? 最佳答案 str.sub!(/[?.!,;]?$/,'')[?.!,;]-字符类。匹配这5个字符中的任何一个(注意,。在字符类中并不特殊)?-前一个字符或组

  9. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

    一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

  10. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

随机推荐