web-dev-qa-db-ja.com

Symfony2:カスタム複合フォームタイプに制約を使用する方法?

ここで私はしばらく頭を悩ませてきた質問です。私は(まだ)Symfony2のエキスパートではないため、どこかで新人のミスを犯した可能性があります。

Field1:標準のSymfony2 textフィールドタイプ

Field2:カスタムフィールドタイプcompoundfield with text field + checkbox field)

preview

My Goal: _autoValue's text input child_で機能するように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()
    )
));
_

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 %}
_

質問

私はかなり長い間ドキュメントとグーグルを読んでいて、このフォームを作成するときに追加された元の制約をコピー、バインド、または参照する方法を理解できません。

->誰かがこれを達成する方法を知っていますか?

->ボーナスポイント。メインフォームのバインドされたエンティティに追加された制約を有効にする方法(エンティティクラスの注釈を介して)

[〜#〜] ps [〜#〜]

すみません、長い質問になりました。問題を明確にすることに成功したことを願っています。そうでない場合は、詳細について私に尋ねてください!

16
Maurice

検証に関するドキュメント を最初にもう一度お読みになることをお勧めします。

これから私たちができることは、検証は主にフォームタイプではなくクラスで行われるということです。それはあなたが見落としたものです。あなたがする必要があるのは:

  • TextWithAutoValueTypeのデータクラスを作成するには、たとえばsrc/My/Bundle/Form/Model/TextWithAutoValueと呼ばれます。 textおよびcheckboxと呼ばれるプロパティと、それらのセッター/ゲッターを含める必要があります。
  • このデータクラスをフォームタイプに関連付けるには。このため、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

編集:

フォームタイプを別のタイプで使用する方法はすでにご存じだと思います。検証設定を定義するとき、 検証グループ と呼ばれる非常に便利なものを使用できます。ここに基本的な例を示します(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パラメータがあります。これは、検証グループ名を含む配列です。オブジェクトの検証を要求するときに、検証するグループのセットを指定できます。次に、システムは検証ファイルを調べて、どの制約を適用する必要があるかを調べます。

デフォルトでは、「デフォルト」グループがすべての制約に設定されています。これは、定期的な検証を実行するときに使用されるグループでもあります。

  • MyFormType :: getDefaultOptions()で特定のフォームタイプのデフォルトグループを指定するには、validation_groupsパラメータ(文字列の配列-検証グループの名前)、
  • MyFormType :: buildForm()でフォームタイプを別のタイプに追加する場合、特定の検証グループを使用できます。

もちろん、これはすべてのフォームタイプオプションの標準的な動作です。例:

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

さまざまなエンティティの使用に関しては、重ねたフォームと同じアーキテクチャに従ってデータクラスを重ねることができます。上記の例では、textWithAutoValueTypeを使用するフォームタイプには、「auto_text」プロパティと対応するゲッター/セッターを持つ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
13
Zephyr

ここで説明されているように https://speakerdeck.com/bschussek/3-steps-to-symfony2-form-mastery#39 (スライド39)Bernhard Schussek(symofnyフォーム拡張の主な貢献者)、トランスフォーマーは決して情報を変更するべきではなく、その表現を変更するだけです。

情報を追加すると(チェックボックス '=> true)、何かが間違っています。

編集中:

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

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

    $builder->addModelTransformer(
        new TextWithAutoValueTransformer()
    );
}
2
Asmir Mustafic