3

I'm trying to understand some advanced eloquent commands and on the Laravel official documentation, there is not so much about the Eloquent orWhereHas method and there isn't also an example about how it works.
https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence

Can somebody help me to understand it with also a simple example?

Davide Casiraghi
  • 15,591
  • 9
  • 34
  • 56

2 Answers2

4

How to use it: just chain as any other Eloquent method

User::whereHas(...)->orWhereHas(...)->get();

When to use it: imagine you have Users, Posts and Comments, and each user can write posts and comments. Then you need to get active users. For example, you assume active as user, who has made posts OR comments last 7 days. So, you can get it this way:

$users = App\Models\User::query()
    ->whereHas('posts', function (Builder $query) {
        $query->where('created_at', '>=', Carbon::now()->subDays(7));
    })
    ->orWhereHas('comments', function (Builder $query) {
        $query->where('created_at', '>=', Carbon::now()->subDays(7));
    })
    ->get();
Roman Meyer
  • 2,634
  • 2
  • 20
  • 27
2

Say there's a blog kind of app. The main entity/model of the app would be Post (Blog Post).

When any author writes and publishes a Post,

  • visitors to the blog site can leave Comment(s) for the Post
  • visitors can Like a Post

So we have 3 models here

  • Post - which can have many Comment(s)
  • Post - can have many Like(s)

Now let's say for some reason we want to get all Post records from the database which either have 10 or more comments in the current month or 3 or more likes in the current month

We can write a query like

$posts = Post::whereHas('comments', function($query) {
        $query->where('created_at', '>', now()->startOfMonth();
    }, '>=', 10)
    ->orWhereHas('likes', function($query){
        $query->where('created_at', '> ', now()->startOfMonth();
    }, '>=', 3)
    ->get();

Laravel docs: https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence

Just like where both whereHas and orWhereHas accepts closure as 2nd argument for more fine grained query control.

Actually whereHas is supposed to be used when you want to have more power on constraints.

If you just want to check the existence of relation records you can use has for eg:

Get all post records which either have comment or like and paginate 20 per page

$postsWithCommentsOrLikes = Post::has('comments')
    ->orHas('likes')
    ->paginate(20);
Donkarnash
  • 12,433
  • 5
  • 26
  • 37
  • as far i understood, your code example can be changed from `whereHas` to `has`, because you are using no callbacks to filter subqueries – Roman Meyer Dec 06 '20 at 10:55
  • Yes true I was just adding that but got distracted with something else – Donkarnash Dec 06 '20 at 11:01
  • In this case, if you specify any condition I think you can just use has and orHas – Davide Casiraghi Dec 06 '20 at 11:26
  • Yes @DavideCasiraghi if the requirement is to just check whether model has related records or not then simple `has()` and `orHas()` can suffice. However if more fine grained control is required to create a complex constraint on relationship check then `whereHas` and `orWhereHas` come into play as both these accept closure as second parameter where complex query logic can be defined. Have update answer for both scenarios – Donkarnash Dec 06 '20 at 12:39