Search code examples
phplaravelaudiolaravel-5has-many

Laravel combining has() and whereHas()


I'm trying to combine some methods in Eloquent but can't seem to get it together properly. I have a query that pulls all items where the hasMany count is 0.

So basically I want to know where the relationship is "empty". In this case I have an item with audio samples. So, I want to get items where there are no audio samples yet.

return $this->hasMany('App\Models\Item')->has('audios', '=', 0);

This works completely fine. However I also want to add a filter based on male and female audio samples. If I use whereHas I can get the filter but only directly and can't get the has 0 clause on it.

return $this->hasMany('App\Models\Item')->whereHas('audios', function ($q) {
    $q->where('gender', 'female');
});

But no I want combine them and can't figure this bit out. So "get all items with no female audio samples".

Not a lot of documentation on these except in the trivial case, I tried a few variations but it's not coming up right. Just completely empty sets or only female or male directly without that "empty" 0 set.

Here is the query I would like to get:

SELECT *
FROM `items`
WHERE (
    SELECT COUNT(*) 
    FROM `audios`
    WHERE `audios`.`item_id` = `items`.`id`
    AND `audios`.`gender`='female'
) = 0

Solution

  • whereHas, doesntHave etc are all methods that, in the end, call has. If you look at the signature of whereHas you can see that it allows a count to be passed as well:

    public function whereHas($relation, Closure $callback, $operator = '>=', $count = 1)
    

    So you could do that, or just use whereDoesntHave:

    return $this->hasMany('App\Models\Item')->whereDoesntHave('audios', function ($q) {
        $q->where('gender', 'female');
    });