I am making simple pagination which using this code:
$paginate = array(
'limit' => 30,
'fields' => array('DISTINCT Doctor.id','Doctor.*'),
'order' => array('Doctor.id' => 'desc'),
'joins' => array(
array('table' => 'doctors_medical_degrees',
'alias' => 'DoctorsMedicalDegree',
'type' => 'INNER',
'conditions' => array(
'Doctor.id = DoctorsMedicalDegree.doctor_id',
)
),
),
'recursive' => -1,
);
$this->Paginator->settings = $paginate;
$data = $this->Paginator->paginate('Doctor');
Now the problem is I am using Inner join so for Distinct result I am using Distinct Doctor.id, but the cakephp when doing query for pagination the count query not including Distinct Doctor.id
'query' => 'SELECT COUNT(*) AS `count` FROM `pharma`.`doctors` AS `Doctor` INNER JOIN `pharma`.`doctors_medical_degrees` AS `DoctorsMedicalDegree` ON (`Doctor`.`id` = `DoctorsMedicalDegree`.`doctor_id`)'
as you can see No
COUNT(DISTINCT Doctor.id)
so pagination return more number of result which it can actually return for
The problem is that the paginator doesn't pass the fields to the find('count')
call, so by default it will always count on *
.
But even if it would pass the fields, passing an array would make the find('count')
call expect that the field to count is passed as a COUNT()
expression, ie something like
'fields' => array('COUNT(DISTINCT Doctor.id) as `count`')
However that won't work with the paginator anyways, so what you need is a customized find('count')
call.
Custom query pagination to the rescue
See Cookbook > Pagination > Custom Query Pagination for more information.
Custom query pagination is probably your best bet, that way it's totally up to you how counting is being done.
For example you could make use of the extra values passed by the paginator component, that way you could pass the field to count on to the find('count')` call, something like this (untested example code):
class Doctor extends AppModel {
// ...
public function paginateCount($conditions = null, $recursive = 0, $extra = array()) {
$parameters = compact('conditions');
if($recursive != $this->recursive) {
$parameters['recursive'] = $recursive;
}
if(!empty($extra['countField'])) {
$parameters['fields'] = $extra['countField'];
unset($extra['countField']);
}
return $this->find('count', array_merge($parameters, $extra));
}
}
$this->Paginator->settings = array(
'limit' => 30,
'fields' => array('DISTINCT Doctor.id','Doctor.*'),
// ...
'countField' => 'DISTINCT Doctor.id'
);
$data = $this->Paginator->paginate('Doctor');
This should then create a COUNT
query that looks like
SELECT COUNT(DISTINCT Doctor.id) AS `count` ...
I found the solution on CakePHP - Pagination total count differs from actual count when using DISTINCT
Add the public function paginateCount in your model and use the distinct option in your paginator like:
$this->paginate = array('limit' => $limit, 'order' => array('Item.created' => 'ASC', 'Item.code' => 'ASC'),
'fields' => 'DISTINCT Item.*',
'conditions' => $conditions,
'countField' => array('Item.id'),
'joins' => $joins,
'distinct' => 'Item.id',
'contain' => array(
'Image' => array('limit' => 1),
'ItemsTag'
)
);