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.