Eloquent withWhereHas Method: Don't Repeat Conditions

In Laravel, we have a method called whereHas that takes the parent Model only if it has a relationship matching a condition. As an example:

app/Http/Controllers/UserController.php

public function index()
{
$users = User::whereHas('posts', function ($query) {
$query->where('published', 1);
})
->get();
 
return view('users.index', compact('users'));
}

This code will return all users that have at least one published post. But we won't have posts loaded in the $users collection automatically. Let's fix that in two different ways that depend on your Laravel versions.


Before Laravel 9.17

The simplest way to fix it is to use the with() method:

app/Http/Controllers/UserController.php

public function index()
{
$users = User::whereHas('posts', function ($query) {
$query->where('published', 1);
})
->with('posts' => function($query) {
$query->where('published', 1);
})
->get();
 
return view('users.index', compact('users'));
}

We just filtered based on the relationship and loaded the filtered data. But the problem is that we have to write the condition twice.


New in Laravel 9.17

It is solved since Laravel 9.17 with the new withWhereHas() method that combines the whereHas() and with() functions. Let's see it in action:

app/Http/Controllers/UserController.php

public function index()
{
$users = User::withWhereHas('posts', function ($query) {
$query->where('published', 1);
})->get();
 
return view('users.index', compact('users'));
}

It will do the same as the previous code but without us repeating the condition twice in the code.

We solved a DRY problem and made our code more readable.

No comments or questions yet...

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1057 lessons, total 42 h 44 min)
  • 79 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials