Table filter using a select on a relationship with a column based on enum class
Package
filament/filament
Package Version
v3.2.82
Laravel Version
v11.8.0
Livewire Version
3.5.0
PHP Version
PHP 8.2.0
Problem description
I get this error:
Filament\Forms\Components\Select::isOptionDisabled(): Argument #2 ($label) must be of type string, App\Enums\MembershipStatuses given
From vendor/filament/forms/src/Components/Concerns/CanDisableOptions.php#39
Expected behavior
Should get a table filtered with the relationship enum column when accessing the admin panel Membership Request resource
php artisan migrate:fresh --seed
to populate with a few rows and access the panel /admin with user [email protected] password="password"
Steps to reproduce
I have a model MembershipRequest which have a BelongsTo relationship to a Membership class The Membership class has a property 'status' which is casts to an Enum Class called MembershipStatuses
I add the filter to the filament table for resource MembershipRequest using a relationship() method to the membership status:
SelectFilter::make('membership.status')
->relationship('membership', 'status'),
My Model Membership has this $casts
protected $casts = [
'status' => App\Enums\MembershipStatuses::class, // Enum class
//...
];
And MembershipRequest has this relationship:
public function membership(): BelongsTo
{
return $this->belongsTo(Membership::class);
}
Reproduction repository
https://github.com/ngalso/filament-issue.git
Relevant log output
No response
Use v3.2.78 fixed the problem for me. array_diff(): argument #2 must be of type array, string given in update forms with relationships.
I am already using v.3.2.82 and I just tried with v3.2.83 and the error is still being triggered.
Downgrade te version: "filament/filament": "v3.2.78",
A fix is to add the HasLabel contract in the isOptionDisabled $label parameter (Filament\Forms\Components\Concerns\CanDisableOptions)
public function isOptionDisabled($value, string|\Filament\Support\Contracts\HasLabel $label): bool
{
//
}
Only thing left from there is to use the HasLabel contract in your enum
<?php
namespace App\Enums;
use Filament\Support\Contracts\HasLabel;
enum MembershipStatuses: string implements HasLabel
{
case UNPAID = 'unpaid'; // not yet paid
case PROCESSING = 'processing'; // paid and need to print for board
case PENDING = 'pending'; // printed and waiting to be approved by board - no vote possible
case ACTIVE = 'active'; // approved by board - voting is possible
case EXPIRING = 'expiring'; // no vote possible - but renewing is possible
case EXPIRED = 'expired'; // no vote - no renewal. Need a new one.
case CANCELLED = 'cancelled'; // cancelled by the user
case REVOKED = 'revoked'; // revoked by the board - no new approval possible
public function getLabel(): ?string
{
return $this->name;
}
}
If this is a workable solution I can create a PR?
Thanks, let me run some test and will let you know.
It now passes the error message but the filter is not applied to the resource
Downgrade te version: "filament/filament": "v3.2.78",
Thanks but even on v3.2.78 the error still happens
Hi Steve,
One more change to get it to work
In the SelectFilter class in Filament\Tables\Filters in the SetUp function you have to add this after line 112
if ($label instanceof HasLabel) {
$label = $label->getLabel();
}
Then it will work
Don't forget to change your filter to
->filters([
SelectFilter::make('status')
->relationship('membership', 'status')
->preload(),
])
->filtersFormSchema(fn(array $filters): array => [
Section::make('Filters')
->description('These filters affect the visibility of the records in the table.')
->schema([
$filters['status'],
])
->columns(2)
->columnSpanFull(),
])
changed membership.status to status
Solution for people who has upgraded to laravel 11 and is still waiting for this to be fixed:
Filament\Forms\Components\Select component fix
Select::make('payment_processor_id')
->relationship('paymentProcessor', 'name')
// add this line
->getOptionLabelFromRecordUsing(fn (PaymentProcessor $record) => $record->name->getLabel())
Filament\Tables\Filters\SelectFilter component fix
SelectFilter::make('transport_order_status_id')
->label('Status')
->relationship('status', 'name')
// add this line
->getOptionLabelFromRecordUsing(fn (TransportOrderStatus $record) => $record->name->getLabel())
// and this
->indicateUsing(fn ($data) => 'Status: ' . implode(' & ', $data['values']))
Looks like no other has encountered issues with indicators, but they are crashing too.
Thank You very much for this man. I spent a lot of time trying to figure it out. Finally this worked for me!
Thanks all for your input. In the end I changed my logic and did not have to filter by a parent relationship
Maybe keep this issue open as this issue is not yet resolved by filamentphp? I think and it's really important to have a proper enum support.
I think you are right, but I can't re-open it...
@danharrin can we keep this open?
I can confirm this problem.
In my case, I don't want to populate the options based on the relationship. I just want to show the options from the enum. I solved my problem with the following code without using the relationship method:
SelectFilter::make('status')
->options(StatusEnum::class)
->modifyQueryUsing(function ($query, $data) {
if (! empty($data['value'])) {
$query->whereHas('casefile', function ($query) use ($data) {
$query->where('status', $data);
});
}
})
->label('Status')
For those looking for multiple() support. This should work:
SelectFilter::make('order_status')
->options(OrderStatusEnum::class)
->modifyQueryUsing(function ($query, $data) {
if (! empty($data["values"])) {
$query->whereHas('order', function ($query) use ($data) {
$query->whereIn('status', Arr::flatten($data));
});
}
})
->multiple()
->searchable()
->label('Status')
Hey @polar-sh[bot]! We're sorry to hear that you've hit this issue. 💛
However, it looks like you forgot to fill in the reproduction repository URL. Can you edit your original post and then we'll look at your issue?
We need a public GitHub repository which contains a Laravel app with the minimal amount of Filament code to reproduce the problem. Please do not link to your actual project, what we need instead is a minimal reproduction in a fresh project without any unnecessary code. This means it doesn't matter if your real project is private / confidential, since we want a link to a separate, isolated reproduction. That would allow us to download it and review your bug much easier, so it can be fixed quicker. Please make sure to include a database seeder with everything we need to set the app up quickly.
Same problem here still a year later. I'm kind of shocked enums aren't supported on select fields in relationships.
In Filament, you can use a SelectFilter to filter a list based on which record they are related to:
SelectFilter::make('author')
->relationship('author', 'name')
This is going to produce options like
{ 1: 'First author', 2: 'Second author', 3: 'Third author' }
When you use the filter, Filament is filtering on the author_id field, since the option keys are author IDs
You are doing this, with an enum field (like role):
SelectFilter::make('author')
->relationship('author', 'role')
And it is producing options like
{ 1: 'Writer', 2: 'Admin', 3: 'Writer' }
Whereas you are expecting options like
{ 'writer': 'Writer', 'admin': 'Admin' }
When you use the filter, Filament is filtering on the author_id field, since the option keys are author IDs. You actually want to filter on an entirely different column, the role. Filament just uses that to display the option labels, not for filtering. You want to filter through the relationship on the enum field.
The select filter's relationship() was not made for what you're trying to use it for. The suggestions in the comments above, where you pass the enum class to options(), and then scope the query yourself.
@danharrin please don't colse this, your comment is not accurate.
We indeed are expecting options like this:
{ 1: 'Writer', 2: 'Admin', 3: 'Writer' }, but filamentphp are not generating them with the enum casts.
Filamentphp is crashing with Filament\Forms\Components\Select::isOptionDisabled(): Argument #2 ($label) must be of type string, App\Enums\MembershipStatuses given
So solving this crash would be the goal.
As I have commented above https://github.com/filamentphp/filament/issues/12948#issuecomment-2340434936, using enums requires some workarounds to prevent filamentphp from crashing and it looks like these workarounds can be avoided. Working with filamentphp should be a breeze and for now eloquent enum casts and filamenphp are not really paying well.
If both record 1 and record 3 have the same label, how is the user supposed to differentiate between them when selecting the correct option? Also, they may select "Writer" and expect all the records with "Writer" to be shown, yet they only get presented with one record.