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>');
};
});
ざっくりだけど、こんなかんじです。


