简体   繁体   English

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

[英]Symfony2: How to use constraints on custom compound form type?

Here is a question I've been breaking my head over for a while now. 这是一个我一直在讨厌的问题。 Please know that I'm not a Symfony2 expert (yet), so I might have made a rookie mistake somewhere. 请知道我还不是Symfony2专家,所以我可能在某个地方犯了一个菜鸟错误。

Field1: Standard Symfony2 text field type Field1:标准Symfony2 text字段类型

Field2: Custom field type compound field with text field + checkbox field) Field2:自定义字段类型compound字段,带有text字段+ checkbox字段)

预习

My Goal: Getting constraints added to the autoValue field to work on the autoValue's text input child 我的目标:将约束添加到autoValue字段以处理autoValue's text input child

The reason why the constraints don't work is probably because NotBlank is expecting a string value and the internal data of this form field is an array array('input'=>'value', 'checkbox' => true) . 约束不起作用的原因可能是因为NotBlank期望一个字符串值,并且此表单字段的内部数据是一个数组array('input'=>'value', 'checkbox' => true) This array value gets transformed back into a string with a custom DataTransformer . 此数组值将转换回具有自定义DataTransformer的字符串。 I suspect however that that happens AFTER validating the field against known constraints. 但我怀疑在根据已知约束验证字段后会发生这种情况。

As you see below in commented code, I have been able to get constraints working on the text input, however only when hardcoded into the autoValue's form type, and I want to validate against the main field's constraints. 正如您在注释代码中看到的那样,我已经能够在文本输入上获得约束,但是只有当硬编码到autoValue的表单类型中时,我才能根据主要字段的约束进行验证。

My (simplified) sample code for controller and field: 控制器和字段的我(简化)示例代码:

.

Controller code 控制器代码

Setting up a quick form for testing purposes. 设置快速表单以进行测试。

<?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 source files TextWithAutoValue源文件

src/My/Component/Form/Type/TextWithAutoValueType.php SRC /我的/分量/表/类型/ 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 SRC /我的/分量/表格/ 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 SRC /我的/ ComponentBundle /资源/配置/ 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 SRC /我的/ ComponentBundle /资源/视图/表格/ 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 %}

.

Question

I have been reading docs and google for quite some hours now and can't figure out how to copy, bind, or reference the original constraints that have been added while building this form. 我一直在阅读docs和google几个小时,无法弄清楚如何复制,绑定或引用构建此表单时添加的原始约束。

-> Does anyone know how to accomplish this? - >有谁知道怎么做到这一点?

-> For bonus points; - >奖励积分; how to enable the constraints that have been added to the main form's bound entity? 如何启用已添加到主窗体绑定实体的约束? (via annotations on the entity class) (通过实体类的注释)

PS PS

Sorry it became such a long question, I hope that I succeeded in making my issue clear. 对不起它成了这么长的问题,我希望我成功地解决了我的问题。 If not, please ask me for more details! 如果没有,请向我询问更多详情!

I suggest you read again the documentation about validation first. 我建议您先阅读有关验证文档

What we can make out of this is that validation primarily occurs on classes rather than form types. 我们可以做到的是验证主要发生在类而不是表单类型上。 That is what you overlooked. 那是你忽略的。 What you need to do is: 你需要做的是:

  • To create a data class for your TextWithAutoValueType , called src/My/Bundle/Form/Model/TextWithAutoValue for instance. 要为TextWithAutoValueType创建一个数据类,例如,名为src / My / Bundle / Form / Model / TextWithAutoValue It must contain properties called text and checkbox and their setters/getters; 它必须包含名为textcheckbox的属性及其setter / getter;
  • To associate this data class to your form type. 将此数据类与表单类型相关联。 For this, you must create a TextWithAutoValueType::getDefaultOptions() method and populate the data_class option. 为此,您必须创建TextWithAutoValueType :: getDefaultOptions()方法并填充data_class选项。 Go here for more info about this method; 到这里获取有关此方法的更多信息;
  • Create validation for your data class. 为您的数据类创建验证。 You can either use annotations or a Resources/config/validation.yml file for this. 您可以使用注释或Resources / config / validation.yml文件。 Instead of associating your constraints to the fields of your form, you must associate them to the properties of your class: 您必须将它们与类的属性相关联,而不是将约束与表单的字段相关联:

validation.yml : validation.yml

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

Edit: 编辑:

I assume that you already know how to use a form type in another. 我假设您已经知道如何在另一个表单中使用表单类型。 When defining your validation configuration, you can use a very useful something, called validation groups . 定义验证配置时,您可以使用一个非常有用的东西,称为验证组 Here a basic example (in a validation.yml file, since I'm not much proficient with validation annotations): 这是一个基本的例子(在validation.yml文件中,因为我不太熟悉验证注释):

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

There is a groups parameter that can be added to every constraint. 有一个groups参数可以添加到每个约束。 It is an array containing validation group names. 它是一个包含验证组名称的数组。 When requesting a validation on an object, you can specify with which set of groups you want to validate. 请求对对象进行验证时,您可以指定要验证的组集。 The system will then look in the validation file what constraints should be applied. 然后,系统将在验证文件中查找应该应用的约束。

By default, the "Default" group is set on all constraints. 默认情况下,“默认”组在所有约束上设置。 This also is the group that is used when performing a regular validation. 这也是执行常规验证时使用的组。

  • You can specify the default groups of a specific form type in MyFormType::getDefaultOptions() , by setting the validation_groups parameter (an array of strings - names of validation groups), 您可以通过设置validation_groups参数(字符串数组 - 验证组的名称 ,在MyFormType :: getDefaultOptions()中指定特定表单类型的默认组,
  • When appending a form type to another, in MyFormType::buildForm() , you can use specific validation groups. 将表单类型附加到另一个表单类型时,在MyFormType :: buildForm()中 ,您可以使用特定的验证组。

This, of course, is the standard behaviour for all form type options. 当然,这是所有表单类型选项的标准行为。 An example: 一个例子:

$formBuilder->add('auto_text', 'textWithAutoValue', array(
    'label' => 'my_label',
    'validation_groups' => array('Default', 'Edit'),
));

As for the use of different entities, you can pile up your data classes following the same architecture than your piled-up forms. 至于使用不同的实体,您可以使用与堆积形式相同的架构来堆积数据类。 In the example above, a form type using textWithAutoValueType will have to have a data_class that has a 'auto_text' property and the corresponding getter/setter. 在上面的示例中,使用textWithAutoValueType的表单类型必须具有data_class,该data_class具有'auto_text'属性和相应的getter / setter。

In the validation file, the Valid constraints will be able to cascade validation. 在验证文件中, 有效约束将能够级联验证。 A property with Valid will detect the class of the property and will try to find a corresponding validation configuration for this class, and apply it with the same validation groups: 具有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

As described here https://speakerdeck.com/bschussek/3-steps-to-symfony2-form-mastery#39 (slide 39) by Bernhard Schussek (the main contributor of symofny form extension), a transformer should never change the information, but only change its representation. 如下所述https://speakerdeck.com/bschussek/3-steps-to-symfony2-form-mastery#39 (幻灯片39)由Bernhard Schussek(symofny表格扩展的主要贡献者),变压器应该永远不会改变信息,但只改变其代表性。

Adding the information (checkbox' => true), you are doing something wrong. 添加信息(复选框'=> true),你做错了什么。

In Edit: 在编辑中:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('value', 'text', $options);

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM