CakePHP2のPaginatorを検索でも使えるように

方法を知らなかったので1日失ったよ…

Paginatorを使ってページングを実現しつつ、Cakeのアソシエーションを使って複数テーブルを結合させつつ、検索機能の実装をする必要があったしようと思ってた。
アソシエーションをいくつも使っていると、発行されるsqlは1回ではなくなるようで、そうすると深い階層のデータ検索を行った時の結果行数の値がおかしな事になってた、みたい…?

色々調べた結果、以下の方法に辿り着いたよ。時間掛かったよ。。


$this->paginate = array(
        //表示するフィールドの指定をする。'*'で全部。
	'fields' => '*' , 

        //JOIN するテーブルの設定。
	'joins' => array(
	             array(
			'type' => 'LEFT',
			'alias' => 'Tag',
			'table' => 'tags',
			'conditions' => array('Tag.id = Book.tag_id')
		      )
        )

	'conditions' => array(
                          'Book.name' => 'ABCD'
                        )
);

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

フォームを使って絞込検索条件を指定しつつ、条件ごとにsqlを変えられるようにしてみた。

$joins = array();
$cond = array();

if ($this->request->is('post')) {

/*
  フォームからの値。(例)
  $this->data['category_name'] = 'マンガ';
*/
	if(!empty($this->data['category_name'])){

              //category名の指定があったら、categoryテーブルをJOINする
               $join = array(
        	 'type' => 'LEFT',
	         'alias' => 'Category',
	         'table' => 'categories',
        	 'conditions' => array('Category.id = Book.category_id')
                );
                
                //$joins配列にプッシュ
                array_push($joins,$join);
                
               //検索条件を追加
		$cond['Category.name'] = $this->data['category_name'];
	}


/*
   フォームからの値。チェックボックスとか。(例)
   $this->data['tag_ids'] = array(2,5,14,11);
*/
	if(!empty($this->data['tag_ids'])){

              //tag_idの指定があったら、tagテーブルをJOINする
               $join = array(
        	 'type' => 'LEFT',
	         'alias' => 'Tag',
	         'table' => 'tags',
	         'conditions' => array('Book.tag_id = Tag.id')
                );
                
                //$joins配列にプッシュ
                array_push($joins,$join);
                
               //検索条件を追加
		$cond['Tag.id'] = $this->data['tag_ids'];
	}


        //条件を設定
       $this->paginate = array(
             'fields' => '*' , 
	     'joins' =>	$joins,
	     'conditions' => $cond
       );
	
	$this->set('books',$this->Paginator->paginate());

}          

こんな感じで。
ただ、これだけだとページングした時に検索条件が引き回されないので、getのパラメータを使うとか、sessionを使うとかしないといけないです。