Refactoring to whereRelation method

Eduar Bastidas • September 7, 2021

tips refactoring

Previously in Laravel when you wanted to get a relation and include an extra complex condition you had to do it with the whereHas method in the following way:

1// Get me all users who have posts that are to be published in the future.
2User::whereHas('posts', function ($query) {
3 $query->where('published_at', '>', now());
4})->get();

Recently DarkGhostHunter has made a PR in Laravel 8.57.0 version where it is possible to simplify this in a much more elegant and polished way.

1User::whereRelation('posts', 'published_at', '>', now())->get();

As you can see, we have collapsed the closure into the parameter list of the whereRelation method.

With this PR, you also have access to whereRelation and orWhereRelation helpers, and whereMorphRelation and orWhereMorphRelation for morph relations. Since these use the where method underneath, you can do advanced things:

1Comment::whereMorphRelation('commentable', '*', [
2 'is_public' => true,
3 'is_vip' => false,
4])->get();

What cannot be done

However, it also becomes a disadvantage, since you will not be able to use scopes inside as you used to do with whereHas, for example you will not be able to make

1Post::whereHas('comments', function ($comment) {
2 $comment->approved();
3})->get();

Or nested where:

1User::whereHas('posts', function ($post) {
2 $post->whereHas('tags', function ($tag) {
3 $tag->where('name', 'tips');
4 })->where('published_at', '>', now());
5})->get();

This is an improvement that many of us will appreciate very much and that will serve us in the day to day to have a more elegant code without a doubt.