F
Filament4mo ago
morty

Where would be the best place to centralize this data so it's only queried once?

I have the following dashboard:
class SeedDashboard extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-chart-bar-square';

protected static string $view = 'filament.crm.pages.seed-dashboard';

protected function getHeaderWidgets(): array
{
return [
SeedStatsOverview::class,
SeedTargetsByGroupChart::class,
SeedOrdersByGroupChart::class,
];
}
}
class SeedDashboard extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-chart-bar-square';

protected static string $view = 'filament.crm.pages.seed-dashboard';

protected function getHeaderWidgets(): array
{
return [
SeedStatsOverview::class,
SeedTargetsByGroupChart::class,
SeedOrdersByGroupChart::class,
];
}
}
As you can see, it has 3 different widgets. However, all of the widgets use the same database query to get the data and this query is somewhat expensive so I don't want to run it 3 times, once for each widget. Where would the best place be to centralize the query so that all 3 widgets can access it but it's only run once per request? edit: My current thought is on the SeedDashboard class itself, perhaps maybe in the mount method? But I'm unsure how this works for my widgets to access it.
11 Replies
awcodes
awcodes4mo ago
It’s not the same query though, is it? And each widget is its own livewire component.
morty
mortyOP4mo ago
And each widget is its own livewire component.
That's what I was wondering, so hmm. Also, yes it is the same query. It's a big complicated raw SQL query.
awcodes
awcodes4mo ago
If the data is different in each widget then it can’t be the same query.
morty
mortyOP4mo ago
it's the same database query, but I'm using laravel collections to pluck out the stuff I need for each widget for example
protected function formatData(Collection $data): array
{
$currentFiscalYear = FiscalYearHelper::getFiscalYear();
$previousFiscalYear = FiscalYearHelper::getPreviousFiscalYear();

$formattedData = [];

foreach (SeedProductGroup::cases() as $seedProductGroup) {
$chartData = $data
->where('group_code', $seedProductGroup)
->sortBy('fiscal_year')
->pluck('quantity', 'fiscal_year')
->toArray();

$value = Number::format($chartData[$currentFiscalYear], 0);
$variance = $chartData[$currentFiscalYear] - $chartData[$previousFiscalYear];
$varianceDescription = Number::abbreviate(abs($variance), 1);
$varianceIncreaseDecrease = $variance > 0 ? 'increase' : 'decrease';
$description = "{$varianceDescription} {$varianceIncreaseDecrease}";
$descriptionIcon = $variance > 0 ? 'heroicon-m-arrow-trending-up' : 'heroicon-m-arrow-trending-down';
$color = $variance > 0 ? 'success' : 'danger';

$formattedData[$seedProductGroup->value]['value'] = $value;
$formattedData[$seedProductGroup->value]['description'] = $description;
$formattedData[$seedProductGroup->value]['descriptionIcon'] = $descriptionIcon;
$formattedData[$seedProductGroup->value]['color'] = $color;
$formattedData[$seedProductGroup->value]['chart'] = $chartData;
}

return $formattedData;
}
protected function formatData(Collection $data): array
{
$currentFiscalYear = FiscalYearHelper::getFiscalYear();
$previousFiscalYear = FiscalYearHelper::getPreviousFiscalYear();

$formattedData = [];

foreach (SeedProductGroup::cases() as $seedProductGroup) {
$chartData = $data
->where('group_code', $seedProductGroup)
->sortBy('fiscal_year')
->pluck('quantity', 'fiscal_year')
->toArray();

$value = Number::format($chartData[$currentFiscalYear], 0);
$variance = $chartData[$currentFiscalYear] - $chartData[$previousFiscalYear];
$varianceDescription = Number::abbreviate(abs($variance), 1);
$varianceIncreaseDecrease = $variance > 0 ? 'increase' : 'decrease';
$description = "{$varianceDescription} {$varianceIncreaseDecrease}";
$descriptionIcon = $variance > 0 ? 'heroicon-m-arrow-trending-up' : 'heroicon-m-arrow-trending-down';
$color = $variance > 0 ? 'success' : 'danger';

$formattedData[$seedProductGroup->value]['value'] = $value;
$formattedData[$seedProductGroup->value]['description'] = $description;
$formattedData[$seedProductGroup->value]['descriptionIcon'] = $descriptionIcon;
$formattedData[$seedProductGroup->value]['color'] = $color;
$formattedData[$seedProductGroup->value]['chart'] = $chartData;
}

return $formattedData;
}
The $data that is passed to this method is the database query results
awcodes
awcodes4mo ago
But each widget is a separate livewire component meaning they are running their own query on mount. Unless you are running the query on the page and passing the data to each widget for further processing they are going to run their own query.
morty
mortyOP4mo ago
Unless you are running the query on the page and passing the data to each widget for further processing they are going to run their own query.
This is exactly what I want to do, but unsure how since the getHeaderWidgets just takes an array of the widget classes If I was building a basic Livewire app, I'd just pass the data to the child component, but not sure where to do that in a Filament app
awcodes
awcodes4mo ago
You can pass data to widgets. They are still just livewire components.
morty
mortyOP4mo ago
Where would I do that? The view is empty. Normally in a non-filament app I'd do it in the view with <livewire:todo-count :todos="$todos" /> but in a Filament app, this page just has a blank view.
morty
mortyOP4mo ago
sorry this is probably a stupid question omg I just needed to RTFM... sorry, and thanks 😄
awcodes
awcodes4mo ago
No worries

Did you find this page helpful?