Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Pixelairport's avatar

Filament table filter with custom model attribute

I try to use a filament filter with an attribute from user model. Problem is, that for each user the attribute has to do an api request to an external server. So it is not part of the query. Is this possible? I know that is not a good solution and can take very long. But is it possible? I also think about to just a second resource with only the one segment of users. This is an example code I have right now.

SelectFilter::make('myCustomAttribute')
->options([
  true => 'With',
  false => 'Without',
])
0 likes
5 replies
LaryAI's avatar
Level 58

Using a custom attribute that requires an API request for each user within a Filament table filter is indeed not an ideal solution due to the potential performance issues. However, if you must implement this, you could use a custom query callback for the filter to handle the logic.

Here's an example of how you might approach this:

SelectFilter::make('myCustomAttribute')
    ->options([
        'with' => 'With',
        'without' => 'Without',
    ])
    ->query(function ($query, $value) {
        // Assuming you have a method on your User model that checks the custom attribute
        // and that method is called `hasCustomAttribute` which returns a boolean.
        $userIdsWithAttribute = [];
        $userIdsWithoutAttribute = [];

        // This is not efficient, but it's what the question asks for.
        // It would be better to store the result of the API request in the database and query it.
        foreach ($query->get() as $user) {
            if ($user->hasCustomAttribute()) {
                $userIdsWithAttribute[] = $user->id;
            } else {
                $userIdsWithoutAttribute[] = $user->id;
            }
        }

        if ($value === 'with') {
            $query->whereIn('id', $userIdsWithAttribute);
        } else {
            $query->whereIn('id', $userIdsWithoutAttribute);
        }
    });

Please note that this code will execute an API request for each user every time the filter is applied, which can be very slow and resource-intensive. It's highly recommended to cache the results of the API request or store them in the database to avoid making an API request for each user every time.

If you can modify the user model to include a cached version of the custom attribute, you could then use a standard query filter without the performance penalty. Here's an example of how you might do that:

// In your User model, add a method to update the custom attribute
public function updateCustomAttribute()
{
    // Perform the API request and store the result in a column like `has_custom_attribute`
    $this->has_custom_attribute = $this->fetchCustomAttributeFromApi();
    $this->save();
}

// Then, in your Filament filter, you can simply query the database column
SelectFilter::make('myCustomAttribute')
    ->options([
        'with' => 'With',
        'without' => 'Without',
    ])
    ->query(function ($query, $value) {
        if ($value === 'with') {
            $query->where('has_custom_attribute', true);
        } else {
            $query->where('has_custom_attribute', false);
        }
    });

This second approach assumes that you have a boolean column has_custom_attribute in your users table that stores the result of the API request. You would need to ensure that this column is updated regularly to reflect the current state of the custom attribute.

jaseofspades88's avatar
Level 51

That sounds like an n+1 problem waiting to happen. Is it not possible to run an event that synchronises all of the custom attributes to the model, then you can simply treat the 'customAttribute' as a regular one?

Having an accessor for an API request is not a good idea. Imagine if you had 10,000 records, that's a lot of API requests to make when pulling data and hydrating those models.

1 like
Pixelairport's avatar

@jaseofspades88 Thx. Yes ... I think that would be the best idea. I will sync the data I need to an extra table and work with relations.

Please or to participate in this conversation.