If you have a Filament Select with a relationship and want to list only the options that haven't been used yet, you can do it by adding a modifyQueryUsing
parameter. In this tutorial, we will also ensure that it works correctly for the Edit operation.
Here's the example, taken from a question on the official Filament Discord.
Imagine you have these two DB models:
app/Models/Auction.php:
class Auction extends Model{ protected $fillable = ['car_id', 'name']; public function car(): BelongsTo { return $this->belongsTo(Car::class); }}
app/Models/Car.php:
class Car extends Model{ protected $fillable = ['name']; public function auction(): HasOne { return $this->hasOne(Auction::class); }}
And here's the initial Filament code for the Auction form:
app/Filament/Resources/AuctionResource.php:
public static function form(Form $form): Form{ return $form ->schema([ Forms\Components\TextInput::make('name'), Forms\Components\Select::make('car_id') ->relationship( name: 'car', titleAttribute: 'name', ) ]);}
The visual result:
Now, the goal/challenge is the Select field: we need to list only the cars that haven't been used in other auctions.
In other words, if we used a car "Audi A4" in one of the auctions, it should NOT appear when creating other new auctions.
Step 1. Adding modifyQueryUsing
Parameter.
When using a Select::make()->relationship()
, you can pass a parameter called modifyQueryUsing
with a callback function to add some condition to the query.
In this case, we will add the Eloquent method ->whereDoesntHave()
for the relationship.
app/Filament/Resources/AuctionResource.php:
// ... Forms\Components\Select::make('car_id') ->relationship( name: 'car', titleAttribute: 'name', modifyQueryUsing: fn (Builder $query) => $query->whereDoesntHave('auction') )
Now, if we add an auction record with "Audi A4" and go to the New Auction form again...
Success, "Audi A4" is not in the list!
But this is not the end of the story.
We have a problem with the Edit form. If we go to Edit the "Audi Auction" record, the "Audi A4" will not be in the list either!
Step 2. Fix for Edit Form.
Did you know that the callback function for modifyQueryUsing
accepts not only a Query Builder but also another parameter called $operation
, which automatically contains the "type" of the form: "create", "edit", etc.
We can use that parameter to check if we need to add that relationship condition.
Here's the full code:
Forms\Components\Select::make('car_id') ->relationship( name: 'car', titleAttribute: 'name', modifyQueryUsing: function (Builder $query, string $operation) { if ($operation == 'create') { $query->whereDoesntHave('auction'); } }, )
And now "Audi A4" appears in the Edit form successfully! While also NOT appearing in the Create form.
Now the job is fully done successfully!
If you want more Filament examples, you can find more real-life projects on our FilamentExamples.com.
No comments or questions yet...