Home | Symfony2Doc »リファレンスドキュメント »Form Type リファレンス »collection フィールドタイプ

コンテンツ上部に更新日の記載のないページは、翻訳の内容が2.0相当のものになっております。最新の内容は原文のページをご確認ください。

Note

  • 対象バージョン : 2.3
  • 翻訳更新日 : 2013/12/01

collection フィールドタイプ

このフィールドタイプは複数のフィールドやフォームの”コレクション”の表示に使われます。 最も簡単なところでは、複数のメールアドレス用フィールドを表示するために、テキストフィールドの配列をマップできます。 より複雑な例では、フォーム全体をコレクションの要素として扱うこともできます。 たとえば、製品情報と製品に関連する多くの写真を、1つの製品情報フォームにまとめて管理したい場合に便利です。

対応するタグ type オプションに依存
オプション
継承された オプション
親タイプ form
クラス CollectionType

Note

もしDoctrineのエンティティとあわせて使っている場合、 allow_addallow_deleteby_reference オプションには特に注意を払ってください。 クックブックの記事「 フォームのコレクションを埋め込む方法 」に完全な例があります。

基本的な使い方

このタイプは、ひとつのフォーム中にある類似アイテムのコレクションを管理したいときに使われます。 たとえば、メールアドレス配列に対応する emails フィールドがあるとします。フォーム中では1つのメールアドレスにつきテキストボックスを1つずつ出力したいです:

$builder->add('emails', 'collection', array(
    //配列の中のどのアイテムも "email" フィールドとされます
    'type'   => 'email',
    // これらのオプションはすべて "email" タイプに渡されます
    'options'  => array(
        'required'  => false,
        'attr'      => array('class' => 'email-box')
    ),
));

一番簡単に表示する方法はすべてを一度で行うことです:

  • Twig
    {{ form_row(form.emails) }}
    
  • PHP
    <?php echo $view['form']->row($form['emails']) ?>
    

より柔軟な方法は以下のようになります:

  • Twig
    {{ form_label(form.emails) }}
    {{ form_errors(form.emails) }}
    
    <ul>
    {% for emailField in form.emails %}
        <li>
            {{ form_errors(emailField) }}
            {{ form_widget(emailField) }}
        </li>
    {% endfor %}
    </ul>
    
  • PHP
    <?php echo $view['form']->label($form['emails']) ?>
    <?php echo $view['form']->errors($form['emails']) ?>
    
    <ul>
    <?php foreach ($form['emails'] as $emailField): ?>
        <li>
            <?php echo $view['form']->errors($emailField) ?>
            <?php echo $view['form']->widget($emailField) ?>
        </li>
    <?php endforeach; ?>
    </ul>
    

どちらの場合も emails データ配列が空の場合は入力フィールドは表示されません。

この簡単な例では、まだ新しいアドレスを追加することや既存のアドレスを削除することはできません。 新しくアドレスを追加するには allow_add オプション(および prototype オプション)を有効にしてください。 (続く例を見てください)。メールアドレスを emails 配列から削除するには allow_delete オプションを有効にしてください。

アイテムの追加と削除

もし allow_addtrue にセットされていれば、認識されていないアイテムが送信されたとき、 それらはシームレスにアイテム配列に追加されるでしょう。これは理論上はすばらしいですが、 実際上、クライアントサイドJavaScriptを正しくするにはもう少し手間がかかります。

上述の例に沿って続く例では、 emails データ配列に二つのメールアドレスがある状態で始めるとします。 その場合には、2つの入力のフィールドは(フォームの名前に応じて)次のようにレンダリングされます:

<input type="email" id="form_emails_0" name="form[emails][0]" value="foo@foo.com" />
<input type="email" id="form_emails_1" name="form[emails][1]" value="bar@bar.com" />

ユーザーが別のメールを追加できるようにするために、まず allow_addtrue に設定します。そして、 - JavaScript で - form[emails][2] という名前で追加のフィールド(必要であればさらに追加のフィールド)を動的にレンダリングします。

これを容易にするため、 prototype オプションを true にすることで”テンプレート” フィールドの表示を許可します。 それは JavaScript を利用して動的に新しいフィールドを作成するために利用できます。 表示されたプロトタイプフィールドは次のようになります:

<input type="email" id="form_emails___name__" name="form[emails][__name__]" value="" />

__name__ をいくつかの固有の値で置き換えることで (例えば 2 )、 フォームに新しいHTMLフィールドを構築、挿入することができます。

jQueryを使用した簡単な例は次のようになります。フィールドのコレクションを一度にすべて表示するなら(例えば form_row(form.emails) )、
data-prototype 属性は自動的に表示されるためより簡単です(多少の違いについては続きのnoteを参照のこと)。

これまで説明したことをすべて記述した JavaScript コードは、次のようになります:

  • Twig
    {{ form_start(form) }}
        {# ... #}
    
        {# data-prototype 属性にプロトタイプを保存してください #}
        <ul id="email-fields-list" data-prototype="{{ form_widget(form.emails.vars.prototype) | e }}">
        {% for emailField in form.emails %}
            <li>
                {{ form_errors(emailField) }}
                {{ form_widget(emailField) }}
            </li>
        {% endfor %}
        </ul>
    
        <a href="#" id="add-another-email">Add another email</a>
    
        {# ... #}
    {{ form_end(form) }}
    
    <script type="text/javascript">
        // どれだけのメールフィールドが表示したかを追跡しつづけてください。
        var emailCount = '{{ form.emails | length }}';
    
        jQuery(document).ready(function() {
            jQuery('#add-another-email').click(function() {
                var emailList = jQuery('#email-fields-list');
    
                // prototype template を取得してください
                var newWidget = emailList.attr('data-prototype');
                // id と プロトタイプの名前で使われる "__name__" をメールアドレスに対して固有の数字で置き換えてください。
                // 最後の name 属性は name="contact[emails][2]" のようになります
                newWidget = newWidget.replace(/__name__/g, emailCount);
                emailCount++;
    
                // 新規リスト要素を作成し、リストに追加してください。
                var newLi = jQuery('<li></li>').html(newWidget);
                newLi.appendTo(jQuery('#email-fields-list'));
    
                return false;
            });
        })
    </script>
    

Tip

一度にコレクション全体を表示している場合、コレクションを囲んでいる要素(例えば div または table)の data-prototype 属性にあるプロトタイプは自動的に利用可能です。 唯一の違いは、 “form row” 全体はあなたのために表示します。それは上記でなされたように任意のコンテナ要素でラップする必要が無いことを意味します。

フィールドオプション

type

データ型: string または FormTypeInterface 必須

これはこのコレクションの中のそれぞれのアイテムのフィールドタイプです(たとえば text, choice など)。 たとえば、メールアドレスの配列を持っていた場合、あなたは email タイプを使うでしょう。 もし、その他のフォームのコレクションを組み込みたいとき、新しいフォームタイプのインスタンスを生成し、このオプションに渡してください。

options

データ型: array デフォルト: array()

これは、 type オプションで特定されたフォームタイプに渡された配列です。 たとえば、 choice オプションを type オプションとして 使用した場合(たとえば、ドロップダウンメニューなど)、少なくても選択肢の基になる choices オプションを 指定する必要があります:

$builder->add('favorite_cities', 'collection', array(
    'type'   => 'choice',
    'options'  => array(
        'choices'  => array(
            'nashville' => 'Nashville',
            'paris'     => 'Paris',
            'berlin'    => 'Berlin',
            'london'    => 'London',
        ),
    ),
));

allow_add

データ型: Boolean デフォルト: false

もし true にセットした場合、認識していないアイテムがコレクションに送信された場合、新しいアイテムとして追加されます。 送信されたデータの中で、配列の末尾には新しく生成されたアイテムと同じように既存のアイテムを含みます。 より詳細については上述の例を参照してください。

prototype オプションはプロトタイプアイテムを表示するのに使うことができます。 それらは - JavaScriptと一緒に - 新しいフォームアイテムをクライアントサイドで動的に生成するのに使うことができます。 詳細は上述の例とあわせて “prototype” として tag を”new” させる を参照してください。

Caution

もし他のフォーム全体をデータベースの1対多の関連を反映して埋め込もうとする場合、 新しいオブジェクトの外部キーが正しくセットされたか手動で確認する必要があるでしょう。 Doctrineを使っている場合、これは自動的にはされません。詳細は上述のリンクを参照してください。

allow_delete

データ型: Boolean デフォルト: false

もし true にセットした場合で既存のアイテムが送信データに含まれていない場合、それはアイテム配列の最後から正しく欠落します。 これは、JavaScript 経由でフォーム要素を DOM から単純に取り除く “delete” ボタンを継承することができることを意味します。 ユーザーがフォームを送信したとき、その送信されたデータからの欠落は、それが最後の配列から削除されたことを意味します。

詳細は tag を削除させる を参照してください。

Caution

オブジェクトのコレクションを埋め込んでいるとき、このオプションを使うときは気をつけてください。 この場合、いくつかの組み込まれたフォームが削除されれば、それらはオブジェクト配列の末尾から正しく消える でしょう 。 しかし、あなたのアプリケーションのロジックしだいでは、オブジェクトが削除されたとき、そのオブジェクトまたは外部キー参照先のメインオブジェクトを削除したいと思うでしょう。。 これは自動的には取り扱われません。詳細は「 tag を削除させる 」を参照してください。

prototype

データ型: Boolean デフォルト: true

このオプションは allow_add オプションを使うときに便利です。もし true (且つ allow_addtrue )の場合、 特別な “prototype” 属性が利用可能になります。それは、新しい要素としてページに見えるべき”テンプレート”の例を表示できます。 この要素に与えられた name 属性は __name__ です。これはJavaScript 経由でプロトタイプを読み込み、 __name__ を固有の名前又は数字に置き換え、フォーム中に表示する “add another” ボタンを追加することを許可します。 送信されたときに allow_add オプションの基となる配列にそれは追加されます。

プロトタイプフィールドはコレクションフィールドの中の prototype 変数を経て表示されることができます:

  • Twig
    {{ form_row(form.emails.vars.prototype) }}
    
  • PHP
    <?php echo $view['form']->row($form['emails']->vars['prototype']) ?>
    

ここで留意すべきは、あなたが本当に必要なのは “widget” ですが、どのようにフォームを表示するか次第では、全体を持っている “form row” の方がより簡単かもしれないことです。

Tip

コレクションフィールド全体を一度で表示する場合、プロトタイプの form row はコレクションを囲む( div または table )要素の中の data-prototype 属性で自動的に利用可能です。

このオプションを実際にどのように利用するかより詳しくは上述の例だけではなく「 “prototype” として tag を”new” させる 」をご覧ください。

prototype_name

データ型: String デフォルト: __name__

いくつかのコレクションをフォームの中で持つ場合、またはひどくネストしたコレクションを持つ場合、 関係のないプレースホルダは同じ値に置き換えられないためプレースホルダを変えたいと思うかもしれません。

継承したオプション

以下のオプションは form タイプを継承しています。 すべてのオプションはここにリストしてはおらず、このタイプにもっとも当てはまるもののみです:

label

データ型: string デフォルト: フィールド名から推測されたものです。

フィールドがレンダリングされる際にラベルが設定されます。false が設定されるとラベルは表示されません。 ラベルはテンプレート内部で設定することもできます。

{{ render_label(form.name, 'Your name') }}

mapped

データ型: boolean

オブジェクトを読み込んでいるまたは書き込んでいる間、フィールドが無視されるようにしたい場合は、 mapped オプションを false にしてください。

error_mapping

データ型: array デフォルト: empty

このオプションはバリデーションエラーの対象を編集することができます。

matchingCityAndZipCode という名前のメソッドを持っているとして、それが city および zip code が一致するかの検証をするとします。しかし残念なことに、 “matchingCityAndZipCode” フィールドがフォームに無いため、 Symfony ができるのはフォームの上部にエラーを表示することです。

カスタマイズされたエラーマッピングを使うと、city フィールドの上にエラーを表示するように、より上手にエラーをマップできます。:

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'error_mapping' => array(
            'matchingCityAndZipCode' => 'city',
        ),
    ));
}

こちらが左側、右側のマッピングするルールです:

  • 左側はプロパティパスを有します。
  • クラスのプロパティまたはメソッドで違反が生成された場合、そのパスは単に “propertyName” です。
  • array または ArrayAccess オブジェクトで違反が生成された場合、プロパティパスは [indexName] です。
  • ドットでプロパティを分離し、それらを連結して、ネストされたプロパティパスを作成することができます。たとえば addresses[work].matchingCityAndZipCode のように。
  • 左側のエラーマッピングは単一のドット . も認められます。それはフィールド自体をさしています。フィールドに追加されたエラーはネストされたフィールドの代わりに付与されたことを意味します。
  • 右側は単にフォームのフィールド名を有します。

error_bubbling

データ型: Boolean デフォルト: true

true の場合、このフィールドのエラーは親フィールドまたはフォームに渡されます。 たとえば、通常のフィールドを true に設定した場合、フィールドに対するエラーは 特定のフィールドではなくメインのフォームに付加されます。

by_reference

データ型type: Boolean デフォルト: true

下層にあるオブジェクトに name フィールドを持つとして、ほとんどの場合、setName が呼ばれることを期待します。 しかし、場合によっては setName が呼ばれ ない ことがあります。by_reference をセットすることですべての場合にセッターが呼ばれることを確実にします。

さらに説明するため、簡単な例がこちらです。:

$builder = $this->createFormBuilder($article);
$builder
    ->add('title', 'text')
    ->add(
        $builder->create('author', 'form', array('by_reference' => ?))
            ->add('name', 'text')
            ->add('email', 'email')
    )

by_referencetrue の場合、フォームの submit (または handleRequest )が呼ばれたとき、次のように裏側では処理されます。:

$article->setTitle('...');
$article->getAuthor()->setName('...');
$article->getAuthor()->setEmail('...');

setAuthor が呼び出されないことに注意して下さい。その author はリファレンスにより変更されます。

by_referencefalse の場合、送信時の処理はこのようになります。:

$article->setTitle('...');
$author = $article->getAuthor();
$author->setName('...');
$author->setEmail('...');
$article->setAuthor($author);

このように by_reference=false が実際にすることは、親オブジェクトでセッターを呼ぶことをフレームワークに強制することです。

同様に、下層にあるコレクションに collection フォームタイプを利用している場合、データは( Doctrine の ArrayCollection のように)オブジェクトです。そして、(例えば setAuthors のように)セッターが呼ばれる必要があるときは、by_referencefalse に設定されるべきです。

empty_data

データ型: mixed デフォルト: multiple 又は expanded の場合 array() それ以外 ''

このオプションは empty_value の選択肢が選ばれた時に、どのような値を返すかを決定します。

このオプションのデフォルト値はフィールドオプションによって異なります。:

  • data_class が設定され requiredtrue の場合、 new $data_class();
  • data_class が設定され requiredfalse の場合、 null;
  • data_class が設定されず compoundtrue の場合、 array();
  • data_class が設定されず compoundfalse の場合、 null.

しかし、必要に応じてこれを変更することができます。例えば、値が選択されていないとき gender フィールドを明示的に null に設定したいとすると、このようにできます。:

$builder->add('gender', 'choice', array(
    'choices' => array(
        'm' => 'Male',
        'f' => 'Female'
    ),
    'required'    => false,
    'empty_value' => 'Choose your gender',
    'empty_data'  => null
));

Note

フォームクラス全体に empty_data オプションをセットしたい場合はクックブックの記事( /cookbook/form/use_empty_data )を参照してください。

blog comments powered by Disqus