how to pass raw sql query into paginator component in cakephp - cakephp-2.0

I have row sql query and i want to paginate this query with the help of cakephp paginator component.How could i ?
$q = "SELECT
`UserList`.`id`,`UserList`.`user_id`,`UserList`.`list_user_id`,
`User`.`username` ,`User`.`id` ,
`UserDetail`.`sex`,`UserDetail`.`image`,`UserDetail`.`display_name`,`UserDetail`.`country`,`UserDetail`.`height`,`UserDetail`.`weight`,`UserDetail`.`hair_color`,`UserDetail`.`eye_color`
from `user_lists` as `UserList`
inner join `users` as `User` on `UserList`.`list_user_id` = `User`.`id`
inner join `user_details` as `UserDetail` on `UserList`.`list_user_id` = `UserDetail`.`user_id`
where ((`UserList`.`user_id`=".$user_id.") and (`UserList`.`in_list`='short')) order by `UserList`.`created` desc limit 1";
$this->paginate = array(
'conditions' => /*Pass $q here */,
'limit' => 15,
)
);
thanks in advance.

You don't
That just doesn't work, from the query in the question though, all you need is to use pagination as normal:
class UserListsController extends AppController {
public $paginate = array(
'contain' => array(
'User',
'UserDetail'
)
);
public function index($userId = null) {
$conditions = array(
'user_id' => $userId,
'in_list' => 'short'
);
$data = $this->paginate($conditions);
$this->set('data', $data);
}
}

Related

CakePHP: How to make the paginator component use distinct counting?

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'
)
);

CakePHP HABTM queries

What's the CakePHP way to do such queries?
SELECT news.* FROM news, users
INNER JOIN news_users nu ON nu.user_id = users.id
WHERE users.id = $user_id
I have a link table news_users, so trying with something like $news = $this->News->findByUserId($this->User->id); does not work, because it looks for news.user_id
P.S. The above query works, I just desire to make the script shorter.
You can declare findByUserId function in your News model:
//put this code in your News model
public function findByUserId($user_id = null)
{
return $this->find('all', array(
'conditions' => array(
'NewsUser.user_id' => $user_id
),
'joins' => array(
array(
'table' => 'news_users',
'alias' => 'NewsUser',
'type' => 'INNER',
'conditions' => array(
'NewsUser.news_id = News.id'
)
)
)
));
}
Then you can use your findByUserId function enywhere in your NewsController
//this code in NewsController
$news = $this->News->findByUserId($this->User->id);

cakephp paginate with group and group count

I have a db table with items with a matching group_id. I'd like to display those items in a paginator like this:
codeset_id - itemsInGroupCount
group1 - 3
group2 - 6
How can I do this? I have the distinct groups but how do I get the count?
My Controller:
public function admin_index() {
$this->Codesetitem->recursive = 0;
$this->paginate = array(
'Codesetitem' => array(
'group' => 'codeset_id',
'order' => array('codeset_id' => 'asc')
)
);
$this->set('codesetitems', $this->paginate());
}
The following seems to work on my side:
public $components = array('Paginator');
public function index() {
$this->Paginator->settings = array(
'fields' => array('Item.group_id', 'COUNT(*) AS "Item.group_count"'),
'limit' => 3,
'group' => 'group_id'
);
$this->set('items', $this->Paginator->paginate('Item'));
}
I simply added COUNT(*) AS "Foo.bar" to the fields key.

Cakephp IN(x,x) with 'AND'

I am struggeling with a custom find in cakephp 2.1.
In my model I have this function:
public function findByGenres($data = array()) {
$this->Item2genre->Behaviors->attach('Containable', array('autoFields' => false));
$this->Item2genre->Behaviors->attach('Search.Searchable');
$query = $this->Item2genre->getQuery('all', array(
'conditions' => array('Genre.name' => $data['genre']),
'fields' => array('item_id'),
'contain' => array('Genre')
));
return $query;
}
This returns the following query:
SELECT `Item`.`id` FROM `items` AS `Item`
WHERE `Item`.`id`
IN(SELECT `Item2genre`.`item_id` FROM `item2genre` AS Item2genre
LEFT JOIN `genres` AS Genre ON(`genre_id` = `Genre`.`id`)
WHERE `Genre`.`name`
IN ('Comedy', 'Thriller')
)
The result of the query returns Items with either 'Comedy' or 'Thriller' genre associated to them.
How can I modify the query to only return Items with 'Comedy' AND 'Thriller' genre associated to them?
Any suggestions?
edit:
content of data is:
'genre' => array(
(int) 0 => 'Comedy',
(int) 1 => 'Thriller'
)
You would want your 'conditions' key to be this:
'conditions' => array(
array('Genre.name' => 'Comedy'),
array('Genre.name' => 'Thriller')
)
So specifically to your problem your $data['genre'] is array('Comedy', 'Thriller'). So you could create a variable that has contents similar to what you need by doing:
$conditions = array();
foreach ($data['genre'] as $genre) {
$conditions[] = array('Genre.name' => $genre);
}

How can i set orderby in cakephp

This is my code ,here how can i give orderby .
$this->set('added', $this->paginate('TravancoMarketing', array('status = 0', 'assigned_by = '.$user_level)));
Here i want to give order by TravancoMarketing.id DESC
How can i give this?
You can either add it as the default order by to the TravancoMarketing model:
class TravancoMarketing {
public $order = array('TravancoMarketing.id'=>'DESC');
}
or to the paginate query itself:
$this->paginate = array(
'conditions'=>array(
'TravancoMarketing.status'=>0,
'TravancoMarketing.assigned_by'=>$user_level
),
'order'=>array(
'TravancoMarketing.id'=>'DESC'
)
);
$this->set('added', $this->paginate('TravancoMarketing'));
in your controller you should declare something like this:
public $paginate = array(
'order' => array(
'TravancoMarketing.id' => 'DESC'
)
);

Resources