Cakephp $paginate does not show all the results - cakephp-3.0

when I do $ paginate even without conditions, I miss 5 results.
when I do a "find all" on the same table I have all the results.
$this->paginate = [
'order' => ['Radars.id' => 'DESC'],
'contain' => ['Cities', 'Accommodations', 'Users'],
];
$radars = $this->paginate($this->Radars);

Actually paginate has its own default parameters already defined. Max limit is set to 100 by default.
See the doc for more details
https://book.cakephp.org/3.0/en/controllers/components/pagination.html

Related

Laravel returns error max prepared statements after getting many count()'s

I am getting the following error from Laravel.
SQLSTATE[42000]: Syntax error or access violation: 1461 Can't create
more than max_prepared_stmt_count statements (current value: 16382)
(SQL: select count(*) as aggregate from guild)
I have tried removing the guild count statement, but this makes the next SQL query give an error.
$users = User::count();
$crowdfunding = CrowdfundingSettings::find(1);
$guilds = Guild::count();
$data = [
'totalItems' => ItemTemplate::totalCustomItems(),
'totalAbilities' => Ability::totalCustom(),
'totalMobs' => MobTemplate::all()->count(),
'totalQuests' => Quest::all()->count(),
'totalLootTables' => LootTable::all()->count(),
'totalMerchantTables' => MerchantTable::all()->count(),
'totalDialogue' => Dialogue::all()->count(),
'totalCraftingRecipes' => CraftingRecipe::all()->count(),
'totalItemSets' => ItemSetProfile::all()->count(),
'totalSkills' => Skill::totalCustom()
];
return response()->json([
'crowdfunding_settings' => $crowdfunding,
'accounts' => $users,
//'guilds' => $guilds,
'data' => $data,
]);
I am expecting results to from the statement, yet I get an error. I have increased max prepared statements to 32k, but I still get this error displaying it is set to 16k.
As Dimitri mentioned (and also confirmed here) you should not use ->all() when you only need the count and not the data in the model itself.
Replace $data like so:
$data = [
'totalItems' => ItemTemplate::totalCustomItems(),
'totalAbilities' => Ability::totalCustom(),
'totalMobs' => MobTemplate::count(),
'totalQuests' => Quest::count(),
'totalLootTables' => LootTable::count(),
'totalMerchantTables' => MerchantTable::count(),
'totalDialogue' => Dialogue::count(),
'totalCraftingRecipes' => CraftingRecipe::count(),
'totalItemSets' => ItemSetProfile::count(),
'totalSkills' => Skill::totalCustom()
];
Counting the amount of mob templates using MobTemplate::all()->count() will result in the following sql SELECT * FROM mob_template;. The results of that will be loaded into a Eloquent collection, that collection will then count the items it contains in PHP. This is very slow, memory heavy and as it turns out you might also run into issues with prepared statements.
Count the amount of mob templates using MobTemplate::count() will result in the following sql SELECT COUNT(*) FROM mob_template;. This means the database does all the heavy lifting for counting the records and it only returns the result. That way eloquent does not have to load a collection with a bunch of data and it does not have to count all its items in PHP.
Make sure you're disposing PreparedQuery or any other prepared SQL Command after execution. Disposing calls ClosePreparedStatement.

Multiple Fields with a GroupBy Statement in Laravel

Already received a great answer at this post
Laravel Query using GroupBy with distinct traits
But how can I modify it to include more than just one field. The example uses pluck which can only grab one field.
I have tried to do something like this to add multiple fields to the view as such...
$hats = $hatData->groupBy('style')
->map(function ($item){
return ['colors' => $item->color, 'price' => $item->price,'itemNumber'=>$item->itemNumber];
});
In my initial query for "hatData" I can see the fields are all there but yet I get an error saying that 'colors', (etc.) is not available on this collection instance. I can see the collection looks different than what is obtained from pluck, so it looks like when I need more fields and cant use pluck I have to format the map differently but cant see how. Can anyone explain how I can request multiple fields as well as output them on the view rather than just one field as in the original question? Thanks!
When you use groupBy() of Laravel Illuminate\Support\Collection it gives you a deeper nested arrays/objects, so that you need to do more than one map on the result in order to unveil the real models (or arrays).
I will demo this with an example of a nested collection:
$collect = collect([
collect([
'name' => 'abc',
'age' => 1
]),collect([
'name' => 'cde',
'age' => 5
]),collect([
'name' => 'abcde',
'age' => 2
]),collect([
'name' => 'cde',
'age' => 7
]),
]);
$group = $collect->groupBy('name')->values();
$result = $group->map(function($items, $key){
// here we have uncovered the first level of the group
// $key is the group names which is the key to each group
return $items->map(function ($item){
//This second level opens EACH group (or array) in my case:
return $item['age'];
});
});
The summary is that, you need another loop map(), each() over the main grouped collection.

Cakephp 3 pagination with 'contain' and 'condition' not working

I have a Device Table containing different ids from different tables e.g. Location, Operators etc.
now I want only some of them shown in my view. so there is an array device_ids with the corresponding ids I want to Show.
I tried
$this->paginate['contain'] = ['Locations', 'Operators'];
and this shows me all devices with all corresponding Data.
I tried
$this->paginate['conditions'] = ['id IN' => $device_ids];
and this Shows me only the devices I want to view, but without corresponding Data.
as soon as I Combine those two in
$this->paginate[] = [
'conditions' => ['id IN' => $device_ids],
'contain' => ['Locations', 'Operators']
];
I receive a
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in IN/ALL/ANY subquery is ambiguous.
Has anyone has an Explanation for this behaviour?
What could I change to make this work.
Thanks a lot
L.
sorry,
as soon as I posted the question the answer was there...
I needed to specify the id more,
so with
$this->paginate[] = [
'conditions' => ['Devices.id IN' => $device_ids],
'contain' => ['Locations', 'Operators']];
it works fine.
Thanks for your time
You should add model name with field like ModelName.id
$this->paginate['conditions'] = ['ModelName.id IN' => $device_ids];

CakePHP 3 Paginator using FIELD() in ORDER clause

I have a question regarding the Paginator Component of CakePHP3 (3.0.13). I'm using the MYSQL function FIELD() to order my data, like that:
$this->paginate = array_merge_recursive([
'conditions' => [
'zip IN' => $zips
],
'order' => [
'FIELD(zip, '.rtrim(implode(',', $zips), ',').')',
'ispro' => 'desc',
],
$this->paginate
]);
When I apply this to my $this->paginate() it wouldn't be recognized as long as the query param sort is set. To avoid this I remove the sort in my request with:
if (isset($this->request->query['sort'])) {
unset($this->request->query['sort']);
}
This is working, but I was wondering if there is a better solution, maybe in the paginator component itself, which I haven't found yet.
you can sort your query before you paginate it. Your sort conditions will come before the one appended from the paginator component
so you can do
$dentists = $this->Dentists->find()
->order([
'FIELD(zip, '.rtrim(implode(',', $zips), ',').')',
'ispro' => 'desc'
]);
$this->paginate = array_merge_recursive([
'conditions' => [
'zip IN' => $zips
],
$this->paginate
]);
$dentists = $this->paginate($dentists);

yii CActiveDataProvider with limit and pagination

I'm trying to select few rows from the table and render it in multiple pages (pagination).
This is a code in the model:
return new CActiveDataProvider('Downloads',
array(
'criteria' => array(
'select' => 'download_id,title,thumb_ext',
'order' => 'download_id DESC',
'limit' => $count,
),
'pagination' => array('pageSize' => 5,),
)
);
In the view I display it using CGridView:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns' => array('download_id', 'title', 'thumb_ext'),
));
The problem is that CActiveDataProvider ignores limit of criteria and returns all rows of table...
Thanks.
I'm not positive... but I think Yii uses the LIMIT clause to do SQL result pagination, so it will overwrite/replace your LIMIT clause. You can check this by turning on the CWebLogRoute log route to see exactly what SQL is being executed.
I'm not quite sure how this is supposed to work, anyway. What is the LIMIT clause you added for? If you are paginating anyway, why not let the user paginate through all the records? The solution is probably to change your criteria to get rid of the LIMIT clause.
Are you trying to set the number of results per page? You already have the pageSize set to 5 though...
One other thing to try that might do what you want, is to check out the base Pager class, CPagination. With CLinkPager, it might let you paginate more creatively than the CListPager you are using with the CGridView.
Good luck!
I had the same problem and I found a solution as follows:
return new CActiveDataProvider('Downloads',
array(
'criteria' => array(
'select' => 'download_id,title,thumb_ext',
'order' => 'download_id DESC',
),
'pagination' => array('pageSize' => 5,),
'totalItemCount' => $count,
)
);
and set CGridView to pagination is hidden:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'enablePagination' => false,
'columns' => array('download_id', 'title', 'thumb_ext'),
));
One of the basic features of a data provider is that you can override the calculation of the amount of rows by specifying a "totalItemCount" in the config. Normally (I haven't tested it) this also works for the ActiveDataProvider:
return new CActiveDataProvider('Downloads',
array(
'criteria' => array(
'select' => 'download_id,title,thumb_ext',
'order' => 'download_id DESC',
),
'pagination' => array('pageSize' => 5,),
'totalItemCount' => $count,
)
);