Showing records in the Filament table is simple, but what if you want to modify the original query based on some condition, like user role?
Imagine a scenario: we have two posts in the database by the admin user (author_id = 1) and five by the regular user (author_id = 2).
And in the Filament Table, we want two cases:
- Admins should see ALL posts
- Regular users should see only the posts with their own
author_id
Now, how do we modify the Filament base query?
Preparation: DB/Model Structure
For simplicity, the users
table has a role
column whose value can be admin or user.
database/migrations/0001_01_01_000000_create_users_table.php:
public function up(): void{ Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->string('role')->default('user'); $table->rememberToken(); $table->timestamps(); }); // ...}
The posts
table only has columns for the title and author ID.
database/migrations/xxx_create_posts_table.php:
public function up(): void{ Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->foreignId('author_id')->constrained('users'); $table->timestamps(); });}
app/Models/Post.php:
use Illuminate\Database\Eloquent\Relations\BelongsTo; class Post extends Model{ protected $fillable = [ 'title', 'author_id', ]; public function author(): BelongsTo { return $this->belongsTo(User::class,'author_id'); }}
And in the Filament Resource, we simply show the title and author's name.
class PostResource extends Resource{ // ... public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('title'), Tables\Columns\TextColumn::make('author.name'), ]) ->filters([ // ]) ->actions([ Tables\Actions\EditAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } // ...}
Filament Table: Change Query by Role Condition
Filament has a method modifyQueryUsing()
that can be used to modify the Eloquent query.
Using this method in the Closure, we can do a simple check for the user's role and, if needed, add a simple ->where()
statement.
class PostResource extends Resource{ // ... public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('title'), Tables\Columns\TextColumn::make('author.name'), ]) ->modifyQueryUsing(function (Builder $query) { if (auth()->user()->role === 'user') { return $query->where('author_id', auth()->id()); } }) ->filters([ // ]) ->actions([ Tables\Actions\EditAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } // ...}
When visiting the page with the user with a user role, we can see the condition is added to a query, see the screenshot from Laravel Debugbar.
And visually, the regular user now sees only their posts.
The admin user can see all the posts because the query hasn't been modified.
If you want more Filament examples, you can find more real-life projects on our FilamentExamples.com.
This is lovely but what is i want to change the query if there is a filter? e.g.
->modifyQueryUsing(function (Builder $query) { if (tableFilter) { return $query->with('studentAcademics'); } else{ return $query->whereNull('id'); } })
Then use filters and not modifyt query