fix: Cached configurable resources/pages (#19449)

This commit is contained in:
Dan Harrin
2026-03-08 20:09:08 +00:00
committed by GitHub
parent 784323d89e
commit f91c807393
2 changed files with 177 additions and 52 deletions
@@ -122,9 +122,7 @@ trait HasComponents
*/
public function pages(array $pages): static
{
if ($this->hasCachedComponents()) {
return $this;
}
$hasCachedComponents = $this->hasCachedComponents();
foreach ($pages as $page) {
if ($page instanceof PageConfiguration) {
@@ -142,15 +140,16 @@ trait HasComponents
$this->pageConfigurations[$page->page][$page->getKey()] = $page;
$pageClass = $page->page;
} else {
if (! $hasCachedComponents) {
$this->queueLivewireComponentForRegistration($page->page);
$this->registerToCluster($page->page);
}
} elseif (! $hasCachedComponents) {
$this->pages[] = $page;
$pageClass = $page;
$this->queueLivewireComponentForRegistration($page);
$this->registerToCluster($page);
}
$this->queueLivewireComponentForRegistration($pageClass);
$this->registerToCluster($pageClass);
}
return $this;
@@ -161,9 +160,7 @@ trait HasComponents
*/
public function resources(array $resources): static
{
if ($this->hasCachedComponents()) {
return $this;
}
$hasCachedComponents = $this->hasCachedComponents();
foreach ($resources as $resource) {
if ($resource instanceof ResourceConfiguration) {
@@ -181,14 +178,14 @@ trait HasComponents
$this->resourceConfigurations[$resource->resource][$resource->getKey()] = $resource;
$resourceClass = $resource->resource;
} else {
if (! $hasCachedComponents) {
$this->registerToCluster($resource->resource);
}
} elseif (! $hasCachedComponents) {
$this->resources[] = $resource;
$resourceClass = $resource;
$this->registerToCluster($resource);
}
$this->registerToCluster($resourceClass);
}
return $this;
@@ -731,29 +728,11 @@ trait HasComponents
'clusterDirectories' => $this->clusterDirectories,
'clusterNamespaces' => $this->clusterNamespaces,
'pages' => $this->pages,
'pageConfigurations' => array_map(
static fn (array $configurations): array => array_map(
static fn (PageConfiguration $configuration): array => [
'page' => $configuration->page,
'key' => $configuration->getKey(),
],
$configurations,
),
$this->pageConfigurations,
),
'pageConfigurations' => [],
'pageDirectories' => $this->pageDirectories,
'pageNamespaces' => $this->pageNamespaces,
'resources' => $this->resources,
'resourceConfigurations' => array_map(
static fn (array $configurations): array => array_map(
static fn (ResourceConfiguration $configuration): array => [
'resource' => $configuration->resource,
'key' => $configuration->getKey(),
],
$configurations,
),
$this->resourceConfigurations,
),
'resourceConfigurations' => [],
'resourceDirectories' => $this->resourceDirectories,
'resourceNamespaces' => $this->resourceNamespaces,
'widgets' => $this->widgets,
@@ -779,24 +758,9 @@ trait HasComponents
$this->clusterDirectories = $cache['clusterDirectories'] ?? [];
$this->clusterNamespaces = $cache['clusterNamespaces'] ?? [];
$this->pages = $cache['pages'] ?? [];
$this->pageConfigurations = [];
foreach ($cache['pageConfigurations'] ?? [] as $pageClass => $configurations) {
foreach ($configurations as $configuration) {
$this->pageConfigurations[$pageClass][$configuration['key']] = $configuration['page']::make($configuration['key']);
}
}
$this->pageDirectories = $cache['pageDirectories'] ?? [];
$this->pageNamespaces = $cache['pageNamespaces'] ?? [];
$this->resources = $cache['resources'] ?? [];
$this->resourceConfigurations = [];
foreach ($cache['resourceConfigurations'] ?? [] as $resourceClass => $configurations) {
foreach ($configurations as $configuration) {
$this->resourceConfigurations[$resourceClass][$configuration['key']] = $configuration['resource']::make($configuration['key']);
}
}
$this->resourceDirectories = $cache['resourceDirectories'] ?? [];
$this->resourceNamespaces = $cache['resourceNamespaces'] ?? [];
$this->widgets = $cache['widgets'] ?? [];
+161
View File
@@ -0,0 +1,161 @@
<?php
use Filament\Facades\Filament;
use Filament\Tests\Fixtures\Models\User;
use Filament\Tests\Fixtures\Pages\ConfigurableSettings;
use Filament\Tests\Fixtures\Pages\Settings;
use Filament\Tests\Fixtures\Resources\Posts\ConfigurablePostResource;
use Filament\Tests\Fixtures\Resources\Posts\PostResource;
use Filament\Tests\Fixtures\Resources\Users\UserResource;
use Filament\Tests\TestCase;
uses(TestCase::class);
beforeEach(function (): void {
$this->actingAs(User::factory()->create());
});
afterEach(function (): void {
Filament::getPanel('admin')->clearCachedComponents();
Filament::getPanel('configuration')->clearCachedComponents();
});
it('can cache and restore resources', function (): void {
$panel = Filament::getPanel('admin');
$resourcesBefore = $panel->getResources();
$panel->cacheComponents();
$panel->restoreCachedComponents();
$resourcesAfter = $panel->getResources();
expect($resourcesAfter)->toEqual($resourcesBefore);
expect($resourcesAfter)->toContain(PostResource::class);
expect($resourcesAfter)->toContain(UserResource::class);
});
it('can cache and restore pages', function (): void {
$panel = Filament::getPanel('admin');
$pagesBefore = $panel->getPages();
$panel->cacheComponents();
$panel->restoreCachedComponents();
$pagesAfter = $panel->getPages();
expect($pagesAfter)->toEqual($pagesBefore);
expect($pagesAfter)->toContain(Settings::class);
});
it('can cache and restore widgets', function (): void {
$panel = Filament::getPanel('admin');
$widgetsBefore = $panel->getWidgets();
$panel->cacheComponents();
$panel->restoreCachedComponents();
$widgetsAfter = $panel->getWidgets();
expect($widgetsAfter)->toEqual($widgetsBefore);
});
it('skips duplicate resource class strings when cached', function (): void {
$panel = Filament::getPanel('admin');
$panel->cacheComponents();
$panel->restoreCachedComponents();
// Calling `resources()` again with cached components should not add duplicates
$countBefore = count($panel->getResources());
$panel->resources([PostResource::class]);
$countAfter = count($panel->getResources());
expect($countAfter)->toBe($countBefore);
});
it('skips duplicate page class strings when cached', function (): void {
$panel = Filament::getPanel('admin');
$panel->cacheComponents();
$panel->restoreCachedComponents();
// Calling `pages()` again with cached components should not add duplicates
$countBefore = count($panel->getPages());
$panel->pages([Settings::class]);
$countAfter = count($panel->getPages());
expect($countAfter)->toBe($countBefore);
});
it('can clear cached components', function (): void {
$panel = Filament::getPanel('admin');
$panel->cacheComponents();
expect(file_exists($panel->getComponentCachePath()))->toBeTrue();
$panel->clearCachedComponents();
expect(file_exists($panel->getComponentCachePath()))->toBeFalse();
});
it('preserves resource configurations after caching and restoring components', function (): void {
$panel = Filament::getPanel('configuration');
$panel->cacheComponents();
$panel->restoreCachedComponents();
// Verify configurations still exist
$configurations = $panel->getResourceConfigurations();
expect($configurations)->toHaveCount(2);
// Verify configuration properties are preserved (not just class and key)
$featuredConfig = $panel->getResourceConfiguration(ConfigurablePostResource::class, 'featured');
expect($featuredConfig)->not->toBeNull();
expect($featuredConfig->getSlug())->toBe('featured-posts');
expect($featuredConfig->getNavigationLabel())->toBe('Featured Posts');
expect($featuredConfig->getNavigationGroup())->toBe('Featured Content');
expect($featuredConfig->getNavigationSort())->toBe(1);
expect($featuredConfig->isFeatured())->toBeTrue();
expect($featuredConfig->isArchived())->toBeFalse();
$archivedConfig = $panel->getResourceConfiguration(ConfigurablePostResource::class, 'archived');
expect($archivedConfig)->not->toBeNull();
expect($archivedConfig->getSlug())->toBe('archived-posts');
expect($archivedConfig->getNavigationLabel())->toBe('Archived Posts');
expect($archivedConfig->getNavigationGroup())->toBe('Archive');
expect($archivedConfig->getNavigationSort())->toBe(100);
expect($archivedConfig->isFeatured())->toBeFalse();
expect($archivedConfig->isArchived())->toBeTrue();
});
it('preserves page configurations after caching and restoring components', function (): void {
$panel = Filament::getPanel('configuration');
$panel->cacheComponents();
$panel->restoreCachedComponents();
// Verify configurations still exist
$configurations = $panel->getPageConfigurations();
expect($configurations)->toHaveCount(2);
// Verify configuration properties are preserved (not just class and key)
$generalConfig = $panel->getPageConfiguration(ConfigurableSettings::class, 'general');
expect($generalConfig)->not->toBeNull();
expect($generalConfig->getSlug())->toBe('general-settings');
expect($generalConfig->getNavigationLabel())->toBe('General Settings');
expect($generalConfig->getNavigationGroup())->toBe('Settings');
expect($generalConfig->getNavigationSort())->toBe(1);
expect($generalConfig->getSettingsCategory())->toBe('general');
$advancedConfig = $panel->getPageConfiguration(ConfigurableSettings::class, 'advanced');
expect($advancedConfig)->not->toBeNull();
expect($advancedConfig->getSlug())->toBe('advanced-settings');
expect($advancedConfig->getNavigationLabel())->toBe('Advanced Settings');
expect($advancedConfig->getNavigationGroup())->toBe('Settings');
expect($advancedConfig->getNavigationSort())->toBe(2);
expect($advancedConfig->getSettingsCategory())->toBe('advanced');
});