0

So, trying to scope what a user can see according to him belonging to a providers model, I have this global scope defined :

class Provider extends Model
{
    protected static function booted()
    {
        static::addGlobalScope(new ProviderScope);
    }
...

The scope definition :

class ProviderScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        if(auth()->user()->providers->isNotEmpty()) {
            $builder->whereIn('id', auth()->user()->providers->pluck('id'));
        }
    }
}

And so this gives me an error Undefined property: App\Models\User::$providers which is obviously defined and works everywhere in the app.

My guess is that when trying to call auth()->user()->providers in a function running on Provider's model booted, it tries to initiate those providers, which triggers the booted function again, etc... I don't get why the error is an undefined property and not an infinite loop or something though. Am I right about the reason fir the error?

Also, given this need to scope the providers a user can see globally according to the providers he's already linked to, how would you solve it?

Thanks ahead!

Jeremy Belolo
  • 4,319
  • 6
  • 44
  • 88
  • Show the providers relation – Mihai Nov 06 '22 at 13:12
  • `public function providers() { return $this->belongsToMany(Provider::class)->withTimestamps(); }` but it hasn't anything to do with it. I have the same issue in another global scope with a `HasOne` relationship – Jeremy Belolo Nov 06 '22 at 17:15
  • 1
    If it is belongstomany you might need to do providers->first() – Mihai Nov 06 '22 at 17:51

1 Answers1

0

Okay, so it was indeed an issue with trying to load a relationship from inside said relationship boot events. It can't be loaded since it's not yet booted. Anyway, the solution I found is avoiding relationship usages altogether in global scopes.

class ProviderScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        $providers = Provider::withoutGlobalScopes()
            ->join('provider_user', 'provider_user.provider_id', '=', 'providers.id')
            ->where('provider_user.user_id', auth()->user()->id)
            ->get();
        if($providers->isNotEmpty()) {
            $builder->whereIn('id', $providers->pluck('id'));
        }
    }
}

Keep in mind that whereHas calls also rely on relationships, and will crash all the same. That's why we have to use a join instead.

Jeremy Belolo
  • 4,319
  • 6
  • 44
  • 88