How to limit number of result in pagination? - limit

This is my action:
public function index()
{
$this->paginate = [
'page' => 1,
'limit' => 12,
'maxLimit' => 12
];
$suppliers =$this->Suppliers->find('all')
->order(['Suppliers.description'=>'asc']);
$suppliers = $this->paginate($suppliers);
$this->set(compact('suppliers'));
$this->set('_serialize', ['suppliers']);
}
No matters value I put on limit, max limit.. he always give me all record from my database...

Related

Attempt to read property post_id on int

I have a small response from db model, and i colud rebase it and response in route, but i see error.
My Controller:
class PostController extends Controller {
public function getLastRecord() {
$lastRec = Post::latest('created_at')->first();
$res = [];
$res = collect($lastRec)->map(function($record) {
return [
'id' => $record->post_id,
'rec_name' => $record->post_name,
'user' => $record->user_id,
];
})->toArray();
return $res;
}
}
I want that response will be array
['id': 1, 'rec_name': 'test_name', 'user': 1]
instead names from db
['post_id': 1, 'post_name': 'test_name', 'user_id': 1]
Error:
Attempt to read property "post_id" on int
When you collect() a single Record, then call ->map() (or other iterative methods), it loops over your Model's columns, not multiple Post records. You can solve this by wrapping $lastRec in an array, or using ->get() instead of ->first():
$lastRec = Post::latest('created_at')->first();
return collect([$lastRec])->map(function($record) {
return [
'id' => $record->post_id,
'rec_name' => $record->post_name,
'user' => $record->user_id,
];
})->toArray();
// OR
$lastRecs = Post::latest('created_at')->get();
return $lastRecs->map(function ($record) {
return [
'id' => $record->post_id,
'rec_name' => $record->post_name,
'user' => $record->user_id,
];
})->toArray();
Or, since this is a single record (using ->first() only ever returns 1 record), you don't need to collect() or map() at all:
$lastRec = Post::latest('created_at')->first();
return [
'id' => $lastRec->post_id,
'rec_name' => $lastRec->post_name,
'user' => $lastRec->user_id
];

Relationship laravel : count data

Model Category:
public function product()
{
return $this->hasMany(products::class);
}
Model product:
public function category()
{
return $this->belongsTo(Category::class);
}
I handle in controller:
$result = Category::select(['id', 'name'])
->with(['product:category_id, status'])
->where('order', 1)
->get();
Result when I print out raw data :
[
'id' => 1,
'name' => 'Hot'
'product' => [
'status' => 1,
'category_id' => 1
]
]
[
'id' => 2,
'name' => 'New'
'product' => [
'status' => 2,
'category_id' => 2
]
]
..........
I got the list of category id and name, and got the product data array based on relationship. In my product table, There is a status column with values ​​equal to 1,2,3.
Now I want to count how many status = 1 and how many status = [2, 3] through the product array I get using that relationship?
you can use withCount for counting related data. lets say, you want total products, status1 products and status23 products.
$result = Category::select(['id', 'name'])
->with(['product:category_id, status'])
->withCount([
'product',
'product as status_one_product' => function ($query) {
$query->where('status', 1);
},
'product as status_other_product' => function ($query) {
$query->whereIn('status', [2, 3]);
}
])
->where('order', 1)
->get();
now you can get counted data like
echo $result[0]->product_count; // total product
echo $result[0]->status_one_product; // total product with status 1
echo $result[0]->status_other_product; // total product with status 2 and 3

Why i can't create fake data with faker when i use the unique method

I try to create fake data for a todo app project so i use factory for to do that
i use on the for the category Model this :
$factory->define(Category::class, function (Faker $faker) {
return [
'name' => $faker->name,
'order' => $faker->unique()->randomDigitNotNull,
];
});
and when i use tinker everything works perfectly but when i to the task model
$factory->define(Task::class, function (Faker $faker) {
return [
'category_id' => $faker->numberBetween($min = 1, $max = 6),
'name' => $faker->name,
'description' => $faker->text($maxNbChars = 200),
'satus' => $faker->boolean,
'expired_at' => $faker->dateTime($max = 'now'),
'order' => $faker->unique(true)->numberBetween(1, 50),
];
});
i receive an error
"OverflowException with message 'Maximum retries of 10000 reached without finding a unique value'" and i don't know why its not working
This works
for ($i = 1; $i < 10; $i++) {
$faker->unique()->randomDigitNotNull;
}
When you increase 10 to any value(12, 15, 25); it is going to give an exception because of the implementation of randomDigitNotNull method.
public static function randomDigitNotNull()
{
return mt_rand(1, 9);
}
Since you are saying unique and the method will return you a value in that range [1,9]. if your loop iterates more than 9 times than at least one value will not be unique.

Laravel5.5 adding columns to a collection from a second one

I have a sql request concerning admin :
$admin = Admin::findOrFail(Auth::guard('admin')->user()->id);
from this sql request I also manage to get the users of the admin ...
$users = $admin->users;
Each users must follow training sessions. and I must calculate it by using SQL requests for each users ... So i wrote this foreach statement
foreach ($users as $user) {
$todo = User::select() .....where('users.id' = $user->id)->get();
$done = User::select() .....where('users.id' = $user->id)->get();
$totalTimes = $todo->toBase()->sum('dureeformation');
$spendTimes = $done->toBase()->sum('dureeformation');
$remainingTimes = $totalTimes - $spendTimes;
$timeData[] = ['id' => $user->id, 'totalTime' => $totalTimes, 'spendTime' => $spendTimes, 'remainingTime' => $remainingTimes];
}
the totalTimes, spendTimes and remainingTimes are operations on Collections and i get expected results ...
$users->each(function ($record) use ($timeData) {
$record['totalTime'] = $timeData[$record['id']]['totalTime'];
$record['spendTime'] = $timeData[$record['id']]['spendTime'];
$record['remainingTime'] = $timeData[$record['id']]['remainingTime'];
//dd($record['totalTime']);
});
After this :
$timeData = collect($timeData);
$timeData= $timeData->keyBy('id');
$users = collect($users->toArray());
I have an issue here :
$users->each(function ($record) use ($timeData) {
$record['totalTime'] = $timeData[$record['id']]['totalTime'];
$record['spendTime'] = $timeData[$record['id']]['spendTime'];
$record['remainingTime'] = $timeData[$record['id']]['remainingTime'];
//var_dump($record);
});
$record in the function gives me what i expect ... the var_dump($records) added columns where it was expected but i can't take those results out of the function.
I tried to do this :
$variable = $users->each(function ($record) use ($timeData)...
dd($variable)
but unsuccessfully ...
Looks to me like your $timeData array is built differently than you access it. In your code you are doing
$timeData[] = [
'id' => $user->id,
'totalTime' => $totalTimes,
'spendTime' => $spendTimes,
'remainingTime' => $remainingTimes,
];
which will produce an array like this
[
0 => [
'id' => 17,
'totalTime' => 5,
'spendTime' => 4,
'remainingTime' => 3
],
1 => [
'id' => 17,
'totalTime' => 7,
'spendTime' => 5,
'remainingTime' => 2
]
]
but what you actually want is to have the id as index, right? Then you'd have to build the array this way:
$timeData[$user->id] = [
'totalTime' => $totalTimes,
'spendTime' => $spendTimes,
'remainingTime' => $remainingTimes,
];
or, as an alternative, perform a different lookup:
$users->each(function ($record) use ($timeData) {
$times = array_first($timeData, function ($value, $key) use ($record) {
return $value['id'] === $record['id'];
});
$record['totalTime'] = $times['totalTime'];
$record['spendTime'] = $times['spendTime'];
$record['remainingTime'] = $times['remainingTime'];
});
Both solutions have pros and cons, though. On the one hand, using the user identifier as the index will produce a huge array that is only filled partially. On the other hand, the second solution is a bit slower. As long as you are not going to deal with thousands of entries in the $timeData array, this won't be an issue, though.

Cakephp 3 Dynamic limit parameter when using contain

CakePHP Version 3.5.5
My end goal is to provide the user the functionality to change the amount of results displayed via a select list on the index view. Also I need the initial page load to be sorted by area_name asc.
// WHAT I'VE DONE
I changed where I was stipulated the limit parameter which can be seen below.
// AREAS CONTROLLER
public $paginate = [
'sortWhitelist' => [
'Areas.area_name', 'Users.first_name', 'Users.last_name'
]
//'limit' => 1, // REMOVED FROM HERE
//'order' => [ // REMOVED FROM HERE
//'Areas.area_name' => 'asc'
//]
];
public function index()
{
$query = $this->Areas->find('all')
->contain([
'Users'
])
->where(['Areas.status' => 1]);
$limit = 1;
$this->paginate = [
'order' => ['Areas.area_name' => 'asc'], // ADDED HERE
'limit' => $limit // ADDED HERE
];
$this->set('areas', $this->paginate($query));
}
And I declare the pagination sort links like:
// AREAS INDEX VIEW
<?= $this->Paginator->sort('Areas.area_name', __('Area Name')) ?>
<?= $this->Paginator->sort('Users.first_name', __('First Name')) ?>
<?= $this->Paginator->sort('Users.last_name', __('Last Name')) ?>
// RESULT
The above code works on all index methods within the application that don't use contain but when I implemented this solution here everything worked except I cannot sort on the associated data - IE: Users first and last name?
=========================================================================
WHAT I'VE TRIED
// Attempt 1
I added an initialize method above the public $paginate class like:
public function initialize()
{
$limit = 1;
}
public $paginate = [
'sortWhitelist' => [
'Areas.area_name', 'Users.first_name', 'Users.last_name'
]
'limit' => $limit,
'order' => [
'Areas.area_name' => 'asc'
]
];
public function index()
{
$query = $this->Areas->find('all')
->contain([
'Users'
])
->where(['Areas.status' => 1]);
$this->set('areas', $this->paginate($query));
}
And the view I left the same.
// Result for Attempt 1
syntax error, unexpected ''limit'' (T_CONSTANT_ENCAPSED_STRING), expecting ']' on line 36 which is 'limit' => $limit,
=========================================================================
// Attempt 2
I tried to add the limit parameter and order array to the query like:
public function index()
{
$limit = 1;
$query = $this->Areas->find('all')
->contain([
'Users'
])
->where(['Areas.status' => 1])
->order(['Areas.area_name' => 'asc'])
->limit($limit);
$this->set('areas', $this->paginate($query));
}
// Result for Attempt 2
The result set was not ordered by the area_name and not limited to 1 result.
=========================================================================
// Attempt 3
I then changed the query and tried the following just to see if I could get a dynamic limit working:
$limit = 1;
$query = $this->Areas->find('all')
->contain('Users', function ($q) {
return $q
//->order('Areas.area_name' => 'asc'),
->limit($limit);
})
->where(['Areas.status' => 1]);
$this->set('areas', $this->paginate($query));
// Result for Attempt 3
The result set was not limited to 1 result.
=========================================================================
ADDITIONAL INFORMATION
// USERS TABLE
$this->hasOne('Areas', [
'foreignKey' => 'user_id'
]);
// AREAS TABLE
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
I searched through the following cookbook sections (Pagination, Query Builder, Retrieving Data & Result Sets and Associations - Linking Tables Together) but I can't find a way to get this working so any help would be much appreciated.
Many thanks. Z.
You are overwriting the $paginate property in your index() method, so your settings including the whitelist are being lost.
Set the keys directly instead:
$this->paginate['order'] = ['Areas.area_name' => 'asc'];
$this->paginate['limit'] = $limit;

Resources