Formにcollection type ってのがあります。このprototypeについての説明
詳しくは コチラ(How to Embed a Collection of Forms)を見てもらえればよいのですが、簡単にここでもまとめておこうかと思います。
もうちょっとわかりやすく説明しますと、UserにSongがぶら下がるとしましょう。これはOneToManyでUserがすきな曲は複数もてます。 こんなとき、UserTypeのEmbedでSongTypeを埋め込みたいですよね。でも1つのUserに対してSongTypeのフィールドたちをいっぱいもたなくてはならない。それってどうすんの? => ここで使うのが CollectionTypeなわけです。
EntityでもOneToManyの場合、Doctrine\Common\Collections\Collection が使用されますが、このCollectionと同じことなのかな。このCollectionを扱うためのTypeがCollectionType的な。
その場合もCollection使うと思うんだけど、どうなのよ?
このために、prototypeがあるわけです。prototypeを使えばフォームの項目のHTML内容をプロトタイプとして持ってくれるので、あとはJavascriptでそれをベースにどんどん増やしてね☆ って話。
そもそも collection type ってなんなのか
まぁ、これは名前のままなんですが、typeの集合ですね。 例えば、「あなたの好きな曲はなんですか?」って項目に、TextType(テキストフィールド)が複数ぶら下がる場合を考えれば、 そのTextTypeを集めるのがCollectionTypeとなります。もうちょっとわかりやすく説明しますと、UserにSongがぶら下がるとしましょう。これはOneToManyでUserがすきな曲は複数もてます。 こんなとき、UserTypeのEmbedでSongTypeを埋め込みたいですよね。でも1つのUserに対してSongTypeのフィールドたちをいっぱいもたなくてはならない。それってどうすんの? => ここで使うのが CollectionTypeなわけです。
EntityでもOneToManyの場合、Doctrine\Common\Collections\Collection が使用されますが、このCollectionと同じことなのかな。このCollectionを扱うためのTypeがCollectionType的な。
動的に項目増やしたい場合ってあるよね?
Collectionはなんとなくわかった。ちょっと疑問なんだけど、一般的にSongが上図のように3つしかぶら下がらないとは限らないよね? サービスによっては、Javacript とかで項目を動的に追加したりしたい場合ってあるとおもう。その場合もCollection使うと思うんだけど、どうなのよ?
このために、prototypeがあるわけです。prototypeを使えばフォームの項目のHTML内容をプロトタイプとして持ってくれるので、あとはJavascriptでそれをベースにどんどん増やしてね☆ って話。
// src/Hoge/UserBundle/Form/Type/UserType.php // ... public function buildForm(FormBuilder $builder, array $options) { $builder->add('username'); $builder->add('songs', 'collection', array( 'type' => new SongType(), 'allow_add' => true, 'allow_delete' => true, 'by_reference' => false, 'prototype' => true, )); }以下のようにするとdata-prototype に、エスケープされたプロトタイプのHTMLが入ります
<ul class="songs" data-prototype="{{ form_widget(form.songs.get('prototype')) | e }}"> <li></li> </ul>で、javascriptで以下のように$$name$$を数字に置き換えれば、動的に追加できます。 例えば、ボタンのクリックイベントで addTagForm() を呼べばOK
$(function(){ var collectionHolder = $('ul.songs'); var addTagForm = function() { // Get the data-prototype we explained earlier var prototype = collectionHolder.attr('data-prototype'); // Replace '$$name$$' in the prototype's HTML to // instead be a number based on the current collection's length. var newForm = prototype.replace(/\$\$name\$\$/g, collectionHolder.children().length); collectionHolder.append('<li>'+newForm+'</li>'); }; });ざっくりだけど、こんなかんじです。