symfonyのAdminGeneratorで生成するフォームのカスタマイズでハマった点
symfonyにはschema.ymlで定義したテーブルに対するCRUD関連の画面を一気に生成するAdminGeneratorという機能があり、単純なメンテナンス画面であれば、ほぼこれだけで作れてしまいます。
AdminGeneratorで生成した画面も、がんばればカスタマイズできますが、今回はそのカスタマイズでハマった点を紹介します。
# もしかすると、私が知らなかっただけで常識なのかもしれませんが・・・・。
対象となるテーブル
以下のようなスキーマを定義したとします。
propel: login_data: id: created_at: updated_at: last_name: type: varchar size: 32 required: true first_name: type: varchar size: 32 required: true email: type: varchar size: 128 required: true
graphvizで生成したモデル図はこんな感じです。
AdminGeneratorでCRUD生成
テーブルの準備ができたら、次のsymfonyコマンドで早速AdminGeneratorを実行します。
./symfony propel:generate-admin frontend LoginData --module=ManageLoginData
これで、login_dataテーブルに対する一覧・検索画面、新規追加画面、編集画面、および削除機能が生成されます。
初期状態で入力フォームは以下のようになっています。
フォームの項目をカスタマイズ
デフォルトではすべてのフィールドが表示されますが、created_atやupdated_atなどは除外したいですよね。
そこで、generator.ymlに表示するフィールドだけを指定します。
form: ~
↓
form: display: [last_name, first_name, email]
これで、表示フィールドが3つになります。
次に、少し欲張って「性と名は1行に表示したい」ということで、2つのフィールドを1つにまとめてみます。いくつかやり方はあるでしょうけれど、ここではAdminGeneratorの「バーチャルカラム」の機能を使って、2つの入力フィールドを1つにまとめたパーシャルを定義します。
「_names」というパーシャルを作成します。
/templates/_names.php
<?php ?> <div class="sf_admin_form_row sf_admin_text sf_admin_form_field_name<?php if ( $form['last_name']->hasError() || $form['first_name']->hasError() ) { print ' errors'; }?>"> <?php echo $form['last_name']->renderError() ?> <?php echo $form['first_name']->renderError() ?> <div> <label for="login_data_last_namel">氏名</label> <?php echo $form['last_name']->render($attributes instanceof sfOutputEscaper ? $attributes->getRawValue() : $attributes) ?> <?php echo $form['first_name']->render($attributes instanceof sfOutputEscaper ? $attributes->getRawValue() : $attributes) ?> </div> </div>
これは、AdminGeneratorで生成されるパーツを1つのパーシャルにまとめただけです。
※パーツは、/cache/frontend/dev/modules/autoManageLogin/templates というようなディレクトリに生成されます。
パーシャルを使用するようにgenerator.ymlを書き換えます。
※パーシャルは先頭に「_」を付けるルールです。
form: display: [_names, email]
さて、これで実行してみると・・・・・
例外が発生してしまいます。「last_name」というフィールドがない、と言われていますね・・・。
実は、symfonyの少し前のバージョンではこれで正常に実行できていたのですが、2009年4月のセキュリティフィックスにより、このようにエラーが発生するように変更されたようです。
どういう事かというと、このフォームをレンダリングする際に_names.phpパーシャル内で「last_name」や「first_name」というウィジェットを参照していますが、それらはgenerator.ymlで使用するように設定されていないため、自動的に無効化されているのです。
対処法
この制限の対処法ですが、以下のようにダミーのバーチャルカラムを用意することで「そのフィールドが使われている」とAdminGeneratorに認識させることで例外を回避してみました。
form: display: [_names, email, _first_name, _last_name]
※first_name、last_nameの前に「_」がついている点に注意。
この設定と合わせて、/templatesフォルダに「_first_name.php」「_last_name.php」という空のファイルも作成しておきます。
これで無事、以下のようにフォームが表示されます。
まとめ
- AdminGeneratorのフォームで使用するウィジェット(フィールド)は、リアル名(先頭に_なし)またはバーチャルカラム(先頭に_または~あり)としてgenerator.ymlのdisplayに設定する必要がある
- 1つのフィールドの表示をカスタマイズしたいだけなら、フィールド名の前に「_」を付けたバーチャルカラムを作成する。(色気を出して変わった名前にしない)
- 複数のフィールドをまとめたバーチャルカラム(パーシャル)を作成する場合は、使用するフィールド用のダミーのバーチャルカラムも定義する
なんだかなぁ・・・・。