Navigation Loaded Twice, Causing Badge SQL Query to Run Twice
Package
filament/filament
Package Version
v3.2
Laravel Version
v11
Livewire Version
No response
PHP Version
8.2
Problem description
While preparing a video based on the official filament demo, noticed two queries running for the badge:
Debugged a bit deeper and discovered that the whole menu is being loaded twice.
Confirmed that I'm not alone, by two discussions opened by the same person:
- https://github.com/filamentphp/filament/discussions/10285
- https://github.com/filamentphp/filament/discussions/10204
But those discussions didn't lead to any issues opened, at least I haven't found, so creating one.
Made a bit of a source-dive. Managed to locate the problem but didn't manage to fix it.
Discovered that new NavigationManager() is called twice: https://github.com/search?q=repo%3Afilamentphp%2Ffilament%20new%20NavigationManager&type=code
- In
FilamentServiceProvider - And in
HasRoutesconcern
There seems to be a check to prevent double-loading but for some reason it doesn't trigger for me: https://github.com/filamentphp/filament/blob/d00919cbac22c9b8648b114815ab635aaac6d509/packages/panels/src/Navigation/NavigationManager.php#L49
if (! $this->isNavigationMounted) {
$this->mountNavigation();
}
P.S. Interesting part: during my testing, seems that the Cluster part of the menu (Products + Categories + Brands) is loaded only once, not twice. So there's some separate different logic for clusters, probably.
Expected behavior
There should be one SQL query: either by not duplicating the query, or not duplicating the navigation manager call.
Steps to reproduce
Just load the official demo locally and load any page with Laravel Debugbar and see the queries
Reproduction repository (issue will be closed if this is not valid)
https://github.com/filamentphp/demo
Relevant log output
No response
It looks like this issue was introduced by @danharrin as part of #11292 (Boost Octane performance further) in a47673bc44a57cfc115bc7067164dfaf9f329c90 and modified further in 12cc2730b7a545240eba3c2b9e629743cbb513cb, where it was intentionally switched from loading from the service container to newing up a fresh NavigationManager.
A fast workaround for big tables that slowing down the display of the table is to use Cache, until the final fix, e.x.
$newMails = Cache::remember('filamentMailsBandge', now()->addSeconds(30), function () {
return static::getModel()::where('created_at', '>=', Carbon::now()->subHours(12)->toDateTimeString())->count();
});
What about use once() helper to cache the callback to memory.
https://laravel.com/docs/11.x/releases#the-once-function
public static function getNavigationBadge(): ?string
{
return once(function () {
return number_format(static::getModel()::count());
});
}
Not sure if this should be dropped here, but the getNavigationBadge method is also executed for all tenants that the user is connected to, instead of only the active tenant.
I’m experiencing the same issue with badge on tabs in Filament Tables.
collect(Status::cases())->mapWithKeys(function (Status $status) {
return [
$status->value => Tab::make($status->getLabel())
->badge(function () use ($status) {
return Product::where('status', $status)->count();
})
->modifyQueryUsing(function (Builder $query) use ($status) {
$query->where('status', $status);
}),
];
});
The problem is now increased with v4.0.0-beta with 3 duplicate queries not only 2. which means that the method is loaded 3 times
Fixed in v4 by #16624