16 hours ago
JSn1nj4 pushed to feature/267-Design-v3-extra-theme at JSn1nj4/ElliotDerhay.com
Categories: Simple mistakes
Tags: #Laravel , #Authorization , #Policies , #FilamentPHP , #Query Scopes
I recently discovered that I was accidentally rerunning queries when authorizing access to models and re-applying global scopes that were supposed to be ignored in certain circumstances.
A while ago, I wrote a PostPolicy class to authorize reads/writes. One of the conditions in this class was $post->exists(). This does exactly what it sounds like: checks the DB to see if the model exists.
I also wrote a PostPublishedScope class, applied it to my Post model, and then told Filament to ignore it.
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()->withoutGlobalScope(PostPublishedScope::class);
}
Filament documents this method of disabling global scopes.
Combining these allows me to do a few things:
This seemed to be working.
Recently, I started my local DB over to play with Postgres. When I did that, I found out I wasn't able to open unpublished posts for editing—dummy posts I literally just created.
At first I thought it was a bug in Filament. The unpublished posts were showing in my dashboard, but their CRUD actions weren't all available (Filament respects model policies).
Also, the issue seemed like it was only happening when I had no published posts. The CRUD actions in the Posts table seemed to show again for all of my posts if 1 of my posts was published. This also meant my live website had been having this issue for a while. I just didn't see it because I had posts that were published.
After a lot of poking around, asking questions, and even starting to fill out a bug report, I discovered the issue: in my PostPolicy, I was calling $post->exists() instead of using $post->exists.
Laravel's ->exists() method for the query builder and Eloquent queries the DB directly to see if something exists. This also means that, even though Filament was removing my global scope during its own query, the PostPublishedScope was being reapplied during authorization.
The solution was to check $post->exists instead of calling $post->exists(). By the time the model has been passed to the policy, the $exists property has already been set on the model and any global scopes have already been applied.
Make sure your policy conditions behave exactly as you expect (duh). Also avoid running queries if you can.
At the time, I'm sure I naively thought it was doing the check on the loaded model instead of running another query (and now that I think about it, this sounds like a good edge case test).
I said earlier that most crud actions weren't showing in my table. Turns out I forgot to check $exists in 1 of my CRUD actions, so that one was still available in Filament when it wasn't supposed to be. Whoops... 😅
16 hours ago
JSn1nj4 pushed to feature/267-Design-v3-extra-theme at JSn1nj4/ElliotDerhay.com
16 hours ago
JSn1nj4 pushed to feature/267-Design-v3-extra-theme at JSn1nj4/ElliotDerhay.com
16 hours ago
JSn1nj4 pushed to feature/267-Design-v3-extra-theme at JSn1nj4/ElliotDerhay.com
3 days ago
JSn1nj4 pushed to feature/267-Design-v3-extra-theme at JSn1nj4/ElliotDerhay.com
3 days ago
JSn1nj4 pushed to feature/267-Design-v3-extra-theme at JSn1nj4/ElliotDerhay.com
Please confirm whether you would like to allow tracking cookies on this website, in accordance with its privacy policy.