laraveleloquentlaravel-8laratrust

How to filter User by role based on the called Model?


I'm using Laratrust to manage these roles:

I've a class called User which is the main entity, then I have a specific class for each role: Patient and Doctor.

Problem

To retrieve a list of users with the role of doctor I have to write:

User::whereRoleIs('doctor')->get();

The problem's that I have defined some relationship within the class Doctor, eg:

<?php

namespace App\Models;

use App\Models\Boilerplate\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Doctor extends User
{
    use HasFactory;

    protected $table = 'users';

    public function patients()
    {
        return $this->belongsToMany(Patient::class, 'invites', 'doctor_id', 'user_id');
    }
}

and I cannot access to the relationship patients from the User model. Is there a way to call Doctor:with('patients')->get() and return automatically the users which have the role of Doctor?

So if I type: Doctor:all() the result must be equal to User::whereRoleIs('doctor')->get()

How can I do this?


Solution

  • Splitting data like this by model isn't really the intended use for models. Models in Laravel contain data on a per-table basis. In order to achieve what you want I would either make a DocterService that has methods in it to retrieve docter users by calling User::whereRoleIs('doctor') or just use this method straight away.

    If you really want to use the model though you can use scopes. (https://laravel.com/docs/9.x/eloquent#query-scopes) Create a new scope that includes the whereRoleIs('doctor') method

    <?php
     
    namespace App\Scopes;
     
    use Illuminate\Database\Eloquent\Builder;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\Scope;
     
    class DoctorScope implements Scope
    {
        /**
         * Apply the scope to a given Eloquent query builder.
         *
         * @param  \Illuminate\Database\Eloquent\Builder  $builder
         * @param  \Illuminate\Database\Eloquent\Model  $model
         * @return void
         */
        public function apply(Builder $builder, Model $model)
        {
            $builder->whereRoleIs('doctor');
        }
    }
    

    and apply it to the model by adding the following to the model:

        /**
         * The "booted" method of the model.
         *
         * @return void
         */
        protected static function booted()
        {
            static::addGlobalScope(new DoctorScope);
        }