laravel 4 eloquent eager load relation count

2019-02-11 09:43发布

I have a complex Model with multiple defined relations. In this example I would want to count the Like model and create a property named likes so it can be returned from a REST service.

Is it possible to eager load a model count into a dynamic property?

$beat = Post::with(
         array(
            'user',
            'likes' => function($q){
                $q->count();
            }
        ))
        ->where('id', $id)
        ->first();

2条回答
家丑人穷心不美
2楼-- · 2019-02-11 10:18

You should use the SQL Group By statement in order to make it works. You can rewrite your query like the following one.

$beat = Post::with(
         array(
            'user',
            'likes' => function($q) {
                // The post_id foreign key is needed, 
                // so Eloquent could rearrange the relationship between them
                $q->select( array(DB::raw("count(*) as like_count"), "post_id") )
                  ->groupBy("post_id")
            }
        ))
        ->where('id', $id)
        ->first();

The result of likes is a Collection object with one element. I'm assuming the relationship between model Post and Like is Post hasMany Like. So you can access the count like this.

$beat->likes->first()->like_count;

I'm not tested code above but it should works.

查看更多
在下西门庆
3楼-- · 2019-02-11 10:38

Assuming you are having Post->hasMany->Like relationship and you have declared likes relationship as:

class Post{

  public function likes(){
   return $this->hasMany('Like');
  }
}

create a new function say likeCountRelation as:

public function likeCountRelation()
{
    $a = $this->likes();

    return $a->selectRaw($a->getForeignKey() . ', count(*) as count')->groupBy($a->getForeignKey());
}

now you can override __get() function as:

public function __get($attribute)
{

    if (array_key_exists($attribute, $this->attributes)) {
        return $this->attributes[$attribute];
    }

    switch ($attribute) {

        case 'likesCount':
            return $this->attributes[$attribute] = $this->likesCountRelation->first() ? $this->likesCountRelation->first()->count : 0;
            break;

        default:
            return parent::__get($attribute);

    }
}

or you can use getattribute function as :

public function getLikesCountAttribute(){
 return $this->likesCountRelation->first() ? $this->likesCountRelation->first()->count : 0;
}

and simply access likesCount as $post->likesCount you can even eager load it like:

$posts=Post::with('likesCountRelation')->get();
 foreach($post as $post){
  $post->likesCount;
 }

NOTE: Same logic can be used for morph many relationships.

查看更多
登录 后发表回答