初めての[CakePHP2.x]での開発、そして挫折するまで日記~その27 検索結果をページネーションで表示させる

CakePHP

CakePHP

前回CakePHPで検索ページを作って

データを表示させました。

しかし、データ量が多くなると

検索結果が多くなり

さらに、SQLの処理も遅くなってしまうため

Limitを付けて検索させたいと思いました。

なら、簡単にページネーションまで作ってくれる

CakePHPのPagenateを使って表示するようにしました。

スポンサードリンク

CakePHPのページネーションを設定

前回の検索機能にページネーションを付けます。

まずはページネーションの設定です。

(例)Controller/PostsController.php
//Paginationの設定

public $paginate = array(
	//モデルの指定
	'Post' => array(
  	    //1ページ表示できるデータ数の設定
	    'limit' => 20,
	)
);

次にアクション部分の設定です。

前回の検索機能のコントローラー
(例)Controller/PostController.php

public function search(){
 //リクエストがPOSTで送られたデータが空白で無ければ
   if($this->request->is('post') && $this->request->data['Post']['title'] != ""){
      //Formの値を取得
      $title = $this->request->data['Post']['title'];
    //検索文字を空白(全角又は半角)で区切って配列$keywordsに代入
    $keywords = preg_split("/ |\\s/",$title);
    //配列$keywordsの数だけ繰り返して検索条件を$conditionsに代入
    foreach($keywords as $keyword){
      $conditions[] = "title like '%$keyword%'";
    }
    //POSTされたデータを曖昧検索
    $data=$this->->find('all',array(
     'conditions' => $conditions
    ));
     $this->set('datas',$data);
   }
 }

これを、下記のように変更します。

public function search(){
 //リクエストがPOSTで送られたデータが空白で無ければ
   if($this->request->is('post') && $this->request->data['Search']['title'] != ""){
      //Formの値を取得
      $title = $this->request->data['Post']['title'];
    //検索文字を空白(全角又は半角)で区切って配列$keywordsに代入
    $keywords = preg_split("/ |\\s/",$title);
    //配列$keywordsの数だけ繰り返して検索条件を$conditionsに代入
    foreach($keywords as $keyword){
      $conditions[] = "title like '%$keyword%'";
    }
     $data = $this->paginate($conditions);
     $this->set('datas',$data);
   }
 }

pagenateに検索条件を指定してあげればいいだけです。

pagenateメソッドの引数に条件を配列で指定すると

ページネーションの機能を使って検索結果を表示できます。

また、アクションの前のpagenate変数にオーダーなどの指定もできますが、

アクションによって並び替えをしたい場合は

public function search(){
 //リクエストがPOSTで送られたデータが空白で無ければ
   if($this->request->is('post') && $this->request->data['Search']['title'] != ""){
      //Formの値を取得
      $title = $this->request->data['Post']['title'];
    //検索文字を空白(全角又は半角)で区切って配列$keywordsに代入
    $keywords = preg_split("/ |\\s/",$title);
    //配列$keywordsの数だけ繰り返して検索条件を$conditionsに代入
    foreach($keywords as $keyword){
      $conditions[] = "title like '%$keyword%'";
    }
      //作成日の新しい順に並べ替える
      $this->paginate = array(
         'order' => array('created' => 'DSEC')
     );
     $data = $this->paginate($conditions);
     $this->set('datas',$data);
   }
 }

このようにするとページネーションを

各アクションごとに条件を指定できます。

ページを変えても同じ結果が出るようにする

最初の方法だとページが変わったときに

1ページ目のみしか検索結果が表示されなくなります。

2ページ目以降も同じ結果が出るようにするために

検索条件をセッションに入れるようにします。

public function search($page = null, $sort = null, $direction = null){//ページのパラメータを取る
 //リクエストがPOSTで送られたデータが空白で無ければ
   if($this->request->is('post') && $this->request->data['Search']['title'] != ""){
      //Formの値を取得
      $title = $this->request->data['Post']['title'];
      //session用
      $search['title'] = $title;
    //検索文字を空白(全角又は半角)で区切って配列$keywordsに代入
    $keywords = preg_split("/ |\\s/",$title);
    //配列$keywordsの数だけ繰り返して検索条件を$conditionsに代入
    foreach($keywords as $keyword){
      $conditions[] = "title like '%$keyword%'";
    }
      
      //検索条件をセッションに保存
      if($this->Session->check('conditions')){
         $this->Session->delete('conditions');	//古いのは削除
      }

      if($this->Session->check('search')){
         $this->Session->delete('search');	//古いのは削除
      }

      $this->Session->write('conditions', $conditions);
      $this->Session->write('seach', $search);
 
      //作成日の新しい順に並べ替える
      $this->paginate = array(
         'order' => array('created' => 'DSEC')
     );
     $data = $this->paginate($conditions);
     $this->set('datas',$data);
   }else{
     if($this->Session->check('conditions')){
         //パラメータがなければ新しい検索のため削除
         if(empty($this->params['named']['page']) && empty($this->params['named']['sort']) && empty($this->params['named']['direction'])){
             $this->Session->delete('conditions');
             $this->Session->delete('search');
         }else{
             $conditions = $this->Session->read('conditions');
             $search = $this->Session->read('search');
               //作成日の新しい順に並べ替える
             $this->paginate = array(
               'order' => array('created' => 'DSEC')
             );
             $data = $this->paginate($conditions);
             $this->set('datas', $data);
             $this->set('search', $search);
        }
     }
 }

検索ボタンを押したとき

//検索条件をセッションに保存
      if($this->Session->check('conditions')){
         $this->Session->delete('conditions');	//古いのは削除
      }

      if($this->Session->check('search')){
         $this->Session->delete('search');	//古いのは削除
      }

まず検索ボタンを押した場合に

検索条件をセッションに保存します。

その際に、検索キーワードもセッションに入れておきます。

2ページ目とかに移動した場合に

フォームにキーワードが入っていた方が親切だと思うので・・・

セッションにデータを保存する前に

セッションに前の検索データがあるかを調べて

あれば削除してから、セッションに保存します。

検索条件をセッションに入れると

他のページへ行ってから検索ページに戻ると

検索条件が残ってるといけないので

ページの最初に来たときに

セッションに検索結果があれば削除するようにします。

ページを移動したときと最初に来たとき

if($this->Session->check('conditions')){
  ・・・
   略
  }else{
  ・・・
  略

ページを移動したときと最初に検索ページに来たときは

まず、検索用のセッションがあるかないかを調べます。

無い場合は一番最初の状態なのでセッションがないです。

なので何もしません。

セッションがある場合はページ移動か以前検索した場合なので

ページ移動かどうかを調べます。

ページ移動の場合はパラメーターがあるので

パラメーターがあるかどうかを調べます。

まずは、パラメータを取得できるようにsearchメソッドの引数に

設定を追加しておきます。

public function search($page = null, $sort = null, $direction = null){//ページのパラメータを取る
・・・
略

上記のようにしておくとページ番号や並び順などをパラメータとして取得できます。

if($this->Session->check('conditions')){
  //パラメータがなければ新しい検索のため削除
  if(empty($this->params['named']['page']) && empty($this->params['named']['sort']) && empty($this->params['named']['direction'])){
       $this->Session->delete('conditions');
       $this->Session->delete('search');
  }else{
  ・・・
  略

ページ番号などのパラメータがなければ

ページ移動ではないので検索ページに新しく来たことになります。

なので、前回の検索条件を削除します。

         if(empty($this->params['named']['page']) && empty($this->params['named']['sort']) && empty($this->params['named']['direction'])){
             $this->Session->delete('conditions');
             $this->Session->delete('search');
         }else{
             $conditions = $this->Session->read('conditions');
             $search = $this->Session->read('search');
               //作成日の新しい順に並べ替える
             $this->paginate = array(
               'order' => array('created' => 'DSEC')
             );
             $data = $this->paginate($conditions);
             $this->set('datas', $data);
             $this->set('search', $search);

パラメーターのデータがあればページ移動なので

セッションの検索条件と検索キーワードをセッションから読んで

変数にセットします。

ビューファイルの調整

コントローラーは調整できたので

次にフォームに検索キーワードを入れるようにします。

検索フォームの部分に以下のように変えます。

(例)View/Posts/search.php

<?php
if(!empty($search)){
   $title = $search['title'];
}else{
   $title = "";
}
 echo $this->Form->create('Post', array('action'=>'search'));
 echo $this->Form->input('title', array('label' => 'タイトル名を入れてください', 'default' => $title));
 echo $this->Form->end('検索');
?>

これでページ移動しても

検索フォームに検索キーワードが入力された状態になります。

CakePHP2 実践入門 (WEB DB PRESS plus)

新品価格
¥3,110から
(2015/1/27 23:08時点)

スポンサードリンク

4 Responses to “初めての[CakePHP2.x]での開発、そして挫折するまで日記~その27 検索結果をページネーションで表示させる”

  1. hiro より:

    はじめまして、少々気になったので、ぶしつけながら失礼します。

    コントローラーの22行目
    $this->Session->write(‘search’, $search);

    この$searchですが、何が入っているのでしょうか?
    設定されているところが見当たらなかったので、質問させていただきます。

    • tailtension より:

      >hiroさん

      コメントありがとうございます。
      ご質問のあった、$searchですが
      この記事の内容にはいらない変数です。
      元々、作ったものに記述してあったものが残ったままでした。
      ややこしくてすみません。

      作ったものでは
      $searchに検索に使用したキーワードを入れるようにしています。
      ページが変わっても、フォームは残したままにしているため
      フォームに検索したキーワード表示させるために使っています。

      この記事にはあるとややこしくなるため
      修正しておきます。

      ありがとうございました。

  2. otaka より:

    はじめまして。

    1点確認ですが、
    View/Posts/search.phpの3行目の$searchですが、どこで値を設定していますか?
    controller側から、$searchに値を渡しているようには見えなかったもので質問しました。

    • tailtension より:

      >otakaさん
      コメントありがとうございます。
      ご質問の
      >View/Posts/search.phpの3行目の$searchですが、どこで値を設定していますか?
      ですが、Controller側の記述が抜けておりました。
      申し訳ございません。
      記事を修正しましたので、そちらをご確認ください。
      ありがとうございました。

コメントを残す

サブコンテンツ

このページの先頭へ