CakePHP
CakePHPDay 18

CakePHP2 Search PluginのpresetVarsとfilterArgsについて調べてみた

More than 3 years have passed since last update.

こんにちは @kaihiro です。

CakePHP歴2ヶ月の初心者ですがよろしくお願いします。
これまでは主にJavaでの開発をメインに行っていました。

会社で隣に座っている @k1LoW さんからCakePHPのAdvent Calendar書かないの?って脅されたので頑張ります。

CakeDC Search Plugin

今回、自分で CakeDC の Search Plugin を使用した検索機能を実装してみて、 presetVarsfilterArgs(特にpresetVars)が何を設定しているものなのか最初よく分からなかったので調べたことを書きたいと思います。

presetVars と filterArgs にポイントを絞ってるので、Search Pluginの使い方については他のサイトを参考にしてください。

filterArgs

まずは filterArgs から。

Modelに定義する filterArgs は、検索条件を設定するプロパティです。
検索用のパラメータが渡されたときにどのような検索を行うかを定義します。

class Post extends AppModel {
    public $actsAs = array('Search.Searchable');
    public $belongsTo = array('User');

    public $filterArgs = array(
        'user_id' => array(
            'type' => 'value'
        ),
        'keyword' => array(
            'type' => 'like',
            'field' => array(
                'User.username',
                'Post.body'
            )
        ),
    );

filterArgs は検索条件を設定する項目なので、何をやっているかはイメージしやすいと思います。
type にはlike, ilike, value, expression, subquery, queryを使用して、検索条件を指定することができます。

presetVars

次に presetVars です。

Controller に指定する presetVars は、検索パラメータを管理するための設定値です。
検索条件をURLのパラメータに保持するときのフォーマットや実際にSQLに渡す検索条件を構成する処理、検索後に検索フォームに検索条件を設定する処理に影響します。

せっかく filterArgs の設定をおこなっていても、presetVars が設定されていないと検索条件として使用してくれません。

Controller の例です。

class PostsController extends AppController {

    public $components = array('Paginator','Search.Prg');

    public $presetVars = array(
        'user_id' => array(
            'type' => 'value'
        ),
        'keyword' => array(
            'type' => 'value'
        )
    );

    public function index() {
        $this->Prg->commonProcess();

        $this->Paginator->settings['conditions'] = 
            $this->Post->parseCriteria($this->Prg->parsedParams());

        $this->set('posts', $this->Paginator->paginate());
    }

検索処理の流れ

上記のindexの処理を簡単に説明します。

$this->Prg->commonProcess()は検索条件データのハンドリングを行います。
検索条件がPOSTされると、そのデータを presetVars の定義にしたがって、検索条件を含んだURLを構成し、現在のactionにリダイレクトします。
リダイレクトにより再度、$this->Prg->commonProcess()がGETで呼ばれると、今度はURLに含まれる検索条件を解析して、その結果が parsedParams に設定されます。

あとはその parsedParams を $this->Post->parseCriteria() に渡すことで、Model の filterArgs に定義した内容にしたがってwhere条件が構成され、検索が行われます。

presetVarsのtype

presetVars の type には、value, checkbox, lookupを設定できます。
単一の入力項目に対しては value を使用します。
複数選択可能なチェックボックスの場合は checkbox を指定できます。

複数選択のチェックボックス入力の場合に type を value とすると、URLのパラメータが配列形式となります。

?user_id[0]=1&user_id[1]=4&keyword=hoge

type が checkbox の場合は、|(パイプ)で区切られます。

?user_id=1|4&keyword=hoge

例えば、上記の user_id の type が checkbox の場合に、あえて配列形式でURLパラメータを渡してみると、当然ながら検索条件が想定通りに使用されず、画面の検索フォームにも反映されません。

presetVarsには type の他にも encodeempty などのパラメータがあります。

presetVarsとfilterArgsの関連

検索条件として presetVars に定義する項目と、filterArgs に定義する項目は基本的に同じになるかと思います。
そこで以下のように記述することで presetVars の定義を省略することができます。

    public $presetVars = true;

この場合、presetVars は Controller にてメインで使用する Model の filterArgs の値を引き継ぎます。
type の値は presetVars と filterArgs で異なるため、presetVars の type として有効でないものは PrgComponentにて value に置き換えています。
ですから、presetVars の type に checkbox を指定したい場合は、presetVars を省略せずに明示的に指定する必要があります。

また公式ドキュメントには記載されていませんが、presetVars省略時、filterArgs に presetType を定義しておくと、その値を presetVars の type として使用してくれるようです。

    public $filterArgs = array(
        'user_id' => array(
            'type' => 'query',
            'method' => 'searchByUsers',
            'presetType' => 'checkbox' // presetVarsのtypeを指定
        ),
        'keyword' => array(
            'type' => 'like',
            'field' => array(
                'User.username',
                'Post.body'
            )
        ),
    );

Modelにまとめて定義してしまいたい方はこちらの方法もありかもしれません。

CakePHPを使ってみての感想

これまでJavaで開発してきた自分からすると、CakePHPでの開発はスピード感がずいぶん違うなぁと感じました。
Search Plugin のような便利なプラグインがたくさんあるのも魅力ですね。

CakePHP3についてもこれから触っていきたいと思います!