Php Symfony2:如何对自定义复合表单类型使用约束?

Php Symfony2:如何对自定义复合表单类型使用约束?,php,symfony,constraints,symfony-forms,symfony-2.4,Php,Symfony,Constraints,Symfony Forms,Symfony 2.4,这是一个我已经绞尽脑汁想了一段时间的问题。 请知道我还不是Symfony2专家,所以我可能在某个地方犯了一个新手错误 字段1:标准Symfony2text字段类型 字段2:自定义字段类型复合带文本的字段字段+复选框字段) 我的目标:将约束添加到autoValue字段,以处理autoValue的文本输入子项 约束不起作用的原因可能是NotBlank需要字符串值,而此表单字段的内部数据是数组array('input'=>'value','checkbox'=>true)。此数组值通过自定义的Dat

这是一个我已经绞尽脑汁想了一段时间的问题。 请知道我还不是Symfony2专家,所以我可能在某个地方犯了一个新手错误

字段1:标准Symfony2
text
字段类型

字段2:自定义字段类型
复合
文本的字段
字段+
复选框
字段)

我的目标:将约束添加到
autoValue
字段,以处理
autoValue的文本输入子项

约束不起作用的原因可能是
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()
    )
));
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 %}
{%block textWithAutoValue\u widget%}
{%spaceless%}
{{form_小部件(form.value)}
{{form_小部件(form.checkbox)}
使用默认值
{%endspaceless%}
{%endblock%}

问题: 我已经阅读文档和谷歌好几个小时了,不知道如何复制、绑定或引用在构建表单时添加的原始约束

->有人知道如何做到这一点吗

->奖励积分;如何启用已添加到主窗体绑定实体的约束?(通过实体类上的注释)

PS


对不起,问题太长了,我希望我能把我的问题说清楚。如果没有,请问我更多细节

我建议你先再读一遍

从中我们可以看出,验证主要发生在类上,而不是表单类型上。这就是你忽略的。您需要做的是:

  • 要使用AutoValueType为您的文本创建数据类,请调用src/My/Bundle/Form/Model/TextWithAutoValue。它必须包含名为textcheckbox的属性及其setter/getter
  • 将此数据类与表单类型关联。为此,必须使用AutoValueType::getDefaultOptions()方法创建文本,并填充数据类选项。获取有关此方法的更多信息
  • 为数据类创建验证。对此,您可以使用注释或Resources/config/validation.yml文件。您必须将约束与类的属性相关联,而不是将约束与表单的字段相关联:
验证。yml

src/My/Bundle/Form/Model/TextWithAutoValue:
    properties:
        text:
            - Type:
                type: string
            - NotBlank: ~
        checkbox:
            - Type:
                type: boolean
编辑:

我假设您已经知道如何在另一个表单中使用表单类型。定义验证配置时,可以使用非常有用的东西,称为。下面是一个基本示例(在validation.yml文件中,因为我对验证注释不太精通):

有一个参数可以添加到每个约束中。它是一个包含验证组名称的数组。请求对对象进行验证时,可以指定要使用哪一组组进行验证。然后,系统将在验证文件中查找应该应用哪些约束

默认情况下,将在所有约束上设置“默认”组。这也是执行常规验证时使用的组

  • 通过设置validation_groups参数(字符串数组-验证组的名称),您可以在MyFormType::getDefaultOptions()中指定特定表单类型的默认组
  • 在将表单类型附加到另一个表单类型时,可以在MyFormType::buildForm()中使用特定的验证组
当然,这是所有表单类型选项的标准行为。例如:

$formBuilder->add('auto_text', 'textWithAutoValue', array(
    'label' => 'my_label',
    'validation_groups' => array('Default', 'Edit'),
));
至于不同实体的使用,您可以按照与堆积表单相同的体系结构来堆积数据类。在上面的示例中,使用textWithAutoValueType的表单类型必须具有具有“auto\u text”属性和相应getter/setter的数据类

在验证文件中,有效的约束将能够级联验证。有效的属性将检测属性的类别,并尝试为此类别找到相应的验证配置,并将其应用于相同的验证组:

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
正如Bernhard Schussek(symofny form extension的主要贡献者)在此所述(幻灯片39),转换器永远不应该更改信息,而应该只更改其表示形式

添加信息(复选框“=>true),您做错了

在 编辑:


+1.我有一个问题,但没有答案。@byf ferdy谢谢,这听起来像是一个类似的问题,但我不确定是否相同。我相信我的案例可能有更多的解决方案,因为在这两者之间有一个自定义表单类型。谢谢你,你说的有道理。对于具有不同约束的不同实体,我将如何重新使用此TextWithAutoValue类型?感谢您的详细说明。直到最后一部分,我都理解你所说的一切。这听起来是一个可行的解决方案。我会玩一玩,看看我跑了什么
src/My/Bundle/Form/Model/TextWithAutoValue:
    properties:
        text:
            - Type:
                type: string
            - NotBlank: ~
        checkbox:
            - Type:
                type: boolean
src/My/Bundle/Form/Model/TextWithAutoValue:
    properties:
        text:
            - Type:
                type: string
                groups: [ Default, Create, Edit ]
            - NotBlank:
                groups: [ Edit ]
        checkbox:
            - Type:
                type: boolean
$formBuilder->add('auto_text', 'textWithAutoValue', array(
    'label' => 'my_label',
    'validation_groups' => array('Default', 'Edit'),
));
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
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('value', 'text', $options);

    $builder->add('checkbox', 'checkbox', array('mapped'=>false));

    $builder->addModelTransformer(
        new TextWithAutoValueTransformer()
    );
}