Laravel 5.4 - Cache an array - laravel

I am trying to cache an array, but for some reason, nothing is added. This is the code:
public static function getEmployees()
{
if(!Cache::has('employees')):
$data = ['urlPath' => '/employees/directory'];
$params = ['fields' => 'jobTitle'];
$employees = API::callAPI('GET', $data, $params);
Cache::putMany($employees, 1440);
endif;
return Cache::get('employees');
}
And whey I try to get cached value (array), I am getting null:
dd(Cache::get('employees'));
And this is an array I want to store:
array:2 [▼
"fields" => array:16 [▶]
"employees" => array:257 [▶]
]
(I am using db for storing)

You use putMany() wrong. I bet it'd be sufficient for you need to just use regular put():
Cache::put('employees', $employees, 1440);
but if you want putMany() then you need to prepare source array first, which you are not doing:
$data = [
'fields' => whateverItComesFrom(),
'employees' => API::callAPI('GET', $data, $params),
];
Cache::putMany($data, 1440);
EDIT
As other users mentioned in comments, aside from incorrect usage, the DB storage may also contribute to the issue as, depending on size of the data you want to cache, it may simply exceed database type limits, i.e.
BLOB is just 65535 bytes (64KB) (which suffices for most cases, but you have 200+ entries in array...). MEDIUMBLOB is 16777215 bytes (16 MB) and LONGBLOB for 4294967295 bytes (4 GB), so it may be worth checking that aspect too and change column type if needed.

I have found the issue - the limit of the text field was the reason why cache didn't work. Change the type to LONGBLOB (thanks num8er for advice), and now it is working.

Related

How to add validation for preventing duplicate level points in laravel query?

Here is a table named stages and below are the fields
I don't want to allow to add the same from and to points example, if points from 1 to 10 is already added means not allow them to add the same range, another one condition is don't allow to add in between points example in-between 1to 10 like 5 to 7 are also not allowed.
Tried laravel query
$isexist = Stage::whereBetween('from', [$request->from, $request->to])
->orWhereBetweenColumn('to','from', [$request->from, $request->to])->exists();
but it not satisfying all conditions.
Any one please help, thanks in advance.
you can validate the data like this
$validator = Validator::make($inputData, [
'label' => 'required|unique:tableName,label'
]);
if($validator->fails()){
//Throw validation errors
}
Or you can use
Model::query()->updateOrCreate(['label' => $request->label], [
'from' => $request->from,
'to' => $request->to
]);
Read more on unique validation reference: https://laravel.com/docs/9.x/validation#quick-writing-the-validation-logic

Laravel update chunked result skips rows

I'm trying to convert our database from ID to UUID. When I run the following code to update the database is skips random rows.
AppUser::select('id')->orderBy('created_at')->chunk(1000, function ($appUsers) {
foreach ($appUsers as $appUser) {
$uuid = Str::orderedUuid();
DB::table('files')->where('fileable_type', AppUserInfo::class)->where('fileable_id', $appUser->id)->update([
'fileable_id' => $uuid
]);
DB::table('app_users')->where('id', $appUser->id)->update(['id' => $uuid]);
}
});
Last time i checked ~290 were skipped out of 236196 total.
I've tried to used chunkById, but the same thing happened.
The update function is always returning true, so I must assume that Laravel thinks every row is updated when executed.
There's a big warning in the Laravel documentation on chunking:
When updating or deleting records inside the chunk callback, any changes to the primary key or foreign keys could affect the chunk query. This could potentially result in records not being included in the chunked results.
You'll need to find another way to update your keys in batches. I've used the technique described in an answer to this question: How to chunk results from a custom query in Laravel when I could not use the callback required by the chunk method, although in that case it was not for an update query, only a select.
This is what i ended up doing
$appUsers = AppUser::select('id')->get();
$chunkSize = 1000;
$numberOfChunks = ceil($appUsers->count() / $chunkSize);
$chunks = $appUsers->split($numberOfChunks);
foreach($chunks as $chunk) {
foreach($chunk as $appUser) {
$uuid = Str::orderedUuid();
DB::table('files')->where('fileable_type', AppUserInfo::class)->where('fileable_id', $appUser->id)->update([
'fileable_id' => $uuid
]);
DB::table('app_users')->where('id', $appUser->id)->update(['id' => $uuid]);
}
}

createMany equivalent for updateOrCreate

Is there a createMany equivalent for updateOrCreate in Laravel for when you want to "updateOrCreate" many records in one call?
In other words, is there a sort of updateOrCreateMany function?
From the documentation there doesn't appear to be a function with that name, but maybe there's another friendly Laravel way of doing this... or should I just use a foreach (maybe also using MySQL's insert on duplicate feature)?
Based upon the documentation of Laravel, no there is no method on eloquent like updateOrCreateMany
If you give it a thought, it makes sense because the execution will anyway need to be sequential. As its possible that some entry might affect the previous one so the insertion or updation mode cannot be concurrent. So even if there was some method like that, it would anyway use a loop internally to execute query one by one.
To clear further let's say there was a method updateOrCreateMany which would probably take input like array of arrays like so:
Model::updateOrCreateMany([
[
'email' => 'x#y.com'
],
[
'email' => 'x2#y2.com'
],
[
'email' => 'x#y.com'
]
],
[
[
'name' => 'X Y'
],
[
'name' => 'X2 Y2'
],
[
'name' => 'X Y Updated'
]
]);
As you can see that record 3 is supposed to update the record 1 so basically, you cannot enter all at once by only comparing each with the database image of the insertion time of record1, that way you will enter in error of duplicated email as x#y.com did not exist initially.
Hence, there is no updateOrCreateMany method because it cannot be done concurrent, it needs to be sequential which means some kind of looping mechanism like foreach.
By the way Good Question! +1
Makes sense?
I suggest using a foreach loop on your data and using updateOrCreate method
foreach($records as $record){
Model::updateOrCreate([$record->id, $record->name], [$record->likes, $record->dislikes]);
}

Laravel query different result between (identical?) two vs three argument 'where' clause

I'm having a very odd issue with a query in laravel (5.2) - I've got a collection created from some external source (an API), and I'm trying to run a 'where' query to extract specific records.
Originally, I was trying to extract all entries which were submitted during the current month (so, after the first day of this month)
$entries is the starting collection (time entries on a project - see end of post)
$thisMonthStart = (new Carbon('first day of this month'))->toDateString();
//value of this is 2017-02-01, and the issue is not resolved if I remove toDateString()
$entriesThisMonth = $entries->where('spent-at', '>', $thisMonthStart);
//returns an empty collection, but should have 15 results
Now the really odd part, is that I tried instead to get $entries where 'spent-at' is equal to the first day of the month - there should be one entry. If I don't explicitly specify the comparison operator, I get my expected result:
$entriesThisMonth = $entries->where('spent-at', $thisMonthStart);
//one $entries returned, see end of post
However if I specify the = operator
$entriesThisMonth = $entries->where('spent-at', '=', $thisMonthStart);
//empty collection returned
So I'm now very confused - presumably something is wrong in my original collection, but why does the specifying vs not specifying the operator make any difference? I would have thought that those two queries would give identical results?
(and obviously, not being able to specify the operator is not very helpful when trying to do a < or > comparison, but I'm mostly just interested in what the actual difference is between those two syntaxes, and so why they give different results?)
I couldn't find any info anywhere on how these two versions of the query work and so if it's expected that they could give different results - I would think that they should be identical, but maybe someone with a deeper understanding could explain what's causing this?
Thank you to anyone who can shed some light on the mystery!
A sample of the $entries collection in case is of any use (just a single record):
(NB there are definitely records from the current month, I know this example is too old)
Collection {#952 ▼
#items: array:367 [▼
175412141 => DayEntry {#958 ▼
#_root: "request"
#_convert: true
#_values: array:16 [ …16]
+"id": "175412141"
+"notes": ""
+"spent-at": "2013-10-03"
+"hours": "0.75"
+"user-id": "595841"
+"project-id": "4287629"
+"task-id": "2448666"
+"created-at": "2013-10-03T18:07:54Z"
+"updated-at": "2013-11-01T12:50:51Z"
+"adjustment-record": "false"
+"timer-started-at": ""
+"is-closed": "false"
+"is-billed": "true"
+"started-at": "10:45"
+"ended-at": "11:30"
+"invoice-id": "3633772"
}
And this is what is returned by the where query without the operator:
Collection {#954 ▼
#items: array:1 [▼
568944822 => DayEntry {#1310 ▼
#_root: "request"
#_convert: true
#_values: array:15 [▶]
+"id": "568944822"
+"notes": "Tweaking formatting on job ads and re shuffling ad order"
+"spent-at": "2017-02-01"
+"hours": "0.25"
+"user-id": "595841"
+"project-id": "4287629"
+"task-id": "2448666"
+"created-at": "2017-02-01T14:45:00Z"
+"updated-at": "2017-02-01T14:45:00Z"
+"adjustment-record": "false"
+"timer-started-at": ""
+"is-closed": "false"
+"is-billed": "false"
+"started-at": "14:30"
+"ended-at": "14:45"
}
]
}
To fix your issue... "returns an empty collection, but should have 15 results". If the collection already exists, you need to filter the results. Something like so:
$thisMonthStart = new Carbon('first day of this month');
$entriesThisMonth = $entries->filter(function ($entry) use ($thisMonthStart) {
return $entry['spent-at'] >= $thisMonthStart;
});
The method illuminate\Support\Collection::where is different to the database collection where, it doesn't take an operator as the second argument.
The where method signature to the collection object you are working with is where(string $key, mixed $value, bool $strict = true)
Your second example with the operator is looking for all elements in the collection that match the string '='.
For further reading on the collection you are working with (not an eloquent collection) look here
To get the 15 results that you are expecting, use the filter method on the collection.
Something along these lines should work:
$entriesThisMonth = $entries->filter (function ($e) use ($thisMonthStart) {
return $e ['spent-at'] > $thisMonthStart;
});

Laravel 5 Blade - where condition in count

withing my view I have access to a collection of FoodTypes. I have cast it to an array to make it easier
to display
array:2 [▼
0 => array:7 [▼
"id" => 1
"name" => "Frozen"
"value" => "NOC M1"
]
1 => array:7 [▼
"id" => 2
"name" => "Fresh"
"value" => "NOC A1"
]
]
Initially, I had a Model for each individual FoodType e.g. Frozen and Fresh Models, but I soon discovered that
their tables/data were identical, so it seemed wrong to do this. Now I have a generic Model, with the name defining
the type of food.
Anyways, when I had a Model for each type, it was simple to do a count on the number of particular types. Now however,
I find myself doing something like this
count($data->foodTypes)
The problem is, I need to display the number for each individual type. The above will return 2 because it does not take
the name into consideration. So in essence, I need to do something like the following
count($data->foodTypes->where('name', '=', 'Frozen'))
Would something like this be possible?
Thanks
Yes you can use where.
The method signature from the base collection of eloquent collection:
public function where($key, $value, $strict = true);
That won't go to database again too.
$foods = \App\Foods::all();
$foods->where("food_type_id", 1)->count();

Resources