PHP
CakePHP
Paginator

CakePHP2 Paginatorコンポーネント用いてvirtualFieldで定義したjoin先テーブルのカラムでソートをする方法。

More than 3 years have passed since last update.

少しはまったので、忘れない為のメモとして投稿。

paginatorコンポーネントを使用した一覧ページにて、virtualFieldで定義したjoin先のテーブルの

カラムでソートをする際の記述方法。


Controller

Model1にModel2をjoinしてModel1.idでGROUP BYし、Model1に紐づくjoin先のテーブルのidをカウントする記述。

$this->paginate('Model1')を行う前に前にバーチャルフィールドを定義する。


Model1sController.php

// join先のテーブルのカラムをcountするvirtualField

$this->Model1->virtualFields['model2VFColumnName'] = 'count(distinct Model2.model1_id)';

// paginate
$this->paginate = array('Model1' => array(
'fields' => array(
'id',
'title',
'model2VFColumnName',
),
'joins' => array(
'table' => 'model2s',
'alias' => 'Model2',
'type' => 'left',
'conditions' =>
'Model1.id = Model2.model1_id'
),
'conditions' => array(
is_delete = 0,
),
'limit'=>100,
'group' => array('Model1.id'),
'order' => array('Model1.id' => 'desc'),
);

$model1Data = $this->paginate('Model1');



View

View側ではコントローラー側で定義したvirtualField名を記述する。


Model1sController.php

$this->paginator->sort('model2VFColumnName', '項目名');


以上で、virtualFiledで定義したjoin先のカラムで並び替えができる。

下記に調査の際に読んだPaginatorComponent.php内の仕組みをメモ。


PaginatorComponent.php

paginateメソッド内で呼び出されているvalidateSortメソッド397行目辺り

並び替えに必要なorderをセットする処理


lib/Cake/Controller/Component/PaginatorComponent.php

if ($correctAlias && $object->lib/Cake/Controller/Component/PaginatorComponent.php) {

$order[$object->alias . '.' . $field] = $value;
} elseif ($correctAlias && $object->hasField($key, true)) {
$order[$field] = $value;
} elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field, true)) {
$order[$alias . '.' . $field] = $value;
}

上記コードの最初の条件文でhasField($field)で呼び出し元モデルのテーブルに、

並び替え対象のカラムが存在するかどうかチェックしている。今回のケースはjoin先のテーブルでのソートなので、この条件分には入らない。

次の条件文ではhasField($field, true)となっており、第2引数にtrueがセットされているのでvitrualFieldも含めてカラムが存在するかを確認している。

paginateをコントローラーで呼び出す前にvirtualFieldを定義する事でこの条件分に入りViewで定義する$this->paginator->sort('model2VFColumnName')で生成されるリンクをクリックした際に渡るカラム名model2VFColumnNameが並び替えの対象となる。