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

这是一个我已经打破头了一段时间的问题。请注意,我还不是Symfony2专家,所以我可能在某个地方犯了一个新手错误。

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

字段 2:具有字段 + 字段的自定义字段类型字段)compoundtextcheckbox

preview

我的目标:将约束添加到字段以处理autoValueautoValue's text input child

约束不起作用的原因可能是因为 需要一个字符串值,并且此表单字段的内部数据是一个数组 。此数组值将转换回具有自定义 的字符串。但是,我怀疑在根据已知约束验证字段之后会发生这种情况。NotBlankarray('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/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 %}

.

问题

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

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

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

附言

对不起,这成了一个很长的问题,我希望我成功地把我的问题说清楚了。如果没有,请向我询问更多详细信息!


答案 1

我建议您先再次阅读有关验证的文档

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

  • 为您的TextWithAutoValueType创建一个数据类,例如称为src/My/Bundle/Form/Model/TextWithAutoValue。它必须包含称为文本复选框的属性及其设置者/获取器;
  • 将此数据类与表单类型相关联。为此,您必须创建一个 TextWithAutoValueType::getDefaultOptions() 方法并填充data_class选项。转到此处以获取有关此方法的更多信息;
  • 为数据类创建验证。为此,您可以使用批注或 Resources/config/validation.yml 文件。您不必将约束与窗体的字段相关联,而必须将它们与类的属性相关联:

validation.yml

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

编辑:

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

src/My/Bundle/Form/Model/TextWithAutoValue:
    properties:
        text:
            - Type:
                type: string
                groups: [ Default, Create, Edit ]
            - NotBlank:
                groups: [ Edit ]
        checkbox:
            - Type:
                type: boolean

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

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

  • 您可以通过设置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 的属性将检测该属性的类,并将尝试查找此类的相应验证配置,并使用相同的验证组应用它:

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

答案 2

正如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()
    );
}

推荐