AdminGeneratorで生成した一覧画面のフィルタでプルダウンを使う

AdminGeneratorで管理画面を生成すると、スキーマで外部キーを定義しているフィールドは自動的にプルダウンが生成されますが、特にマスターテーブルを用意しないようなコード値を持つフィールドは、「テキスト入力+is empty」入力欄が生成されてしまいます。

この入力欄にコード値を入力して絞り込むことも出来ますが、やはり画面上では意味のあるコード名を使用したプルダウンやチェックボックスを使用したいところです。

そこで、フィルタに対応するフォームでウィジェットを変更します。


たとえば、「disp_flag(数値)」=0または1 というフィールドがあるとします。

自動生成されているfilter用フォームクラスでは、次のようなウィジェット/バリデータが定義されています。

<?php
// /lib/filter/base/Base〜FormFilter.php

//ウィジェットの定義部分
'disp_flag'          => new sfWidgetFormFilterInput(),

//バリデータの定義部分
'disp_flag'          => new sfValidatorSchemaFilter('text', new sfValidatorInteger(array('required' => false))),
 :

このウィジェットとバリデータを派生クラスのconfigureメソッド内で上書きします。

<?php
// /lib/filter/〜FormFilter.php

//ウィジェットを書き換え
$this->widgetSchema[ 'disp_flag' ] =
  new sfWidgetFormChoice( array( 'choices'=>array( ''=>'', 0=>'0 (非表示)', 1=>'1 (表示)' ) ) );

//バリデータを書き換え
$this->validatorSchema[ 'disp_flag' ] = new sfValidatorPass();

※バリデータをsfValidatorPassにしているのは、以前の記事のsvValidatorIntegerの問題を回避するためですが、必要に応じてregexなどのルールを設定するのが望ましいです。


で、このように書き換えるとそのままではフィルタフォームをsubmitしても上手く動作しません。
これは、生成された時点で利用されているFilter系のウィジェットの場合、入力された値をtext、is_emptyという2つのキーを持つ連想配列として保持するようになっているからです。
(フィルタ関連のクラスが、これらのウィジェットを前提とした作りになっているようです)

そこで、定義しなおしたウィジェットからの入力値の形式を、submitされた時点で補正します。

このような処理を記述するには、AdminGeneratorで生成したactionクラスで、フィルタ時のメソッドをオーバーライドします。

※cacheディレクトリ内に生成されている該当クラスの中からコピペしてきます。

<?php
// /cache/backend/dev/modules/autoモジュール名/actions/actions.class.php
// 使用しているmodelクラスによって@の部分が変わるので注意してください。

  public function executeFilter(sfWebRequest $request)
  {
    $this->setPage(1);

    if ($request->hasParameter('_reset'))
    {
      $this->setFilters($this->configuration->getFilterDefaults());

      $this->redirect('@page');
    }

    $this->filters = $this->configuration->getFilterForm($this->getFilters());

    $this->filters->bind($request->getParameter($this->filters->getName()));
    if ($this->filters->isValid())
    {
      $this->setFilters($this->filters->getValues());

      $this->redirect('@page');
    }

    $this->pager = $this->getPager();
    $this->sort = $this->getSort();

    $this->setTemplate('index');
  }

上のようなexecuteFilterメソッドが定義されているので、これをコピーしてapp内のactionクラス(当初はメソッドは空)にペーストします。
※cache内のファイルを書き換えても意味がないことに注意してくださいw

そしてこの中でパラメータを処理している部分(bindメソッドを呼び出しているところ)で、半ば無理やりではありますが、以下のようにdisp_flagパラメータを補正してやります。

<?php
// /app/backend/modules/モジュール名/actions/actions.class.php
    $param = $request->getParameter($this->filters->getName());
    $param['disp_flag'] = array( 'text'=>$param['disp_flag'], 'is_empty'=>false );
    $this->filters->bind($param);

これで、自分で定義したプルダウンにてフィルタが機能するようになります。


※もっとスマートな方法がありそうですが・・・。ご存知の方教えてください。


※こういったコード値も、すべてマスターテーブルとして用意するのがsymfony(Rails)流なのかもしれませんね。


[2010/01/13追記]