我正在尝试使用付款和送货地址创建地址表单。当选中送货地址上的复选框时,我想跳过在该地址上发生的表单验证。
我创建了下面的表单类型,其中包含一个切换选项,该选项将显示并处理复选框,但即使选中该表单仍然有效。
Symfony有documentation on how to implement such a form,即使我几乎拥有完全相同的代码,检查时也不会关闭验证。我没有使用验证组,所以我只是禁用默认组来禁用实体验证。
AddressType
构建Address
类的表单(在NotBlank
和Callback
等特定字段上有注释限制。)
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自己的资源都表明它应该可以工作......
答案 0 :(得分:2)
[......]所以我只是禁用默认组来禁用实体验证。
假设Address
属性&约束看起来像这样:
/**
* @Assert\NotBlank()
*/
private $name;
// etc.
"验证器"假设这些属性将使用Default
组进行评估,因为他始终将空validation_groups
(例如return [];
)视为['Default']
(因此在检查时不会关闭验证):
https://symfony.com/doc/current/validation/groups.html: 如果未指定任何组,则将应用属于组
Default
的所有约束。
以完整的方式部分关闭验证的解决方案
是否有很多方法可以实现它,但我向您展示了其中两个:
如果没有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
]);
}
这意味着,在提交时切换为关闭:Form
和Address
组应用于地址字段,否则,仅应用Form
组。
(另一种方式)在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
]);
}
在这种情况下,在提交时切换为关闭:Default
和Required
组应用于地址字段,否则仅应用Default
组,从而跳过必填字段。
可以通过将约束选项设置为new Valid()
来验证包含与根对象断开连接的对象的嵌套表单。