Laravel - Sortby date after GroupBy callback - laravel

I'm creating a collection and using a groupBy to group items together depending on the month, however after this I then want to it to go back to ascending date order (Jan/Feb/Mar). Here is my function that I'm using below;
private function monthByMonthAgentReferrals() {
$case = Case::where('start_date', '>', Carbon::now()->subDays(360))
->where('source', 'AGENT')->get()
->groupBy(function($key) {
return Carbon::parse($key->start_date)->format('m');
});
return $case;
}
At the moment when I display the results I get a return of the months in a random order;
Collection {#1982 ▼
#items: array:12 [▼
12 => Collection {#1321 ▶}
"07" => Collection {#1322 ▶}
10 => Collection {#1320 ▶}
"05" => Collection {#1991 ▶}
"06" => Collection {#1990 ▶}
"08" => Collection {#1989 ▶}
"01" => Collection {#1988 ▶}
11 => Collection {#1987 ▶}
"09" => Collection {#1986 ▶}
"02" => Collection {#1985 ▶}
"03" => Collection {#1984 ▶}
"04" => Collection {#1983 ▶}
]
}
How would I go about sorting by 'start_date' again? or would it be better to sort by the array key? Thanks.

You can use it like this:
$case = Case::where('start_date', '>', Carbon::now()->subDays(360))
->selectRaw('table_name.*')
->where('source', 'AGENT')
->groupBy(function($key) {
return Carbon::parse($key->start_date)->format('m');
})->orderBy('start_date')->get();

private function monthByMonthAgentReferrals() {
$case = Case::where('start_date', '>', Carbon::now()->subDays(360))
->where('source', 'AGENT')->get()
->groupBy(function($key) {
return Carbon::parse($key->start_date)->format('m');
})->toArray();
ksort($case);
return collect($case);
}
Converts the collection to an array, use the function ksort on the array and then recollect the array.

Related

Laravel resource ignoring given fields

I'm trying to convert a given API response in something easy to work with.
This is what I have so far:
Controller:
public function drive()
{
$optParams = [
'corpora' => 'drive',
'driveId' => env('GOOGLE_DRIVE_ID'),
'includeItemsFromAllDrives' => true,
'supportsAllDrives' => true,
'fields' => 'files(*)'
];
$results = $this->googleDrive->files->listFiles($optParams);
$data = collect($results);
$collection = new FileCollection($data);
dd($collection);
return 'Hi!';
}
FileCollection resource:
public function toArray($request)
{
return [
'data' => $this->collection,
'meta' => ['files_count' => $this->collection->count()],
];
}
File resource:
public function toArray($request)
{
return [
'name' => $this->resource['name'],
'mime' => $this->resource['mimeType'],
'parents' => $this->resource['parents'],
'version' => $this->resource['version'],
'webDownloadLink' => $this->resource['webContentLink'],
'webLink' => $this->resource['webViewLink'],
'modified_at' => $this->resource['modifiedTime'],
'size' => $this->resource['size']
];
}
This is the result I'm getting:
FileCollection {#223 ▼
+collects: null
+collection: Collection {#243 ▶}
+resource: Collection {#243 ▼
#items: array:2 [▼
0 => File {#224 ▼
+resource: Google_Service_Drive_DriveFile {#279 ▶}
+with: []
+additional: []
}
1 => File {#263 ▼
+resource: Google_Service_Drive_DriveFile {#269 ▶}
+with: []
+additional: []
}
]
}
+with: []
+additional: []
}
So as you can see the types of resources are correct, but for some reason the 'meta' in the FileCollection isn't there, nor are the fields in the File resource. All fields are still shown, like 30+ (instead of the 8 requested in the FileResource).
Am I missing something here?
EDIT:
When accessing the collection with the toArray() method ($collection->toArray(null)), I do indeed get the appropriate result:
array:2 [▼
"data" => Collection {#243 ▼
#items: array:2 [▼
0 => File {#224 ▶}
1 => File {#263 ▶}
]
}
"meta" => array:1 [▼
"files_count" => 2
]
]
So how do I make sure now that this collection uses the toArray() of the FileResources? (I'm still getting over 30 fields, instead of 8).
PS: I don't really get why I need to call the toArray(), nowhere in their documentation is it written : https://laravel.com/docs/5.8/eloquent-resources .

How to get the common values from 2 Laravel collections

I have 2 Collections in Laravel, and I want only common values in my $result object. I see that $collection->intersect() works only for 1D array.
Below are the collections
Collection {#1086 ▼
#items: array:5 [▼
0 => {#1115 ▼
+"name": "Light"
+"class": "ABC"
+"id": 4
}
1 => {#1113 ▼
+"name": "Milo"
+"class": "XYZ"
+"id": 10
}
2 => {#1120 ▼
+"name": "Milo Test"
+"class": "ABC"
+"id": 12
}
3 => {#1102 ▼
+"name": "KMSMiloCow"
+"class": "ABC"
+"id": 16
}
4 => {#1106 ▼
+"name": "MiloCows"
+"class": "XYZ"
+"id": 18
}
]
}
Collection {#1086 ▼
#items: array:5 [▼
0 => {#1115 ▼
+"name": "Light"
+"class_name": "ABC"
+"id": 4
}
]
}
Now in my result, I just need this
Collection {#1086 ▼
#items: array:5 [▼
0 => {#1115 ▼
+"name": "Light"
+"class": "ABC"
+"id": 4
}
]
}
I have no idea this would help you or not but these will be useful
$common_collection = $collection_1->whereIn('id', $collection_2->pluck('id')->toArray())
->unique('id')
->sortBy('id');
To get a collection with common elements, you can use filter():
The filter method filters the collection using the given callback, keeping only those items that pass a given truth test
$commonCollection = $collection1->filter(function ($value, $key) use ($collection2){
return $collection2->contains($value);
});
I think using collection method each and contains, it can be done like this
$collection1->each(function ($value, $key) use ($collection2){
return $collection2->contains($value);
});
dd($collection1);
I test it in routes file web.php like
use Illuminate\Support\Collection;
Route::get('test', function(){
$collection1 = new Collection([
'bear',
'whale',
'chicken',
'tardigrade'
], [[
'bear8',
'whale44',
'chicken45',
'tardigrade445'
]]);
$collection2 = new Collection([
'bear1',
'whale2',
'chicken3',
'tardigrade4'
], [[
'bear',
'whale',
'chicken',
'tardigrade'
]]);
$collection1->each(function ($value, $key) use ($collection2){
return $collection2->contains($value);
});
dd($collection1);
});
use intersect https://laravel.com/docs/9.x/collections#method-intersect
for example:
$commonValues = $collection1->pluck("id")->intersect($collection2->pluck("id"));
dd($commonValues);
Then get common collections
dd($collection1->whereIn("id", $commonValues));
try this
$a1 = array(
array('name' => 'asdfjkl;', 'class' => 'foo'),
array('name' => 'qwerty', 'class' => 'bar'),
array('name' => 'uiop', 'class' => 'baz'),
);
$a2 = array(
array('name' => 'asdfjklk;', 'class' => 'foo'),
array('name' => 'qwertyxs', 'class' => 'bar'),
array('name' => 'uiop', 'class' => 'baz'),
);
$cc = array_uintersect($a1, $a2, 'cmp');
print_r($cc);
function cmp($a1, $a2){
return strcasecmp($a1['name'] , $a2['name']);
}

How to transpose this into an array?

I am trying to transpose a Collection into an array. I'm not sure what's the method to do this. I think it's due to my lack of understanding in the eloquent operators/commands. I've been trying with map but had not made any headway.
Data
Collection {#911 ▼
#items: array:4 [▼
"HIGH" => Collection {#902 ▼
#items: array:2 [▼
0 => Finding {#680 ▶}
1 => Finding {#681 ▶}
]
}
"MEDIUM" => Collection {#903 ▶}
"LOW" => Collection {#904 ▶}
"INFO" => Collection {#905 ▶}
]
}
I would like to transpose this into an array ['HIGH' => 2, 'MEDIUM' => 1, 'LOW' => 13 ...]
I tried to apply a map but it's not giving me what i want. (tried applying the below)
... ->map (function ($risk) { return $risk[0]; });
Looking for tips on learning about these map operators and also how to transpose the Collection result above. Any help will be the most welcome!
Use toArray function to convert the collection to the array
$collection = collect(['name' => 'Desk', 'price' => 200]);
$collection->toArray();
Hope this link helps you.
https://laravel.com/docs/5.7/collections#method-toarray

adding multiple scopes to nested eager loading

In my application users can predict scores of upcoming soccer games.
Basically I want to display all the user predictions for this week. I do this by adding a scope to my match model that only loads matches from this week.
Problem: I'm still getting all my predictions from that user (not only the ones from the current week) For predictions that my user created this week, the correct match is loaded. For the other predictions there is no match but they still get put in my query.
How can I add another scope to my nested eager loading that will only select predictions made during this week or have a match that is not null? (or other solution)
Code:
public function showPredictions() {
$user = auth()->user()->load(['predictions.match' => function ($query) { $query->thisWeek();}]);
dd($user);
return view('predictions', compact('user'));
}
Match model
public function Predictions() {
return $this->hasMany('App\Prediction', 'match_id', 'match_id');
}
public function scopeThisWeek($query) {
$start_date = now()->previous(Carbon::TUESDAY);
$end_date = now()->next(Carbon::MONDAY);
return $query->whereDate('date','>', $start_date)->whereDate('date','<', $end_date);
}
output
#relations: array:1 [▼
"predictions" => Collection {#265 ▼
#items: array:29 [▼
0 => Prediction {#268 ▶}
1 => Prediction {#269 ▶}
2 => Prediction {#270 ▶}
3 => Prediction {#271 ▶}
4 => Prediction {#272 ▶}
5 => Prediction {#273 ▶}
6 => Prediction {#274 ▶}
7 => Prediction {#275 ▶}
8 => Prediction {#276 ▶}
9 => Prediction {#277 ▶}
10 => Prediction {#278 ▶}
11 => Prediction {#279 ▶}
12 => etc...
]
Output I want to achieve (I have 10 predictions for each user that week)
#relations: array:1 [▼
"predictions" => Collection {#265 ▼
#items: array:10 [▼
0 => Prediction {#268 ▶}
1 => Prediction {#269 ▶}
2 => Prediction {#270 ▶}
3 => Prediction {#271 ▶}
4 => Prediction {#272 ▶}
5 => Prediction {#273 ▶}
6 => Prediction {#274 ▶}
7 => Prediction {#275 ▶}
8 => Prediction {#276 ▶}
9 => Prediction {#277 ▶}
10 => Prediction {#278 ▶}
]
I have a relation field in my predictions array with the correct match in.
Use whereHas():
$user = auth()->user()->load([
'predictions' => function ($query) {
$query->whereHas('match', function ($query) {
$query->thisWeek();
});
},
'predictions.match'
]);

Instead an element in a Laravel Colletion each 3 elements

I have a collection with 4 Object :
Collection{#645 ▼
#items: array:4 [▼
0 => Team {#644 ▶}
1 => Team {#613 ▶}
2 => Team {#607 ▶}
3 => Team {#599 ▶}
]
}
I would like to insert a element each 3, begining by 0 index ( In this case, it would be in 0, and 3)
How should I do it???
The push method doesn't allow me to insert between to elements....
Use the map() helper. I've tested this and it works perfectly:
$counter = 0;
$collection->map(function($i) use(&$counter) {
if ($counter % 3 === 0) {
$i->custom = 'Custom value';
}
$counter++;
return $i;
});

Resources