Performance tuning an enormous InfoList

Hi guys, Given the purely fictional example of an InfoList below...
class ProjectResource extends Resource
{
protected static ?string $model = Project::class;
public static function infolist(Infolist $infolist): Infolist
{
return $infolist
->schema([
Section::make('overview')
->heading(fn(Project $project) => $project->name)
->schema([
TextEntry::make('Field 1')
->state(fn(Project $project) => ($project->isRunning()) ? $project->getStatusLabel() : $project->getCheckStatus()->getLabel())
->visible(fn(Project $project) => $project->isComplete()),

// ...

TextEntry::make('Field 100')
->state(fn(Project $project) => ($project->isRunning()) ?? $project->dependencies())
->visible(fn(Project $project) => $project->hasAnyOutput()),
])
]);
}
}
class ProjectResource extends Resource
{
protected static ?string $model = Project::class;
public static function infolist(Infolist $infolist): Infolist
{
return $infolist
->schema([
Section::make('overview')
->heading(fn(Project $project) => $project->name)
->schema([
TextEntry::make('Field 1')
->state(fn(Project $project) => ($project->isRunning()) ? $project->getStatusLabel() : $project->getCheckStatus()->getLabel())
->visible(fn(Project $project) => $project->isComplete()),

// ...

TextEntry::make('Field 100')
->state(fn(Project $project) => ($project->isRunning()) ?? $project->dependencies())
->visible(fn(Project $project) => $project->hasAnyOutput()),
])
]);
}
}
Where there are 100s of fields, and they all contain calculated content, with active rules around their visibility, so on and so on (picture a giant dashboard showing the monitoring and status of lots of different things), obviously this whole thing is going to be costly in terms of calculating its state, but I feel like it's being made MUCH worse by using Closures everywhere, and therefore instantiating brand new instances of objects each time. I've managed to work around some of this by hard caching results, but given the dynamics, I basically need to limit the lifetime to 5 seconds, and I'm writing a LOT of boilerplate to code to handle it.
1 Reply
Malcolm Turntbull
Malcolm TurntbullOP13mo ago
In this type of scenario, would I be better off instantiating the $project once at the start of the method, and injecting it via local usage, e.g.
$project = app(Project::class);
// ---
->visible(fn() => ($project->isRunning())
$project = app(Project::class);
// ---
->visible(fn() => ($project->isRunning())
Or even bypassing Closures entirely, and just calling the functions directly?
$project = app(Project::class);
// ---
->visible($project->isRunning())
$project = app(Project::class);
// ---
->visible($project->isRunning())
Or as another idea, setting a single instance of the Project as an instance in the Service Container?
app()->instance(Project::class, app(Project::class));
// ---
->visible(fn(Project $project) => ($project->isRunning())
app()->instance(Project::class, app(Project::class));
// ---
->visible(fn(Project $project) => ($project->isRunning())
I'm trying to do this in the cleanest way possible, obviously it's not great to have to prep my objects like this, but it's probably less onerous than having to wrap caching code throughout the Models, and just let the object properties do their thing.
Want results from more Discord servers?
Add your server