F
Filament4mo ago
nowak

Slow action modal opening times on resource table

I have a GroupOrderManagementResource with a table, which has actions that use my GroupOrder model records in it's functions. Opening these actions seems to take too long (3+ secons), and I was wondering if I am doing something inefficiently when it comes to using the Resource model records in the table? So my Resource setup looks like this:
class GroupOrderManagementResource extends Resource
{
protected static ?string $model = GroupOrder::class;
protected static ?string $navigationLabel = 'Group Order Manager';

public static ?string $title = 'Group Order Management';

public static ?string $slug = 'group-order-management';
class GroupOrderManagementResource extends Resource
{
protected static ?string $model = GroupOrder::class;
protected static ?string $navigationLabel = 'Group Order Manager';

public static ?string $title = 'Group Order Management';

public static ?string $slug = 'group-order-management';
Then I define my table query like this:
public static function table(Table $table): Table
{
return $table
->query(GroupOrderResource::getEloquentQuery()->with([
'userOrders.userOrderItems.productSku.product.category' => function ($query) {
$query->select('id', 'name');
},
'userOrders.userOrderItems.productSku.product.type' => function ($query) {
$query->select('id', 'name');
},
'route'
])->activeDayGroupOrders())
public static function table(Table $table): Table
{
return $table
->query(GroupOrderResource::getEloquentQuery()->with([
'userOrders.userOrderItems.productSku.product.category' => function ($query) {
$query->select('id', 'name');
},
'userOrders.userOrderItems.productSku.product.type' => function ($query) {
$query->select('id', 'name');
},
'route'
])->activeDayGroupOrders())
Where I am wondering if I am using eager loading correctly? And finally, I have a note TextColumn, that I have added an action to with a form to add/edit the note for a record:
TextColumn::make('note')
->placeholder(__('Click to add note!'))
->extraAttributes(['class' => 'min-w-36 text-wrap cursor-pointer'])
->toggleable()
->action(
Action::make('edit_note')
->label(false)
->form(fn(GroupOrder $record) => [
Textarea::make('note')
->label(fn (Get $get): string => $get('note') ? __('Edit Note') : __('Add Note'))
->default($record->note)
])
->action(fn(GroupOrder $record, array $data) => $record->update(['note' => $data['note']]))
),
TextColumn::make('note')
->placeholder(__('Click to add note!'))
->extraAttributes(['class' => 'min-w-36 text-wrap cursor-pointer'])
->toggleable()
->action(
Action::make('edit_note')
->label(false)
->form(fn(GroupOrder $record) => [
Textarea::make('note')
->label(fn (Get $get): string => $get('note') ? __('Edit Note') : __('Add Note'))
->default($record->note)
])
->action(fn(GroupOrder $record, array $data) => $record->update(['note' => $data['note']]))
),
Any insight is highly appreciated! Thanks!
21 Replies
toeknee
toeknee4mo ago
use telescope and debug where the slowdown is
nowak
nowakOP4mo ago
It might be worth it to share my activeDayGroupOrders() method from my GroupOrder model as well:
/**
* Scope a query to include group orders for the current or next active day.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $mealTypeName Name of the meal type.
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeActiveDayGroupOrders($query)
{
// Calculate the query deadline
$currentDateTime = now();
$lastActiveMealTypeDeadline = MealType::getLastActiveMealTypeDeadline();
$queryDeadline = $currentDateTime;

// If current time is after the last active meal type's deadline including grace period, focus on the next day
if ($currentDateTime->greaterThan($lastActiveMealTypeDeadline)) {
$queryDeadline->addDay();
}

// Filter by deadline
$finalQuery = $query->whereDate('deadline', '=', $queryDeadline->toDateString());

return $finalQuery;
}
/**
* Scope a query to include group orders for the current or next active day.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $mealTypeName Name of the meal type.
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeActiveDayGroupOrders($query)
{
// Calculate the query deadline
$currentDateTime = now();
$lastActiveMealTypeDeadline = MealType::getLastActiveMealTypeDeadline();
$queryDeadline = $currentDateTime;

// If current time is after the last active meal type's deadline including grace period, focus on the next day
if ($currentDateTime->greaterThan($lastActiveMealTypeDeadline)) {
$queryDeadline->addDay();
}

// Filter by deadline
$finalQuery = $query->whereDate('deadline', '=', $queryDeadline->toDateString());

return $finalQuery;
}
Thank you, will look into telescope, is it built into laravel?
toeknee
toeknee4mo ago
if you have. alot in the mealtype model, you could index deadline.
nowak
nowakOP4mo ago
MealType is three records, breakfast, lunch and dinner
toeknee
toeknee4mo ago
No it's a standard Debugger which will show the request and dig down on the request and what is slow Or debugbar
nowak
nowakOP4mo ago
ahh.. I have debugbar installed, but disabled. Will see what enabling it gives me, one sec.
nowak
nowakOP4mo ago
Not sure where I should be looking in debugbar, but I also find the action being unreliable when clicking it and expecting the modal to open:
nowak
nowakOP4mo ago
I also investigated the HTML in dev tools, where it looks like the javascript for clicking the action button is triggered, but somehow the action model does not open sometimes, is this a known bug in filament? Or is it unrelated to filament?
Tonkawuck
Tonkawuck4mo ago
620 queries is cause for concern. Especially with eager loading
toeknee
toeknee4mo ago
That's an awful lot! I would say look at this in mor defail, you are probably not putting closures in the selects..
nowak
nowakOP4mo ago
Yes I always thought too much stuff was happening in the background. Can I expect that all these 620+ queries are due to this resource table, and I can focus on that only? And what amount of queries should I aim for?
Tonkawuck
Tonkawuck4mo ago
Try to keep a page load under 100 queries. But also the queries themselves should be efficient. Inefficient queries can cause issues in small numbers.
toeknee
toeknee4mo ago
Can you provide your whole table code so we review
nowak
nowakOP4mo ago
Yes of course! Thank you! I thought it would be best to just share the whole php file for the resource. It seems like most of the queries come from my TextColumn::make('userOrders.userOrderItems.product_name'), so that is probably the column that would benefit the most from proper eager loading. But I though I already eager loaded everything that column needs. Apparently not :/
toeknee
toeknee4mo ago
First thing first:
->options(User::couriers()->sortBy('first_name')->pluck('first_name', 'id')->toArray())
->options(User::couriers()->sortBy('first_name')->pluck('first_name', 'id')->toArray())
You shouldn't be calling a queried array of options like that. it should be:
->options(fn() => User::couriers()->sortBy('first_name')->pluck('first_name', 'id')->toArray())
->options(fn() => User::couriers()->sortBy('first_name')->pluck('first_name', 'id')->toArray())
That will reduce it straight away TextColumn::make('userOrders.userOrderItems.product_name') is heavy as, you are calling the product_name, then running a query after the function to find the SKU etc. You should have this as a relationship/join so that product_name is so: userOrders.userOrderItems.product and then the prodiuct should have the SKU, Type, Category etc. All preloading into the main query not more additional queries
nowak
nowakOP4mo ago
Thank you! Interestingly this:
->options(User::couriers()->sortBy('first_name')->pluck('first_name', 'id')->toArray())
->options(User::couriers()->sortBy('first_name')->pluck('first_name', 'id')->toArray())
gives me 661 queries, while this:
->options(fn() => User::couriers()->sortBy('first_name')->pluck('first_name', 'id')->toArray())
->options(fn() => User::couriers()->sortBy('first_name')->pluck('first_name', 'id')->toArray())
gives me 697 queries, so using the closure seems to increase the amount of queries, hmm.. This is before I have attempted to optimize the TextColumn::make('userOrders.userOrderItems.product_name') column.
Zen Nitiruj
Zen Nitiruj4mo ago
It looks complicated. Look like you try to get all in formation loaded in the table. Each table record will queries many many times. I would think that you should make another database table for this. If your data have been saved to another table like group_order_management, where they created final result. Then your model GroupOrderManagement and This resource will just load quickly in table.
toeknee
toeknee4mo ago
Fairly sure you don't need the toArray() in a pluck method but could be wrong
nowak
nowakOP4mo ago
I don't think it should be necessary with another table. It seems like I have reduced the queries to ~137 already by modifying my eager loading in the table query:
return $table
->query(GroupOrderResource::getEloquentQuery()->with([
'userOrders.userOrderItems.productSku.product.category',
'userOrders.userOrderItems.productSku.product.type',
'route'
])->activeDayGroupOrders())
return $table
->query(GroupOrderResource::getEloquentQuery()->with([
'userOrders.userOrderItems.productSku.product.category',
'userOrders.userOrderItems.productSku.product.type',
'route'
])->activeDayGroupOrders())
And using this relationship in my problematic TextColumn:
TextColumn::make('userOrders.userOrderItems.productSku.product.name')
TextColumn::make('userOrders.userOrderItems.productSku.product.name')
True, then this:
->options(fn() => User::couriers()->sortBy('first_name')->pluck('first_name', 'id'))
->options(fn() => User::couriers()->sortBy('first_name')->pluck('first_name', 'id'))
Gives me ~ 2 queries less than this:
->options(User::couriers()->sortBy('first_name')->pluck('first_name', 'id'))
->options(User::couriers()->sortBy('first_name')->pluck('first_name', 'id'))
toeknee
toeknee4mo ago
Correct, a small improvement atleast. Well done on the table query loading 😄
nowak
nowakOP4mo ago
Thank you! I still have some improvements to do, especially with how I use the OrderStatus model, but this jump started my progress in optimizing my eloquent relationships and loading 🙂
Want results from more Discord servers?
Add your server