I have a specific need to only get models where all of the related models have a specific value.
For example, I have a model called User
, and User
has a hasMany
relationship on a model called Job
.
┌────────┐ ┌───────┐
│ │ 1:n │ │
│ USER │ ───────► │ JOB │
│ │ │ │
└────────┘ └───────┘
Lets say the Job
model has a column called Status
which can be one of the following Enums
JobStatus::OPEN
JobStatus::CLOSED
JobStatus::SCHEDULED
JobStatus::IN_PROGRESS
I want to be able to create a method on the User
model called scopeIsFinished()
. The purpose of the scope is to filter users where every of their Jobs’ status is either JobStatus::CLOSED
or JobStatus::SCHEDULED
(and henceforth, they have no jobs with JobStatus::OPEN
or JobStatus::IN_PROGRESS
). If they have one or more jobs that are open or in progress, the user is out of scope.
In a perfect world, a method like the following would be great
/**
* Is finished. Every single one of the users jobs are closed, they have 0 open jobs.
*
* @param Builder $query
* @return Builder
*/
public function scopeIsFinished(Builder $query): Builder
{
return $query->whereOnlyHas('jobs', function($sub){
$sub->whereIn('status', [JobStatus::CLOSED, JobStatus::SCHEDULED]);
});
}
Does anyone know if this is possible, or a nice clean easy way I can achieve this?
I want to avoid making relationships like openJobs
, closedJobs
, scheduledJobs
, etc, and have the scope rely on whereHas()
and whereDoesntHave()
.