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で生成したモデル図はこんな感じです。


er2

AdminGeneratorでCRUD生成

テーブルの準備ができたら、次のsymfonyコマンドで早速AdminGeneratorを実行します。

./symfony propel:generate-admin frontend LoginData --module=ManageLoginData

これで、login_dataテーブルに対する一覧・検索画面、新規追加画面、編集画面、および削除機能が生成されます。

初期状態で入力フォームは以下のようになっています。


admingenerator1

フォームの項目をカスタマイズ

デフォルトではすべてのフィールドが表示されますが、created_atやupdated_atなどは除外したいですよね。
そこで、generator.ymlに表示するフィールドだけを指定します。

      form: ~

 ↓

      form:
        display:     [last_name, first_name, email]

これで、表示フィールドが3つになります。


admingenerator2


次に、少し欲張って「性と名は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]

さて、これで実行してみると・・・・・


admingenerator3

例外が発生してしまいます。「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」という空のファイルも作成しておきます。

これで無事、以下のようにフォームが表示されます。


admingenerator4

まとめ

  • AdminGeneratorのフォームで使用するウィジェット(フィールド)は、リアル名(先頭に_なし)またはバーチャルカラム(先頭に_または~あり)としてgenerator.ymlのdisplayに設定する必要がある
  • 1つのフィールドの表示をカスタマイズしたいだけなら、フィールド名の前に「_」を付けたバーチャルカラムを作成する。(色気を出して変わった名前にしない)
  • 複数のフィールドをまとめたバーチャルカラム(パーシャル)を作成する場合は、使用するフィールド用のダミーのバーチャルカラムも定義する


なんだかなぁ・・・・。