paginator.php -> 検索条件の引継ぎ(GET)

Posted by muchag | CakePHP | 2011-05-29 (日) 15:10:27

paginator は便利なんだけど
検索条件は引き継げない。

そこで、検索条件を引き継いで paginator を利用する手法。
今回は、GET 送信にて条件を引き回す手法。

【環境】
[CakePHP] 1.3.8

なぜ GET 送信を選んだかというと
paginator では、ページ番号リンクやソート用リンクでは
条件を URL に名前付き引数として付記する手法が用いられているため
GET 送信にすれば、全部まとめて処理できると考えた。
 

経過分析

コントローラ内の処理では

  • 検索フォームから入力があった時
  • paginator からのページ遷移時
    • ページ番号もしくは「前へ」等の場合
    • ソートの場合

のように場合に分けて考えないといけない。
 

検索条件の取得
大前提
  • フォームの GET 送信は、URL に引数が付記される
    • CakePHP では、GET 送信時 $this->params[‘url’] に引数が格納される
  • paginator が作成するリンクは名前付き引数である
    • paginator が自動作成する引数は $this->passedArgs に格納される

上記より、検索条件は

  • $this->params[‘url’]
  • $this->passedArgs

のいずれかをチェックすればよいことになる。
 

具体例
list.ctp
  1. echo $form->create('User', array('type'=>'get'));
  2.  
  3. //「名前」で検索するテキストボックス
  4. echo $form->input('name');
  5.  
  6. echo $form->end('抽出');
  7.  
  8. /* リスト出力 */

今、上記のようなビューが存在するとする。
 

検索条件の設定

この場合、下記のようにすることで
フォームからもリンクからも条件を取得し
paginator に条件を引き渡すことができる。

users_controller.php
  1. // フォームからの送信があった場合
  2. if ( !empty($this->params['url']['data']['User']['name']) ) {
  3.     $this->paginate['conditions']['User.name LIKE'] = '%'.$this->params['url']['data']['User']['name'].'%';
  4. }
  5. // patinator が作成したリンクからきた場合
  6. elseif ( !empty($this->passedArgs['name']) ) {
  7.     $this->paginate['conditions']['User.name LIKE'] = '%'.$this->passedArgs['name'].'%';
  8. }

参考元サイトを初め、いくつか見たサイトでは6行目を if としていたが
今のところ elseif で問題はない。
 

サニタイズ

ユーザが指定する検索文言は、もちろんエスケープ処理をしないといけないので
サニタイズをかます。

ここで書くと面倒なので、完成例参照。
 

検索条件の引き継ぎ
$this->passedArgs

後述するが、$this->passedArgs はビューでも利用するので
フォームからのページ遷移でも $this->passedArgs の設定が必要。

そこで、上記例にその設定を差し込む。

users_controller.php
  1. // フォームからの送信があった場合
  2. if ( !empty($this->params['url']['data']['User']['name']) ) {
  3.     $this->paginate['conditions']['User.name LIKE'] = '%'.$this->params['url']['data']['User']['name'].'%';
  4.     $this->passedArgs['name'] = $this->params['url']['data']['User']['name'];
  5. }

4行目を追加。

参考元サイトを初め、多くのサイトで4行目を

  1. urlencode($this->passedArgs['name'] = $this->params['url']['data']['User']['name']);

としていたが、ここで urlencode を実行すると
paginator の WHERE 句のパラメータが、エンコードされた文字列になってしまうため
データ抽出が上手く作動しなかった。
 

テキストボックス

検索文言をテキストボックスに配置。

array(‘url’=>$this->passedArgs) に引き継いだ情報が入っているので

  1. echo $formEx->input('code', array('default'=>$this->passedArgs['name']) );

としてやればよさそうなものだが、
これをすると、検索文言がセットされていないときに

Notice (8): Undefined index: name

となってしまう。

そこで、予め変数を用意して初期化し代入することで
この Notice を回避できる。

list.ctp
  1. // 変数を作成し初期化
  2. $name = '';
  3.  
  4. // 引き継ぎ変数から情報を取得
  5. extract($this->passedArgs);
  6.  
  7. // 検索用テキストボックスを初期値を設定して配置
  8. echo $form->input('code', array('default'=>$name) );

 

urlencode

引き継いだ検索条件は、再び URL 付記の形で受け継がれていくので
検索文言を urlencode しておく。

list.ctp
  1. foreach ($this->passedArgs as $key => $val) {
  2.     $this->passedArgs[$key] = urlencode($val);
  3. }

 

ページ番号リンク

検索条件のページ番号リンクへの引き継ぎは、ビューの先頭で

list.ctp
  1. $paginator->options( array('url' => $this->passedArgs) );

としてやることで実現する。
 

ソートリンク

paginator は、ソート用のリンクを sort メソッドにて自動作成してくれるが
そこへ更に array(‘url’=>$this->passedArgs) を付加することで
検索条件をもリンクへ自動付記してくれる。

list.ctp
  1. echo $paginator->sort('▲▼', 'name', array('url'=>$this->passedArgs) );

としてやることで実現する。
 

完成例

上述の基本以外に、サニタイズ処理をし
1ページ当たりの表示行数を設定するドロップダウンを追加してある。

users_controller.php
  1. App::import('Sanitize');
  2. class UsersController extends AppController {
  3.  
  4.     function list()
  5.     {
  6.         // 1ページ当たりの表示行数情報の取得&設定
  7.         if ( !empty($this->params['url']['limit']) ) {
  8.             $this->paginate['limit'] = $this->params['url']['limit'];
  9.             $this->passedArgs['limit'] = $this->params['url']['limit'];
  10.         }
  11.         elseif ( !empty($this->passedArgs['limit']) ) {
  12.             $this->paginate['limit'] = $this->paginate['limit'];
  13.         }
  14.         $this->set('limit', $this->paginate['limit']);
  15.  
  16.         // 1ページ当たりの表示行数ドロップダウンのリスト
  17.         $options = array(20 => '20', 50 => '50', 100 => '100');
  18.         $this->set('options', $options);
  19.  
  20.         //「名前」フィールドでの検索文言取得&設定
  21.         if ( !empty($this->params['url']['data']['User']['name']) ) {
  22.             Sanitize::clean($this->params['url']['data']['User']['name']);
  23.             $this->paginate['conditions']['User.name LIKE'] = '%'.$this->params['url']['data']['User']['name'].'%';
  24.             $this->passedArgs['name'] = $this->params['url']['data']['User']['name'];
  25.         }
  26.         elseif (!empty($this->passedArgs['name']) ) {
  27.             $this->paginate['conditions']['User.name LIKE'] = '%'.$this->passedArgs['name'].'%';
  28.         }
  29.         $this->set('users', $this->paginate('User') );
  30.     }
  31. }

 

list.ctp
  1. // 変数を作成し初期化
  2. $name = '';
  3.  
  4. // 引き継ぎ変数から情報を取得
  5. extract($this->passedArgs);
  6.  
  7. // 検索用テキストボックスを初期値を設定して配置
  8. echo $form->input('code', array('default'=>$name) );
  9.  
  10. // 引き継ぎ検索条件を urlencode
  11. foreach ($this->passedArgs as $key => $val) {
  12.     $this->passedArgs[$key] = urlencode($val);
  13. }
  14.  
  15. // paginator に検索条件を引き継ぎ
  16. $paginator->options( array('url' => $this->passedArgs) );
  17.  
  18. echo $form->create('User', array('type'=>'get'));
  19.  
  20. // 1ページ当たりに表示する行数(件数)ドロップダウン
  21. echo $form->select('limit', $options, $limit);
  22.  
  23. //「名前」で検索するテキストボックスを初期値を設定して配置
  24. echo $form->input('code', array('default'=>$name) );
  25.  
  26. echo $form->end('抽出');
  27.  
  28. // ソートリンク設置
  29. echo $paginator->sort('▲▼', 'name', array('url'=>$this->passedArgs) );
  30.  
  31. // ページャーリンク設置
  32. echo $paginator->prev('前へ');
  33. echo $paginator->numbers();
  34. echo $paginator->next('後へ');
  35.  
  36. /* リスト出力 */

 

最後に

今回の設定では検索対象を「名前」フィールドとしたが
テキストボックスをフィールド毎に複数設置すれば
それぞれのフィールドに検索文言を設定でき
AND 検索となる。

ただし、1つのフィールド内でのスペース区切り AND 検索には対応していない。
これは今後の課題。
 

参考元サイト

WebTecNote:Pagination + Search ページ遷移時に検索条件を維持させる
でじうぃき:CakePHP Paginate Sort の使い方
きままな日記帳:CakePHPで名前付きパラメータを受け取る

もしかして、とってもシンプルな手法を見つけたかも・・・。
futuremix:CakePHP の Paginator に独自にパラメータを追加する
今度時間があるときに試してみよう。

CakePHP | 2011-05-29 (日) 15:10:27 |

コメントはまだありません »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment