(CakePHP 2.x) 重複を取り除いた場合のPaginateのページ数

CakePHP

CakePHP

CakePHPのPaginateがとても便利で

色々な場所に使っているのですが、

重複したものを取り除いた場合に

ページ数が重複を取り除く前になってしまいます。

そのページ数を直す方法です。

スポンサードリンク

重複したものを省くGROUP BY

まず、Paginateを使う時にGROUP BYをしていします。

コントローラーで重複を省きたいカラムを設定します。

アクションごとに設定する場合は設定したアクション内に記述します。

$this->paginate = array(
	'group' => array('company'),
);
$data = $this->paginate();

これでPagenateすると

取得データはGROUP BYされています。

しかし、ページ数や取得件数がGROUP BYの前の結果になってしまい

ページ移動をするとエラーになります。

Paginatorで件数を取得しなおす

こちらに解決策がありました。
(参考)
Group Byしている時にpaginator->number()が表示されない件Add Star

GROUP BYをするモデル内で

paginateのオプションとして’group’が含まれていれば

getAffectedRowsをオーバーライドして

ページ数を取得しなおすという方法です。

Model.php

//ページネーションでGroup By使ったときのページ数
public function paginateCount($conditions = null, $recursive = 0, $extra = array()) {
    $parameters = compact('conditions');
    $this->recursive = $recursive;
    $count = $this->find('count', array_merge($parameters, $extra));
    if (isset($extra['group'])) {
        $count = $this->getAffectedRows();
    }
    return $count;
}

こうすると、paginateの設定で

GROUP BYを設定している場合は

ページカウンターがページ数を

取得しなおしてくれて

問題なく使えます。

DISTINCTで試してみる

重複を取り除く方法としてDISTINCTもあります。

こちらでやった場合ですが、

GROUP BYと同じでページ数が重複を取り除く前のページ数になります。

こんな感じでDISTINCTを指定します。

$this->paginate = array(
    'fields' => array('DISTINCT company'),
);
$data = $this->paginate();

これをGROUP BYと同じ方法でやってみます。

こちらを参考にさせてもらいました。
(参考)
【cakePHP】重複を省いたPaginator

Model.php

public function paginateCount($conditions = null, $recursive = 0, $extra = array()) {
    $parameters = compact('conditions');
    $this->recursive = $recursive;
    $extra['fields'] = 'DISTINCT '.$this->name.'.id'; // 重複削除
    $count = $this->find('count', array_merge($parameters, $extra));
    return $count;
}

この方法でもページ数は重複を除いた数で出てきました。

が、

これだと、同じモデルを使ってPagenateしているアクションで

勝手にDISTINCTされてしまいます。

じゃあ、GRORP BYの時と同じように

fieldsで判断させればと思いまして、

Model.php

//ページネーションでGroup By使ったときのページ数
public function paginateCount($conditions = null, $recursive = 0, $extra = array()) {
    $parameters = compact('conditions');
    $this->recursive = $recursive;
    $count = $this->find('count', array_merge($parameters, $extra));
    if (isset($extra['fields'])) {
        $count = $this->getAffectedRows();
    }
    return $count;
}

こんな感じでextraでfieldsがあるときにとしてみました。

コントローラーにはDISTINCTを付けます。

$this->paginate = array(
	'fields' => array('DISTINCT company'),
);
$data = $this->paginate();

すると・・・

結果は重複が取り除かれているものの

ページ数は重複前のの状態です。

なぜだろうと思いましてPaginatorControllerの中身を見てみると

lib/Cake/Controller/Component/PaginatorController.php

//169行目らへん
$extra = array_diff_key($options, compact(
	'conditions', 'fields', 'order', 'limit', 'page', 'recursive'
));

ここを見るとオプション項目で

‘conditions’, ‘fields’, ‘order’, ‘limit’, ‘page’, ‘recursive’の

6つの項目は変数extraに渡されないようです。

なので、GROUP BYで判断させるものの方が

使い勝手がいいかと思います。

CakePHP2 実践入門 (WEB DB PRESS plus)

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

スポンサードリンク

コメントを残す

サブコンテンツ

このページの先頭へ