Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

taijuten's avatar

Making Dynamic Eloquent Scopes

Evening all,

I have a certain problem that I need to solve, and I'm unsure of the best way to approach it.

Here's an example: I have a model: School. A School has many Students, and each student has many Guardians The many-to-many relationship between Students and Guardians has some other properties, such as is_legal_guardian (boolean) and order (integer).

All of this is fine, however, I need each School to be able to set up what I can only describe as a filter, or a preset, so, that when retrieving the Guardians for each Student, the results are filtered by whatever the school has defined for a particular filter. An example of this might be a school sets up a filter called "Legal Guardians who are first point of contact", where they only wish to return Guardians of each Student where the legal_guardian is true and the order equals 1.

The only way I can think of doing this is having a GuardianFilter model, and having Guardians linked to that, but unsure of how that relationship would work, when the relationship itself is defined by the School.

I apologise if this is difficult to follow, but am happy to provide further clarification if required.

0 likes
2 replies
jusahah87's avatar

@taijuten Pivot table between Student and Guardian holds all the relevant data for filtering. I would create a separate Model for that table. Here called "StudentGuardian".


// StudentGuardian is pivot model for the many-to-many relation between Students and Guardians.
class StudentGuardian extends Model
{
    // Relations defined to Student and Guardian models not shown

    // Dynamic query builder method
    public function scopeCustomFiltering($query, $filters)
    {
        return $filters->reduce(function($extendedQuery, $filter) {
            return $extendedQuery->where($filter['attribute'], $filter['op'], $filter['val']); 
        }, $query);
    }

}

// example usage
$filters = [
   ['attribute' => 'order', 'op' => '=', 'val' => 1],
   ['attribute' => 'is_legal_guardian', 'op' => '=', 'val' => true]
];
$studentIdsOfSchool = Student::where('school_id', 1)->select('id')->get();
$studentGuardians = StudentGuardian::whereIn('student_id', $studentIdsOfSchool)
   ->customFiltering(collect($filters))
   ->with('guardian')
   ->get();

$guardians = $studentGuardians->pluck('guardian'); // Does pluck work here? Never tried something like this.

I have not actually implemented anything like above so take it with a grain of salt. But it should work I guess?

2 likes

Please or to participate in this conversation.