nickdavies07's avatar

Chaining where() after whereHas()/orWhereHas()

Can I chain where() after a whereHas or orWhereHas method?

I have this query in which I check a model either has a parent with the given ID, or is in fact the parent model.

I then dynamically chain a scope to the end by using reflection to check what is passed in, however the where clause is not executed.

$project = 1;

return $instance->whereHas('project.parents', function ($q) use ($project) {
    	return $q->where('parent_id', $project);
    })->orWhereHas('project', function ($q) use ($project) {
    	return $q->where('id', $project);
    })->$method();

So for example, the method/scope generated by $method() would chain this:

$project = 1;

return $instance->whereHas('project.parents', function ($q) use ($project) {
    	return $q->where('parent_id', $project);
    })->orWhereHas('project', function ($q) use ($project) {
    	return $q->where('id', $project);
    })->where('category_id', 2)->get();

The above produces a query where the where query is enclosed within the second whereHas exists subquery, so isn't executing properly. Moving it outside of the subquery in the raw SQL correctly returns the results. How do I allow this to execute in the manner I want it to with the query builder?

0 likes
3 replies
MichalOravec's avatar
Level 75
$project = 1;

return $instance->where(function ($query) use ($project) {
        $query->whereHas('project.parents', function ($q) use ($project) {
            return $q->where('parent_id', $project);
        })->orWhereHas('project', function ($q) use ($project) {
            return $q->where('id', $project);
        });
    })->where('category_id', 2)->get();

Docs: https://laravel.com/docs/8.x/queries#logical-grouping

You should always group orWhere (orWhereHas etc) calls in order to avoid unexpected behavior when global scopes are applied.

2 likes
tykus's avatar
return $instance->where(function ($builder) {
	$builder->whereHas('project.parents', function ($q) use ($project) {
    	return $q->where('parent_id', $project);
    })->orWhereHas('project', function ($q) use ($project) {
    	return $q->where('id', $project);
    });
})->where('category_id', 2)->get();
1 like

Please or to participate in this conversation.