count relation of relation in laravel

2020-04-12 05:11发布

问题:

Suppose I have a Conversation model like this :

class Conversation extends Model
{
    public function questions (){
        return $this->hasMany('App\Question','conversation_id','conversation_id');
    }
    public function category ()
    {
        return $this->belongsTo('App\Category', 'cat', 'cat_id');
    }

}

And a Question model like this:

class Question extends Model
{
    public function conversation ()
    {
        return $this->belongsTo('App\Conversation', 'conversation_id', 'conversation_id');
    }
}

As you can see there is a hasMany relation between those two.

In the other hand there is a Category like below that has a relation with Conversation model :

class Category extends Node
{
    public function conversations (){
        return $this->hasMany('App\Conversation','cat','cat_id');
    }
}

Now I want to append an attribute named question_count to Category that counts all questions of conversations of each category. for that I added this :

    public function getQuestionsCountAttribute ()
    {
        return $this->conversations->questions->count();
    }

But when fetch a category I got this error :

ErrorException in Category.php line 59:
Undefined property: Illuminate\Database\Eloquent\Collection::$questions

What did I do? how can I count relations of a relation with minimum server overloading?

I am using laravel 5.3.4.

回答1:

I think that you need a has many through relationship here.

What you do wrong:

When you write $this->conversations->questions, this can't work, because the questions are a relation of a single conversation and not of a collection of conversations (here, $this->conversations is a Collection)

The solution:

Using hasManyThrough relation:

You can find the documentation for this relation on this page, if my explanation is bad

The basics are, you need to define a relation on your Category model:

class Category extends Node
{
    public function conversations ()
    {
        return $this->hasMany('App\Conversation');
    }

    public function questions ()
    {
        return $this->hasManyThrough('App\Question', 'App\Conversation');
    }
}

(I will let your look into the documentation for your non standards foreign keys)

You should then be able to use: $category->questions->count()



回答2:

You can count related model with 'withCount' method. https://laravel.com/docs/5.3/eloquent-relationships#counting-related-models



回答3:

$this->conversations contains the collection of conversations. Each of the conversations has its own questions property that contains all related questions for that conversation, however there is no questions attribute on the collection itself that would contain all related questions for that category.

In order to be able to get the count of all the questions in the category, you need to define a hasManyThrough relation that would link questions to the category directly.

First, add the relation to your Category model:

class Category extends Model {
  public function questions() {
    return $this->hasManyThrough('App\Question', 'App\Conversation', 'category_id', 'conversation_id', 'id');
  }
}

Once you have it, you'll be able to get the count of all questions for a category with:

public function getQuestionsCountAttribute ()
{
    return $this->questions()->count(); // if you only need the counter
}