Laravel: sorting collection by last name in single string - php

i'm trying to sort a collection, which consists of ids and full names, alphabetically by the last name.
the id comes from a parent class and the full name from the child.
I tried exploding the string and ordering according to the last name, but couldn't really get it to also reorder th IDs properly.
I tried both with sortBy while getting the collection and with usort after retrieving it
$testExaminers=TestExaminer::where('test_id',$request->testid)
->with('examiner')
->get()
->sortBy('examiner.name');
$result = array();
$num=0;
foreach($testExaminers as $testExaminer) {
$result[$num]['id'] = (int) $testExaminer->examiner_id;
$result[$num]['text'] = $testExaminer->examiner->name;
$num++;
}
echo json_encode(['examiners'=>$result]);
The code above works fine for sorting it by first name, but I need it to sort by last name.
user inputs test_id, which gives a list of "TestExaminers", each has a property "examiner_id" associated with a unique "examiner", which in turn has a name "firstname middlename lastname".
so it should look something like this
before sort
$result = [[1,'Alpha Z. Goodman'],[2,'Joe Bman'],[3,'ZZ Top'],[4,'Joe Aman']]
after sort
$result = [[4,'Joe Aman'],[2,'Joe Bman'],[1,'Alpha Z. Goodman'],[3,'ZZ Top']]
Thanks!

How about trying something like this?
$testExaminers = TestExaminer::where('test_id', $request->testid)
->with('examiner')
->get()
->map(function ($item, $key) {
$item->examiner->last_name = array_slice(explode(' ', $item->examiner->name), -1)[0];
return $item;
})
->sortBy('examiner.last_name');

Related

how to compare two collection and get match records

I am using Laravel and I have two different collections that contain ID of products
First one is colorProduct and second is tagProduct
so I want to compare these two and get only same ID of products so how can I do this?
$colorProducts = Color::where('code', $request->color)->get()->first()->products;
$tagProducts = $tag->products->where('shop_id', $shop->id);
$colorAndTagProducts = collect();
foreach ($colorProducts->toBase()->merge($tagProducts)->unique('id')->groupBy('id') as $allProducts) {
if ($allProducts->count() >= 1) {
$colorAndTagProducts[] = $allProducts->first();
}
}
here
$colorAndTagProducts
gives me all records form both collection but I only want same record
I dont know, if I understand correctly, but maybe like this?
I suppose Color and Product are in many to many relationship. And Product and Shop/tag in one to many.
$colorId = Color::where('code', $request->color)->get()->first()->id;
$shopId = $shop->id;
$products = Product::whereHas('colors', function ($query) use ($colorId) {
$query->where('id', $colorId); //id or color_id
})->where('shop_id', $shopId)->get();
intersect()
The intersect method removes any values from the original collection
that are not present in the given array or collection. The resulting
collection will preserve the original collection's keys:
I did it with this method

How to get count of each result

How can I get the total number of records for each of the grouped column(some_id) results generated in this eloquent query? (Answers generated using DB query builder or vanilla PHP also welcome).
$results = \App\MyModel::groupBy('some_id')
->whereNotNull('some_id')
// some query here to get sum of each grouped column records
->get();
The desired result would be such that when I'm looping through the results, I can also have a field called for example totalRecords for each grouped results. i.e.
foreach($results as $result) {
echo $result->totalRecords;
}
$results = DB::table('your_table')
->select('some_column_name', DB::raw('count(some_id) as totalRecords'))
->whereRaw('some_id IS NOT NULL')
->groupBy('some_id')
->get();
You can do like this :-
$results = \App\MyModel::select('*', DB::raw('count(some_id) as totalRecords'))
->groupBy('some_id')
->whereNotNull('some_id')
->get();
foreach ($results as $result) {
echo $result->totalRecords;
}
Collection Provide itself count() method.
But sometime once you fetch whole collection using get(). You can use count method on collection something like this:
$results = \App\MyModel::groupBy('some_id')
->whereNotNull('some_id')
// some query here to get sum of each grouped column records
->get();
dd($results->count());
Also, If your data is not collection then Php array's provide you count method you can use that too:
dd(count($results));
I used dd method just for debuging purpose.That will show you result before actual output.
count() method of array will help you to count collection as well as sub collection or array of sub array.
Good luck !!!

Combine two queries into one and sort them

I am trying to display buildings and circuits in list (only 3 in total, sorted by the column "updated_at"). The problem is that they are not in the same table. I have a table circuits and a table buildings.
I tried to do this:
$buildings = Building::published()->limit(3)->get();
$circuits = Circuit::published()->limit(3)->get();
$merged = $buildings->merge($circuits);
$this->data['buildingsAndCircuits'] = $merged->all();
I get everything right when I'm doing my var_dump and I know how to access the data when I do a foreach. But that does not do what I want.
I would like to sort them (by updated_at) and have only three and not six.
Is there a way to do that?
I tried to make conditions like with the QueryBuilder on $merge but it does not work
$this->data['buildingsAndCircuits'] = $merged->orderBy('updated_at', 'DESC')->limit(3)->all();
thank you very much
Once you've called get on each query then the query is executed and the result is returned. orderBy will not longer work after that since what you have in $buildings, $circuits and $merged is a collection.
You can however do this:
$buildings = Building::published()->limit(3)->get();
$circuits = Circuit::published()->limit(3)->get();
$merged = $buildings->merge($circuits)->sortByDesc('updated_at');
$this->data['buildingsAndCircuits'] = $merged->all();
Check what else you can do on collections in the documentation

Retrieving items Based on multiple IDS in Laravel

I have a relationship between employees and items. It's a one-to-many relationship (i.e employee can have many items).
For instance, there are two employees Mark and Bill.
Mark bought items with item_no 1-0234, 1-0235 respectively.
Bill bought items with item_no 1-0236, 1-0237 respectively.
Item numbers are unique and therefore can be used to find the customer who is in possession.
This is my code to find customers items belong to. I select ids of all items using a checkbox.
What I am looking to achieve is, I want to find all employees based on the item selected, retrieve the phone numbers and item_nos using explode and process a message to them.
Controller
<?php
public function processMessage(Request $request)
{
$ids = $request->ids; // i am able to get the item_nos selected, eg. 1 - 0234, 1 - 0236
$split = explode(",", $ids);
if (request()->ajax()) {
$employees = Employee::whereHas('items', function ($emp) use ($split) {
$emp->where('id', $split);
})->get();
$get_name = [];
$get_phone = [];
foreach ($emps as $key => $emps) {
$get_name[] = $emps->name;
$get_phone [] = $emps->phone;
}
}
return ['success' => $get_phone];
}
PS: in the code, imagine i have selected two items with item_nos 1-0234, 1-0236. That is, my code should return two phone numbers, i.e for Mark and Bill but it returns just one of them, which is Mark's. Why is this happening
If i correct, following should help inside your query function-
$emp->whereIn('id',$split);

Laravel whereIn list values not found in query?

When building a query to find multiple values from a model, eloquent would look something like this:
return Contact::whereIn('user_name', explode(',', $userNames)
But let's say that the value for userNames is ['foo', 'bar']; but I only have foo as a valid username, is there a way to get bar (all failed to find) out as part of the same query without having to compare the result ->get() against the request?
It's not possible to get the query to return the list of username that doesn't exist from the given condition. But you could do this.
$allUserNames = explode(',', $userNames);
$validUserNames = Contact::whereIn('user_name', $allUserNames)
->pluck('user_name')
->toArray();
$invalidUserNames = array_values(array_diff($allUserNames, $validUserNames));
You can use array diff to remove the unvalid value form the select region, and you lost the ->get() to get the results;
return Contact::whereIn('user_name', array_diff(explode(',', $userNames, ['bar']))->get()

Categories