I am trying to make a pagination for my threads.
The code works, but I want to limit the posts per page.
How can I achieve this?
And how to draw the pagination to my threads view?
My code:
$this->paginate = [
'contain' => 'posts'
];
$query = $this->Threads->find('all')->where(['id' => $id]);
$this->set('test', $this->paginate($query));
Thanks.
Have you tried passing a limit option to $this->paginate?
$this->paginate = [
'contain' => ['Posts'],
'limit' => 10 // limits the rows per page
];
https://book.cakephp.org/3.0/en/controllers/components/pagination.html
Related
Products belongsToMany Categories and Categories hasMany Products, inside my Product view I'm showing a list of all it's categories but I want to paginate or limit these results.
My current code on ProductsController is:
$product = $this->Products
->findBySlug($slug_prod)
->contain(['Metas', 'Attachments', 'Categories'])
->first();
$this->set(compact('product'));
I know I need to set $this->paginate() to paginate something but I can't get it working to paginate the categories inside the product. I hope you guys can understand me.
UPDATE: Currently I have this going on:
$product = $this->Products->findBySlug($slug_prod)->contain([
'Metas',
'Attachments',
'Categories' => [
'sort' => ['Categories.title' => 'ASC'],
'queryBuilder' => function ($q) {
return $q->order(['Categories.title' => 'ASC'])->limit(6);
}
]
])->first();
The limit works but I don't know how to paginate yet
The paginator doesn't support paginating associations, you'll have to read the associated records manually in a separate query, and paginate that one, something along the lines of this:
$product = $this->Products
->findBySlug($slug_prod)
->contain(['Metas', 'Attachments'])
->first();
$categoriesQuery = $this->Products->Categories
->find()
->innerJoinWith('Products', function (\Cake\ORM\Query $query) use ($product) {
return $query->where([
'Products.id' => $product->id,
]);
})
->group('Categories.id');
$paginationOptions = [
'limit' => 6,
'order' => [
'Categories.title' => 'ASC'
]
];
$categories = $this->paginate($categoriesQuery, $paginationOptions);
$this->set(compact('product', 'categories'));
Then in your view template you can display your $product and separately paginate $categories as usual.
See also
Cookbook > Controllers > Components > Pagination
Cookbook > Views > Helper> Paginator
Cookbook > Database Access & ORM > Query Builder > Filtering by Associated Data
Products belongsToMany Categories and Categories hasMany Products, inside my Product view I'm showing a list of all it's categories but I want to paginate or limit these results.
My current code on ProductsController is:
$product = $this->Products
->findBySlug($slug_prod)
->contain(['Metas', 'Attachments', 'Categories'])
->first();
$this->set(compact('product'));
I know I need to set $this->paginate() to paginate something but I can't get it working to paginate the categories inside the product. I hope you guys can understand me.
UPDATE: Currently I have this going on:
$product = $this->Products->findBySlug($slug_prod)->contain([
'Metas',
'Attachments',
'Categories' => [
'sort' => ['Categories.title' => 'ASC'],
'queryBuilder' => function ($q) {
return $q->order(['Categories.title' => 'ASC'])->limit(6);
}
]
])->first();
The limit works but I don't know how to paginate yet
The paginator doesn't support paginating associations, you'll have to read the associated records manually in a separate query, and paginate that one, something along the lines of this:
$product = $this->Products
->findBySlug($slug_prod)
->contain(['Metas', 'Attachments'])
->first();
$categoriesQuery = $this->Products->Categories
->find()
->innerJoinWith('Products', function (\Cake\ORM\Query $query) use ($product) {
return $query->where([
'Products.id' => $product->id,
]);
})
->group('Categories.id');
$paginationOptions = [
'limit' => 6,
'order' => [
'Categories.title' => 'ASC'
]
];
$categories = $this->paginate($categoriesQuery, $paginationOptions);
$this->set(compact('product', 'categories'));
Then in your view template you can display your $product and separately paginate $categories as usual.
See also
Cookbook > Controllers > Components > Pagination
Cookbook > Views > Helper> Paginator
Cookbook > Database Access & ORM > Query Builder > Filtering by Associated Data
The Code
Say I have two models, named Product and Image, which are linked by Product hasMany Image and Image belongsTo Product.
Now, say I want to fetch all products with the first image each. I would use this code:
$this->Products->find('all')
->contain([
'Images' => function($q) {
return $q
->order('created ASC')
->limit(1);
}
]);
Looks about right, right? Except now only one of the products contains an image, although actually each product contains at least one image (if queried without the limit).
The resulting Queries
The problem seems to be with the limit, since this produces the following two queries (for example):
SELECT
Products.id AS `Products__id`,
FROM
products Products
and
SELECT
Images.id AS `Images__id`,
Images.product_id AS `Images__product_id`,
Images.created AS `Images__created`
FROM
images Images
WHERE
Images.product_id in (1,2,3,4,5)
ORDER BY
created ASC
LIMIT 1
Looking at the second query, it is quite obvious how this will always result in only one image.
The Problem
However, I would have expected the Cake ORM to limit the images to 1 per product when I called limit(1).
My question: Is this an error in how I use the ORM? If so, how should I limit the number of images to one per image?
The cleanest way you can do this is by creating another association:
$this->hasOne('FirstImage', [
'className' => 'Images',
'foreignKey' => 'image_id',
'strategy' => 'select',
'sort' => ['FirstImage.created' => 'DESC'],
'conditions' => function ($e, $query) {
$query->limit(1);
return [];
}
])
Check it ,this one is my code
$this->Orders->hasOne('Collections', [
'className' => 'Collections',
'foreignKey' => 'order_id',
'strategy' => 'select',
'conditions' => function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) {
$query->order(['Collections.id' => 'ASC']);
return [];
}
]);
$Lists = $this->Orders->find('all')->where($condition)->contain(['Collections'])->order(['Orders.due_date DESC']);
$this->set(compact('Lists'));
If the reason you are limiting it to one image is that you want to have a defaulted image. You might consider adding a default field in the image table and doing a Alias like this:
var $hasOne = array(
'CoverImage' => array(
'className' => 'Image',
'conditions' => array('CoverImage.default' => true),
),
It looks like you are using Cake v3 so you can just add the equivalent association as the above is a 2.x sample.
In the Model definition we would do the following:
public $hasMany = [
'ModelName' => [
'limit' => 1,
'order' => 'ModelName.field DESC'
],
];
as described in the docs: https://book.cakephp.org/2/en/models/associations-linking-models-together.html#hasmany
Currently, I am working on Cakephp Application. I want to first paginate and then sort the paginated data according to the condition show below or the other way around. First sort the data and then paginate it. Any hints on how to approach the problem.
I am just one week familiar with cakephp.
$condition[] = 'Banner.customer_id = "'.$loggedUserId.'"';
$this->Banner->recursive = 2;
$this->paginate = array(
'limit' => 20,
);
$data = $this->paginate('Banner', $condition);
$data_sorted = $this->Banner->find('all',array('order'=>array("Banner.created DESC")));
$this->set('loggedInUserId', $loggedUserId);
$this->set('savecrit', $savecrit);
$this->set('Banners', $data_sorted);
Try this:
$this->paginate = array(
'conditions' => array('Banner.customer_id' => $loggedUserId),
'limit' => 20,
'order' => array('id' => 'DESC'),
);
So this is what I am trying to do.
My table say(Courses) has multiple entries with same id.
When I get the data from paginate it shows all the records. So if I have 3 records with Id 5 it will show record number 5 three times.
Now What I want is that it should show the record only once.
I searched online but can't find anything.
If anyone has come across such problem and found a solution to it please let me know.
Thanks,
I came across your problem, as I had a similar problem. David Z's solution did not work for me, but I did find that the group variable in $paginate worked for me.
So using your code sample above, this is how I'd think it should work.
$paginate = array(
'Courses' => array(
'limit' => 20,
'fields' => array('Courses.id'),
'conditions' => $cond,
'group' => array('Courses.id'),
'order' => array('Courses.id' => 'asc')
)
);
To hopefully shed some more light on the solution that worked for me, I have Systems that belong to Companies. I wanted to get a list of the unique companies, for the systems I have. This is the exact code I used, that worked for me
$this->paginate = array ('fields' => array ('Company.*'),
'order' => array('Company.name' => 'ASC'),
'group' => array('Company.id'));
$this->set('companies', $this->paginate($this->Company->System));
Hope this has helped
Looking at the CakePHP cookbook, the documentation for pagination shows that you can override the $paginate member. Behind the scenes, this similar to passing in the parameters for your model's find('all'). Maybe try setting parameter to explicitly return the filds that you are interested with the distinct keyword to narrow down the values you need?
class RecipesController extends AppController {
var $paginate = array(
'fields' => array('Model.field1', 'DISTINCT Model.field2')
);
}
So here is how my paginate variable looks like:
var $paginate = array(
'Courses' => array(
'limit' => 20,
'page' => 1,
'order' => array(
'Courses.id' => 'asc')
),
);
The condition variable looks something like this:
$cond = array("Courses.id LIKE "=>$this->data['id_search'],
"Courses.length LIKE "=>$this->data['length_search'],
"Courses.marks LIKE "=>$this->data['marks']
);
And this is how I am calling paginate.
$data = $this->paginate('CdmaRfReport',$cond);
I tried doing
$paginate = array(
'Courses' => array(
'limit' => 20,
'fields' => array('DISTINCT Courses.id'),
'page' => 1,
'conditions' => $cond,
'group' => array('id'),
'order' => array(
'Courses.id' => 'asc')
)
);
It doesn't seem to help.
I also tried
$cond = array("DISTINCT Courses.id "=>$this->data['id_search'],
"Courses.length LIKE "=>$this->data['length_search'],
"Courses.marks LIKE "=>$this->data['marks']
);
Even this errors out
I might be something wrong. But I am not able to figure it out.
Any suggestions please let me know.