2012年5月6日日曜日

Form CollectionType ~ prototype

Formにcollection type ってのがあります。このprototypeについての説明 詳しくは コチラ(How to Embed a Collection of Forms)を見てもらえればよいのですが、簡単にここでもまとめておこうかと思います。

そもそも 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>');
    };

});
ざっくりだけど、こんなかんじです。

2012年5月2日水曜日

Formのwidget個々のカスタマイズ

Formのwidgetには、choice, time, number ..... のように、いくつか用意されています。 詳しくは コチラ (symfony日本語ドキュメント) で, templateで出力する際は
{{ form_widget(form.fieldname) }} 
みたいにやります。 そうすると、
みたいな感じで表示されます。 ですが、
みたく、縦並びにしたいとかって、レイアウトをwidgetごとに変更したいときってありますよね。 そんなときは、
{% form_theme form _self %}
{% block _[formtype名]_[フィールド名]_widget %}
{% spaceless %}
    <div {{ block('widget_container_attributes') }}>
    {% for child in form %}
     <div> {# 追加!!!!!! #}
            {{ form_widget(child) }}
            {{ form_label(child) }}
     </div> {# 追加!!!!!! #}
    {% endfor %}
    </div>
{% endspaceless %}
{% endblock _recallItem_is_new_widget %}
みたいな感じで、テンプレートをカスタマイズできます。 これは、テンプレートのデフォルトのテーマをカスタマイズって形をとっていて、その元となるテンプレートは vendor/symfony/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig にありますので、これを見ながらカスタマイズすればOK.

Share

Twitter Delicious Facebook Digg Stumbleupon Favorites More