Fetching and filtering relations in Laravel Eloquent

20,916

Solution 1

patricus solution pointed me in the right direction. I cross posted my question to the laracasts Forum and got a lot of help from Jarek Tkaczyk who also frequently visits this site.

hasManyThrough() for the Group model is the way to go:

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

There a couple of caveats, though:

  1. Use the relation object instead of a collection ($group->comments(), NOT $group->comments)
  2. If you use Laravel’s soft deletes you can’t just change the get() to a delete(), because you’ll get an ambiguity error for the column updated_at. You can’t prefix it either, it’s just how Eloquent works.

If you want to delete all comments from a specific user in a specific group you’ll have to do it a little bit differently:

$commentsToDelete = $group->comments()
        ->where('threads_comments.owner_id', $id)
        ->select('threads_comments.id')
        ->lists('id');

ThreadComment::whereIn('id', $commentsToDelete)->delete();

You basically fetch all relevant IDs in the first query and then batch delete them in a second one.

Solution 2

If a group hasMany threads, and a thread hasMany comments, you can add another relationship to group: group hasMany comments through threads.

On the group:

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

Now, you can get the comments in a group by $group->comments;

From here, you can tack on the requirement for the user:

$user_comments = $group->comments()->where('owner_id', $user_id)->get();

If you want, you can extract the where out into a scope on the Comment.

Share:
20,916
Rafael Bugajewski
Author by

Rafael Bugajewski

One half of Cocobit. My wife and I make great software for your iPhone, iPad & Mac 🤓

Updated on February 12, 2020

Comments

  • Rafael Bugajewski
    Rafael Bugajewski about 4 years

    I have the following models in Eloquent: groups, threads, comments and users. I want to find all comments in a specific group from a specific user.

    This is my current approach:

    $group->threads->each(function ($thread) use ($user_id)
    {
      $user_comments = $thread->comments->filter(function ($comment) use ($user_id)
      {
        return $comment->owner_id == $id;
      });
    });
    

    This looks ugly as hell, is probably slow as hell, and I just want to get rid of it. What is the fastest and most elegant way in Eloquent to get to my result set?

  • zardilior
    zardilior over 5 years
    Making the difference between relation object () and collection, is just the answer to most realtionship issues. Thanks!!