I use Laravel 5.3.
I have 2 tables :
Articles
---------
id
cat_id
title
And
Category
---------
id
parent_id
title
Define a articles()
relation in your Category
model as:
public function articles()
{
return $this->hasMany(Article::class, 'cat_id');
}
Then you can try it as:
Category::where('parent_id', 0)->withCount('articles')->get();
This should work:
$category
->where('categories.parent_id', 0)
->leftJoin('article', 'article.cat_id', '=', 'categories.id')
->select('categories.id', \DB::raw('COUNT(article.id)'))
->groupBy('categories.id')
->get();
The above query will get you category IDs and count of all articles that belong to the category.
After reading your question and comments again, if I understand correctly you want to get the count of all articles that belong to those categories (with parent_id = 0) + the count of articles that belong to sub categories (those with parent_id = (id of some category)).
Now I have no way of testing this easily, but I think something along these lines should work for that.
$category
->where('categories.parent_id', 0)
->leftJoin('article', 'article.cat_id', '=', 'categories.id')
->leftJoin('categories as c2', 'c2.parent_id', '=', 'categories.id')
->leftJoin('article as a2', 'a2.cat_id', '=', 'c2.id')
->select('categories.id', \DB::raw('(COUNT(article.id)) + (COUNT(a2.id)) as count'))
->groupBy('categories.id')
->get();
That beign said, I think you're better of having a column named count in categories and update it each time a new article gets added. For performance.
I am sure somebody is still going through this, I was able to solve it the following way, suppose I have an Agent model and a Schedule model, i.e. one agent may have many schedules:
class Schedule extends Model {
public function agent() {
return $this->belongsTo(Agent::class, 'agent_id');
}
}
class Agent extends Model {
public function user(){
return $this->belongsTo(User::class);
}
public function schedules(){
return $this->hasMany(Schedule::class);
}
}
Well some agents may not necessarily have schedules assigned, thus, I filtered those before calling the with()
method, like this:
$agents = Agents::whereIn(
'id',
Schedule::distinct()->pluck('agent_id')
)->with('schedules')->get();
Hope this helps!.
You can use the hasManyThrough()
Eloquent method to fetch all of the childrens' Articles, then add the article counts together in a nice little getter. I added the getter to the $appends
array on the model to help illustrate it in the Tinker output.
class Category extends Model
{
protected $appends = [
'articleCount'
];
public function articles()
{
return $this->hasMany(Article::class);
}
public function children()
{
return $this->hasMany(Category::class, 'parent_id');
}
public function childrenArticles()
{
return $this->hasManyThrough(Article::class, Category::class, 'parent_id');
}
public function getArticleCountAttribute()
{
return $this->articles()->count() + $this->childrenArticles()->count();
}
}
Here's the Tinker output:
Psy Shell v0.8.0 (PHP 7.0.6 — cli) by Justin Hileman
>>> $cat = App\Category::first();
=> App\Category {#677
id: "1",
name: "Cooking",
parent_id: null,
created_at: "2016-12-15 18:31:57",
updated_at: "2016-12-15 18:31:57",
}
>>> $cat->toArray();
=> [
"id" => 1,
"name" => "Cooking",
"parent_id" => null,
"created_at" => "2016-12-15 18:31:57",
"updated_at" => "2016-12-15 18:31:57",
"articleCount" => 79,
]
>>>
If you want to restrict your Category query to ones that have children that have articles, you could do that using the has()
method:
Category::has('children.articles')->get();
Here's more on the has()
method:
https://laravel.com/docs/5.3/eloquent-relationships#querying-relationship-existence
And the hasManyThrough()
method:
https://laravel.com/docs/5.3/eloquent-relationships#has-many-through
you can use withCount()
. It is available from 5.3 version
for more info about eloquent visit : https://laravel.com/docs/5.3/eloquent-relationships