5

I am having problems filtering a relationship using laravel 4.1 hasWhere.

Iteration 1 - Get all posts: Done

$posts = Post::all();

Iteration 2 - Get all posts lazy load comments: Done

$posts = Post::with('comments')->get();

Iteration 3 - Get only posts with comments and lazy load: Done

$posts = Post::with('comments')->has('comments')->get();

Iteration 4 - Get only posts with published comments and lazy load: Broken

$posts = Post::with('comments')
    ->whereHas('comments', function($q) {
        return $q->where('published', '=', 1);
    })
    ->get();

Output of print_r($posts->toArray()) shows output of iteration 3 and 4 as exactly the same. I am unable to filter the relation based on the condition that 'comments.published' = 1.

Gravy
  • 12,264
  • 26
  • 124
  • 193
  • I believe the problem is that you're calling `return` on the query's where method. Simply call `$q->where('published', '=', 1);` (no `return` statement) and you should be good. – Soulriser Feb 23 '17 at 22:08

2 Answers2

2

I have found a solution, however I am uncertain that this is the most elegant solution. As such, I am leaving this open for better suggestions.

    $posts = Post::
        ->whereHas('comments', function($q)
            {
                $q->where('published', '=', 1);
            })
        ->with([
            'comments' => function($q)
            {
                $q->where('published', '=', 1);
            },
            ])->get();

Basically, my solution involves filtering eloquent results, and also filtering lazy loading separately. Is this necessary? Is there a better way of achieving this?

Gravy
  • 12,264
  • 26
  • 124
  • 193
  • you don't need the second filter in the with section: This will simply do a second query with the filter on the (already) filtered values. So what you are basically doing is one query with the filter and then another query (the eager loaded one) with the filter again. simply calling `with('comments')` should do the trick in this case. – Hans Vn Dec 09 '15 at 10:17
0

It took me a while to figure this out as well, so here is what works for me..

$postsFilter = Comments::with('Posts')->where('published', 1)->first();
$posts= $postsFilter ->posts;

of course yo have to bind with belongsToOne or belongToMany in the model definitions.

// And in case anyone reading wants to also use pre-filtered data you can pass a closure to the 'with'

$usersFilter = Addresses::with(array('Users' => function($query) use ($keyword){ 
    $query->where('somefield', $keyword);
}))->where('town', $keyword)->first();
$myUsers = $usersFilter->users;
Elias Escalante
  • 305
  • 3
  • 13