felipesmendes
felipesmendes

Reputation: 47

Loses Auth :: user () when declaring an Oberserver in AppServiceProvider

I'm trying to use a local scope in one of my models but for this I need to check the user permission, so I try to get the autenticated user by Auth::user().

But it givens me a null because I have an Observer declared for this model, and if I comment the declaration of the Observer the Auth::user() method give me a user authenticated.

There is a correct way or place to declare the Observer and in the model I can get the authenticated user, because I need to use Observers and get in boot method the authenticated user?

Laravel Framework 6.5.2

AppServiceProvider Don't work auth in model

 /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Conciliador::observe(ConciliadorObserver::class);
        Proposta::observe(PropostaObserver::class);

    }

AppServiceProvider work auth in model

 /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //Conciliador::observe(ConciliadorObserver::class);
        //Proposta::observe(PropostaObserver::class);

    }

Model does not have user logged in when Observer is declared in AppServiceProvider

 /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();
        $user = Auth::user();
        dd($user); // null if Observer is declared in AppServiceProvider
        if($user && $user->tipo == 'admin-gerenciador'){
            $conciliadores = $user->conciliadores->pluck('id')->toArray();
            static::addGlobalScope('Conciliadores', function (Builder $builder) {
                $builder->whereIn('id',$conciliadores);
            });
        }
    }

Upvotes: 0

Views: 716

Answers (2)

mpyw
mpyw

Reputation: 5764

  • Don't call Auth::user() anywhere. It may trigger authentication side-effects. It is highly recommended to do that only in controllers and middleware.
  • But you can safely call Auth::user() if you check by Auth::hasUser() in advance; it checks if the user is ALREADY authenticated.

So your code goes like:

/**
 * The "booting" method of the model.
 */
protected static function boot(): void
{
    static::addGlobalScope('Conciliadores', function (Builder $query) {
        if (Auth::hasUser() && Auth::user()->tipo === 'admin-gerenciador') {
            $query->whereKey(Auth::user()->conciliadores->modelKeys());
        }
    });
}

It's very simple solution. Even middleware is unnecessary.

EDIT

This scope is always available, but actually apply conditions only if the user is already authenticated.

Upvotes: 1

lagbox
lagbox

Reputation: 50541

You shouldn't be doing this in your model's boot method like that. The boot method is only called once for the model, not for every model instance. The first time the model is used boot gets called, which would be when you are adding the observer for it in the Service Provider in your case; which would be way before the request is dispatched to a route and through the middleware stack. (There is no session at this point, so no authenticated user.)

You probably want to add your global scope to your model via a middleware.

Upvotes: 0

Related Questions