THE SAUNA これが噂のパラダイス
THE SAUNA これが噂のパラダイス
2009.12.08

paginatorでグループ化したときの件数の表示

まっちー

CakePHPで検索結果の表示ページなどにページング処理を行う際、検索結果が何件で現在は何件目が表示されているかみたいなのを表示させたいことはままあると思う。

paginatorヘルパーにはcounterというメソッドがあって、たとえば検索結果の合計数は%count%という定数に入っている。なので、view側で

<?php echo $paginator->counter(array('format' => "全%count%件")) ?>

//実際の表示
全100件

みたいな感じで使うことができる。

しかし、$this->paginate(‘Model’)でDBからデータを引っ張ってくるときに、グループ化していると、これが上手く表示されない。僕がやった場合でも、明らかに4000件くらい該当するデータがあったのに表示は『全1件』とかになってた。

何じゃこりゃと思って調べてみると、こちらのサイトにどうやらその疑問の答えとなることが書いてある。

どうやらグループ化して件数をカウントすると、そのグループごとの件数が出てくるらしい。たとえばユーザーIDでグループ化したら、各ユーザーIDごとの合計件数が取得されると、そういう感じ。そりゃ合計が4000件になるわけがない。

上記の参考サイトにはその解決方法も書いてあったので、今回はそれを丸々参考(人はそれをパクリと言う)にさせていただきました。

controller.phpにあるpaginateメソッドを見てみると、モデルにpaginateCountというメソッドがなければmodel.phpのfindCountを呼ぶようになっているみたいなので、要は自分でpaginateCountというメソッドを作ってグループ化した場合でもSQL文でSELECTしただけの件数を取得できるようにすれば良い。

そこで以下のソースをページング処理の必要なモデルに書く。複数のモデルで使うようならapp_model.phpに書くのが良いと思う。

function paginateCount($conditions = null, $recursive = 0, $extra = array()) {

 € € € $params = array('conditions' => $conditions);

 € € € $this->recursive = $recursive;

 € € € $count = $this->find('count', array_merge($params, $extra));
 € €
 € € € if(isset($extra['group'])) {

 € € € € € € € $count = $this->getAffectedRows();

 € € € }
 € €
 € € € return $count;

}

getAffectedRows()というのは、簡単に言えば投げたSQL文にヒットした件数を返しますよという関数。つまりグループ化とか関係なく、全件を返してくれる。

しかしグループ化するとそんな処理が行われていたなんて、初めて知ったさ。CakePHPは、まだまだ知らないことがいっぱいのようです。