Reputation: 2848
There is a table named requests with a column named status and I have access to this table through a HasManyThrough relation.
The table looks like this:
id | status | request
--------------------------
1 | 1 | lorem ipsum
2 | 2 | lorem ipsum
3 | 1 | lorem ipsum
4 | 3 | lorem ipsum
5 | 1 | lorem ipsum
I need to count all different status rows in an efficient way, the result I'm looking for is something like this:
status | status_count
---------------------
1 | 3
2 | 1
3 | 1
Also I need to be able to do something like this:
$status[1] Or $status->id[1] // which prints out the count of that status
I Know this two option which both of them are ugly:
1. Using filters:
// Through a table named group which contains year column
$requests = Auth::user()->requests()->where('year', 2016)->get();
$status[1] = $requests->filter(
function($request){
return $request->status == 1;
})->count();
Now I have 10 status id, and I should repeat this code 10 times, what if i had 100 status... so it's not a good option.
2. Trying to create a right SQL:
As I know the correct SQL statement for doing this looks like this:
SELECT 'status', COUNT(*) FROM requests GROUP BY status
For creating this statement I'm doing this:
$groups = Group::where(['owner_id' => Auth::user()->id, 'year' => 2016])
->lists('id');
$requests = DB::table('requests')
->select( DB::raw('count(status) as status_count, status') )
->whereIn('group_id', $groups)
->groupBy('status')
->get();
And here is my dd output:
array:2 [▼
0 => {
+"status_count": "3"
+"status": "1"
}
1 => {
+"status_count": "1"
+"status": "2"
}
2 => {
+"status_count": "1"
+"status": "3"
}
]
Which I have no idea how can I use them, for example how can I know what is the count of status 2? I can use a foreach to create an array with status as a key and status_counts as a value but I'm looking fro a right way to do this.
Another thing is how can I create this SQL statement through eloquent and not DB?
Is there any other way that I'm missing?
Upvotes: 5
Views: 9898
Reputation: 2848
Okay, here is what I've did:
First I managed to create a correct SQL only with eloquent and getting the statuses and their count only by 1 request.
Here is the hasManyThrough relation:
public function requests()
{
return $this->hasManyThrough('App\Models\Request',
'App\Models\Group', 'owner_id', 'group_id');
}
Then to get the count of desired requests statuses:
$requests = Auth::user()->requests()->
select( DB::raw('count(requests.status) as count, requests.status') )->
groupBy('requests.status')->where('year', '2016')->get();
Again our result is exactly as we wanted:
status | status_count
---------------------
1 | 3
2 | 1
3 | 1
This time we have two option to work with counts, I go with the new one first:
1. Using where:
// returns null if there is no row with status of 1
$status = $projects->where('status_id', "1")->first();
// if $status is null there is no row with status of 1 so return 0
echo ( empty($status) ) ? 0 : $status->count;
Easy right? but it's not as clean as we want.
2. The foreach trick:
As I mentioned it in my question we can use a foreach to create an array of statuses and their count. but whats happens when we try to get the count of an status which does not exist in the result of our query? we are going to get an error: Undefined offset.
And here is my Idea:
First we will create an array to keep all status codes and their count then we fill this array with zero.
My system only has 10 status code so:
$requests_counts = array_fill(1, 10, 0); // status 1 to 10 - default count: 0
Then with a foreach statement we only override the indexs that have a count in our query result:
foreach($requests as $request)
$requests_counts[$request->status] = $request->count;
So all status codes going to have a value even the ones that are not exist in our query result.
*Count of all status codes
But what if we want to print out the number of all requests no matter what status code they have? should we create an other query and count all the results rows? nope we are going use a function named array_sum:
array_sum($requests_counts); // prints out number of all requests
Upvotes: 4
Reputation: 9749
$groups = Group::where(['owner_id' => Auth::user()->id, 'year' => 2016])
->groupBy('status')
->select( DB::raw('status , COUNT(*) as status_count') )
->get();
Upvotes: 1
Reputation: 4620
I would stick to your second option with little tweak.
$groups = Group::where(['owner_id' => Auth::user()->id, 'year' => 2016])
->lists('id');
$requests = DB::table('requests')
->select( DB::raw('count(status) as status_count, status') )
->whereIn('group_id', $groups)
->groupBy('status')
->get();
$output = [];
foreach ($requests as $a)
{
$output[$a->status] = $a->status_count;
}
Then in your ouput you have $output[1]
count for status 1 etc...
Upvotes: 0