Skip to content
Advertisement

Laravel conditionally add global scopes after method boot

Is it possible to add a global scope after the model has already passed the constructor?

I would like to catch an event (for example creating) and attach a global scope only if the model is creating.

So far I’ve done:

Event::listen('eloquent.creating*', function ($event, $model) {
    /**
     * @var Model $eloquentModel
     */
    $eloquentModel = $model[0];
    $eloquentModel->addGlobalScope(new AuthorizationScope($event));
});

The scope constructor is called, but the apply method from it is never fired because the model at that point already obviously passed the part where it fires the scopes. How could I manually fire it?

Advertisement

Answer

tl;dr; It is not possible. At the time when the Eloquent events are firing scopes are already loaded and applied.

Use case: I wanted to add additional scopes on model create/edit/delete to be able to do some sort of dynamic authorization, however this is not valid because Laravel uses Eloquent query builder for doing DB SELECT. For everything else, such as inserts or deletes, a different query is formed and is not connected to a given query builder, so even if you could tap into it, it makes no sense to do it as it would form a separate query for create/edit/delete actions anyways.

What I ended up doing was reusing the logic which I used within scopes, but instead of limiting the query initially (what scopes do), I would do my checks within event listener and return true/false depending on that check.

For this concrete example, returning false upon catching eloquent.creating event would mean that the model will not be created, which is exactly what I needed.

For any more details, feel free to check authorization package for microservices I developed using this approach.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement