sfFormのレンダリングにカスタムフォーマッタを使用する
symfonyのフォームライブラリsfFormを使ってフォームを表示する場合、フォームの各要素はデフォルトではテーブルの行として以下のようなHTMLタグで出力されます。
<tr> <th><label for="login_login_name">Login name</label></th> <td><input type="text" name="login[login_name]" id="login_login_name" /></td> </tr>
フォーマッタは、デフォルトの「table」以外に「list」も用意されています。
(これらはそれぞれ、sfWidgetFormSchemaFormatterTableとsfWidgetFormSchemaFormatterListに対応します)
フォーマットをlistに変更するには、フォームの設定を行っている部分で以下のようにします。
<?php class LoginForm extends sfForm { public function setup() { : $this->widgetSchema->setDefaultFormFormatterName('list'); :
こうすると、次のようなHTMLタグで出力されます。
<li> <label for="login_login_name">Login name</label> <input type="text" name="login[login_name]" id="login_login_name" /> </li>
出力されるタグのカスタマイズ
さて、出力されるタグを、独自クラスを指定したdivタグに変更する場合はどうするのでしょうか。
公式のドキュメント(Forms in Action)では、「テンプレートのカスタマイズ」のやり方しか書かれていません。
この方法ではテンプレートに直接フォーム要素を埋め込んでいくので、デザインに対しては柔軟になるのですが、フォーム要素を追加したり変更したりする場合にはテンプレートも合わせて修正しなくてはならないので、開発効率はかなり低下します。
フォーマッタの出力とテンプレートのカスタマイズの中間くらいのことをやりたいですよね。
そこで、sfWidgetFormSchemaFormatterListクラスを真似た、myWidgetFormSchemaFormatterDivクラスを次のように作成します。
<?php class myWidgetFormSchemaFormatterDiv extends sfWidgetFormSchemaFormatter { protected $rowFormat = "<div class=\"formrow\">%error%%label%%field%%help%%hidden_fields%</div>\n", $errorRowFormat = "<div class=\"error\">%errors%</div>\n", $helpFormat = '<div class="help">%help%</div>', $decoratorFormat = "<div class=\"formcontent\">\n%content%\n</div>\n"; }
このフォーマッタを使用するために、formクラスのsetupメソッドで、次のようにフォーマッタを追加してデフォルトに設定します。
<?php class LoginForm extends sfForm { public function setup() { : $this->widgetSchema->addFormFormatter('div', new myWidgetFormSchemaFormatterDiv($this->widgetSchema)); $this->widgetSchema->setDefaultFormFormatterName('div'); :
こうすると、myWidgetFormSchemaFormatterDivクラスのフォーマット設定でフォームがレンダリングされます。
<div class="formrow"><label for="login_login_name">Login name</label> <input type="text" name="login[login_name]" id="login_login_name" /></div>
sfWidgetFormSchema::setFormFormatterNameを使用する場合の注意
上のサンプルコードではsetDefaultFormFormatterNameメソッドでフォーマッタを変更しましたが、同じような機能を持つsetFormFormatterNameメソッドがあります。
この2つの違いは、クラスのスタティック変数としてフォーマッタ名を保存するか、インスタンスのメンバ変数として保存するかです。1つの画面で複数のフォームオブジェクトを使用し、それぞれで別のフォーマッタを利用したい場合は、setFormFormatterNameを使用するということですね。