Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel 4.1 Eager Loading Nested Relationships with Constraints

I am trying to get Eager-Loading nested relationships, with constraints, to work. Everyone seems to be giving the same example of eager-loading nested relationships:

$users = User::with('posts.comments')->get();

What I want to do instead is get all the the Users related to a post of a given id. But at the same time, I also want to get the comments associated with that post.

In 4.1, I to achieve the latter, I could do:

$comments = Comment::whereHas('post', function($query) { $query->whereId(1); })->get();

Is there a way to marry this two and constrain a nested relationship?

like image 459
kJamesy Avatar asked Apr 04 '14 16:04

kJamesy


2 Answers

Actually found it a lot simpler than thought.

Given these models:

class User extends \Eloquent {

    public function posts()
    {
        return $this->hasMany('Post');
    }

    public function comments()
    {
        return $this->hasManyThrough('Comment', 'Post');
    }       

}

class Post extends \Eloquent {

    public function user()
    {
        return $this->belongsTo('User');
    }

    public function comments()
    {
        return $this->hasMany('Comment');
    }       

}

class Comment extends \Eloquent {

    public function post()
    {
        return $this->belongsTo('Post');
    }

}

We can then fetch a user that has a given post like so:

$userId = 2; $postId = 5;
$user =  User::with(['comments' => function($q) use($postId) { $q->where('post_id', $postId); }])->find($userId);

This won't work when using get() as it DOES NOT constrain the users to only those related to the given post. But this is OK since we are only interested in a single post of post_id $postId. Since a post belongsTo one and only one user, we needn't worry about the other users. We could therefore use find() or first() to get the actual results.

Also, the 'middle' relationship i.e. 'post' is automatically returned and we can get it by doing the following without having to use an extra 'with' as suggested in previous answer:

var_dump($user->posts);
like image 114
kJamesy Avatar answered Oct 17 '22 07:10

kJamesy


If the relations in the models are correct you can simply do:

$user = User::with('posts.comments')->get();

You can add as many relations as you want ( or up to the memory limit ;)).

It also works with pivot tables.

like image 27
GnarfDwarf Avatar answered Oct 17 '22 07:10

GnarfDwarf