Symfony2:如何对自定义复合表单类型使用约束?
Posted
技术标签:
【中文标题】Symfony2:如何对自定义复合表单类型使用约束?【英文标题】:Symfony2: How to use constraints on custom compound form type? 【发布时间】:2014-02-24 12:42:32 【问题描述】:这是一个我已经思考了一段时间的问题。 请注意,我(还)不是 Symfony2 专家,所以我可能在某个地方犯了一个新手错误。
Field1:标准 Symfony2 text
字段类型
Field2:自定义字段类型 compound
field 和 text
字段 + checkbox
字段)
我的目标:将约束添加到 autoValue
字段以处理 autoValue's text input child
约束不起作用的原因可能是因为NotBlank
需要一个字符串值,而这个表单字段的内部数据是一个数组array('input'=>'value', 'checkbox' => true)
。这个数组值被转换回带有自定义DataTransformer
的字符串。然而,我怀疑这是在针对已知约束验证字段之后发生的。
正如您在下面的注释代码中看到的那样,我已经能够在文本输入上获得约束,但是只有在硬编码到 autoValue 的表单类型中并且我想针对主字段的约束进行验证时。
我的(简化的)控制器和字段示例代码:
.
控制器代码
为测试目的设置一个快速表单。
<?php
//...
// $entityInstance holds an entity that has it's own constraints
// that have been added via annotations
$formBuilder = $this->createFormBuilder( $entityInstance, array(
'attr' => array(
// added to disable html5 validation
'novalidate' => 'novalidate'
)
));
$formBuilder->add('regular_text', 'text', array(
'constraints' => array(
new \Symfony\Component\Validator\Constraints\NotBlank()
)
));
$formBuilder->add('auto_text', 'textWithAutoValue', array(
'constraints' => array(
new \Symfony\Component\Validator\Constraints\NotBlank()
)
));
.
TextWithAutoValue 源文件
src/My/Component/Form/Type/TextWithAutoValueType.php
<?php
namespace My\Component\Form\Type;
use My\Component\Form\DataTransformer\TextWithAutoValueTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class TextWithAutoValueType extends AbstractType
/**
* @inheritdoc
*/
public function buildForm(FormBuilderInterface $builder, array $options)
$builder->add('value', 'text', array(
// when I uncomment this, the NotBlank constraint works. I just
// want to validate against whatever constraints are added to the
// main form field 'auto_text' instead of hardcoding them here
// 'constraints' => array(
// new \Symfony\Component\Validator\Constraints\NotBlank()
// )
));
$builder->add('checkbox', 'checkbox', array(
));
$builder->addModelTransformer(
new TextWithAutoValueTransformer()
);
public function getName()
return 'textWithAutoValue';
src/My/Component/Form/DataTransformer/TextWithAutoValueType.php
<?php
namespace My\Component\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
class TextWithAutoValueTransformer
implements DataTransformerInterface
/**
* @inheritdoc
*/
public function transform($value)
return array(
'value' => (string) $value,
'checkbox' => true
);
/**
* @inheritdoc
*/
public function reverseTransform($value)
return $value['value'];
src/My/ComponentBundle/Resources/config/services.yml
parameters:
services:
my_component.form.type.textWithAutoValue:
class: My\Component\Form\Type\TextWithAutoValueType
tags:
- name: form.type, alias: textWithAutoValue
src/My/ComponentBundle/Resources/views/Form/fields.html.twig
% block textWithAutoValue_widget %
% spaceless %
form_widget(form.value)
form_widget(form.checkbox)
<label for=" form.checkbox.vars.id">use default value</label>
% endspaceless %
% endblock %
.
问题
我已经阅读 docs 和 google 好几个小时了,不知道如何复制、绑定或引用在构建此表单时添加的原始约束。
-> 有谁知道如何做到这一点?
-> 用于奖励积分;如何启用已添加到主窗体绑定实体的约束? (通过实体类上的注释)
附言
抱歉,问题变得这么长,我希望我成功地把我的问题说清楚了。如果没有,请向我询问更多详细信息!
【问题讨论】:
+1。我有一个same question,但对此没有答案。 @byf-ferdy 谢谢,这听起来像是一个类似的问题,但我不确定它是否是 same。我相信我的案例可能有更多解决方法的选择,因为两者之间有一个自定义表单类型。 【参考方案1】:正如 Bernhard Schussek(symofny 表单扩展的主要贡献者)在 https://speakerdeck.com/bschussek/3-steps-to-symfony2-form-mastery#39(幻灯片 39)中所述,转换器永远不应更改信息,而应仅更改其表示形式。
添加信息(复选框'=> true),你做错了什么。
在 编辑:
public function buildForm(FormBuilderInterface $builder, array $options)
$builder->add('value', 'text', $options);
$builder->add('checkbox', 'checkbox', array('mapped'=>false));
$builder->addModelTransformer(
new TextWithAutoValueTransformer()
);
【讨论】:
公平。这只是我尝试在前端获得一个有效的复选框。我只需要它作为接口,我不需要它作为实体的一部分或类似的东西。我只是在检查时使用它来自动填充随附的文本字段。我将它添加到表单中是因为我想在 POST 请求之间保持选中/取消选中。你知道有什么方法可以做到吗? 如果使用 Zephyr 描述的 TextWithCheckbox 类,可以在类构造函数中设置复选框的默认 true 值。【参考方案2】:我建议你先读一遍documentation about validation。
我们可以由此得出的结论是,验证主要发生在类而不是表单类型上。那是你忽略的。你需要做的是:
为您的 TextWithAutoValueType 创建一个数据类,例如称为 src/My/Bundle/Form/Model/TextWithAutoValue。它必须包含名为 text 和 checkbox 的属性及其 setter/getter; 将此数据类与您的表单类型相关联。为此,您必须创建 TextWithAutoValueType::getDefaultOptions() 方法并填充 data_class 选项。转至here 了解有关此方法的更多信息; 为您的数据类创建验证。为此,您可以使用注释或 Resources/config/validation.yml 文件。您必须将约束与您的类的属性相关联,而不是将您的约束与表单的字段相关联:validation.yml:
src/My/Bundle/Form/Model/TextWithAutoValue:
properties:
text:
- Type:
type: string
- NotBlank: ~
checkbox:
- Type:
type: boolean
编辑:
我假设您已经知道如何在另一个表单类型中使用。在定义验证配置时,您可以使用一个非常有用的东西,称为validation groups。这是一个基本示例(在 validation.yml 文件中,因为我不太精通验证注释):
src/My/Bundle/Form/Model/TextWithAutoValue:
properties:
text:
- Type:
type: string
groups: [ Default, Create, Edit ]
- NotBlank:
groups: [ Edit ]
checkbox:
- Type:
type: boolean
有一个 groups 参数可以添加到每个约束条件中。它是一个包含验证组名称的数组。请求对对象进行验证时,您可以指定要验证的组集。然后系统将在验证文件中查看应该应用哪些约束。
默认情况下,“默认”组设置在所有约束上。这也是执行常规验证时使用的组。
您可以通过设置 validation_groups 参数(字符串数组 - 验证名称)在 MyFormType::getDefaultOptions() 中指定特定表单类型的默认组组), 将表单类型附加到另一个表单类型时,在 MyFormType::buildForm() 中,您可以使用特定的验证组。当然,这是所有表单类型选项的标准行为。一个例子:
$formBuilder->add('auto_text', 'textWithAutoValue', array(
'label' => 'my_label',
'validation_groups' => array('Default', 'Edit'),
));
对于不同实体的使用,您可以按照与堆积形式相同的架构堆积数据类。在上面的示例中,使用 textWithAutoValueType 的表单类型必须有一个具有“auto_text”属性和相应 getter/setter 的 data_class。
在验证文件中,Valid 约束将能够级联验证。具有 Valid 的属性将检测该属性的类,并尝试为该类找到相应的验证配置,并将其应用于相同的验证组:
src/My/Bundle/Form/Model/ContainerDataClass:
properties:
auto_text:
Valid: ~ # Will call the validation conf just below with the same groups
src/My/Bundle/Form/Model/TextWithAutoValue:
properties:
... etc
【讨论】:
谢谢,你说的很有道理。我如何将这个 TextWithAutoValue 类型重新用于具有不同约束的不同实体? 感谢您的详细说明。我理解你所说的一切的运作,直到最后一部分。这听起来像是一个可行的解决方案。我会玩弄它,看看我遇到了什么。 我将奖励您提供最有帮助的答案。我没有让它按我的意愿工作,但话又说回来,我的问题可能没有答案。再次感谢您的帮助。以上是关于Symfony2:如何对自定义复合表单类型使用约束?的主要内容,如果未能解决你的问题,请参考以下文章