diff --git a/composer.json b/composer.json index b92a7f8..bdab78c 100644 --- a/composer.json +++ b/composer.json @@ -47,13 +47,15 @@ "dbrekelmans/bdi": "^1.1", "infection/infection": "^0.28", "phpstan/extension-installer": "^1.1", + "phpstan/phpdoc-parser": "^1.28", "phpstan/phpstan": "^1.0", "phpstan/phpstan-beberlei-assert": "^1.0", "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^10.1", + "phpunit/phpunit": "^10.1|^11.0", "rector/rector": "^1.0", + "staabm/phpstan-todo-by": "^0.1.25", "symfony/filesystem": "^6.4|^7.0", "symfony/framework-bundle": "^6.4|^7.0", "symfony/mime": "^6.4|^7.0", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e53359a..f78b5f7 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -231,12 +231,7 @@ parameters: path: src/Dto/Manifest.php - - message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\PageCache has an uninitialized property \\$matchCallback\\. Give it default value or assign it in the constructor\\.$#" - count: 1 - path: src/Dto/PageCache.php - - - - message: "#^PHPDoc tag @var for property SpomkyLabs\\\\PwaBundle\\\\Dto\\\\PageCache\\:\\:\\$cacheableResponseHeaders with type array\\\\|null is not subtype of native type array\\.$#" + message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\PageCache extends @final class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\ResourceCache\\.$#" count: 1 path: src/Dto/PageCache.php @@ -260,6 +255,11 @@ parameters: count: 1 path: src/Dto/RelatedApplication.php + - + message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\ResourceCache has an uninitialized property \\$matchCallback\\. Give it default value or assign it in the constructor\\.$#" + count: 1 + path: src/Dto/ResourceCache.php + - message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\ScopeExtension has an uninitialized property \\$origin\\. Give it default value or assign it in the constructor\\.$#" count: 1 diff --git a/rector.php b/rector.php index fe8046d..14591a0 100644 --- a/rector.php +++ b/rector.php @@ -3,6 +3,7 @@ declare(strict_types=1); use Rector\Config\RectorConfig; +use Rector\DeadCode\Rector\ClassMethod\RemoveEmptyClassMethodRector; use Rector\Doctrine\Set\DoctrineSetList; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Set\ValueObject\LevelSetList; @@ -26,7 +27,9 @@ ]); $config->phpVersion(PhpVersion::PHP_82); $config->paths([__DIR__ . '/src', __DIR__ . '/tests', __DIR__ . '/ecs.php', __DIR__ . '/rector.php']); - $config->skip([__DIR__ . '/tests/Controller/DummyController.php']); + $config->skip([ + RemoveEmptyClassMethodRector::class => [__DIR__ . '/tests/Controller/'], + ]); $config->parallel(); $config->importNames(); $config->importShortClasses(); diff --git a/src/Attribute/PreloadUrl.php b/src/Attribute/PreloadUrl.php new file mode 100644 index 0000000..9fb68d0 --- /dev/null +++ b/src/Attribute/PreloadUrl.php @@ -0,0 +1,22 @@ + $params + */ + public function __construct( + public string $alias, + public array $params = [], + public int $pathTypeReference = UrlGeneratorInterface::ABSOLUTE_PATH, + ) { + } +} diff --git a/src/Attribute/PreloadUrlCompilerPass.php b/src/Attribute/PreloadUrlCompilerPass.php new file mode 100644 index 0000000..327cb53 --- /dev/null +++ b/src/Attribute/PreloadUrlCompilerPass.php @@ -0,0 +1,131 @@ +findAllTaggedRoutes($container) as $alias => $urls) { + $definitionId = sprintf('spomky_labs_pwa.preload_urls_tag_generator.%s', $alias); + $definition = new ChildDefinition(PreloadUrlsTagGenerator::class); + $definition + ->setArguments([ + '$alias' => $alias, + '$urls' => $urls, + ]) + ->addTag('spomky_labs_pwa.preload_urls_generator') + ; + $container->setDefinition($definitionId, $definition); + } + } + + /** + * @return array, pathTypeReference: int}[]> + */ + private function findAllTaggedRoutes(ContainerBuilder $container): array + { + $routes = []; + $controllers = $container->findTaggedServiceIds('controller.service_arguments'); + foreach (array_keys($controllers) as $controller) { + if (! is_string($controller) || ! class_exists($controller)) { + continue; + } + $reflectionClass = new ReflectionClass($controller); + $result = $this->findAllPreloadAttributesForClass($reflectionClass); + foreach ($result as $route) { + if (! array_key_exists($route['alias'], $routes)) { + $routes[$route['alias']] = []; + } + $routes[$route['alias']][] = $route; + } + } + + return $routes; + } + + /** + * @param ReflectionClass $reflectionClass + * @return iterable, pathTypeReference: int}> + */ + private function findAllPreloadAttributesForClass(ReflectionClass $reflectionClass): iterable + { + foreach ($reflectionClass->getAttributes(PreloadUrl::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) { + try { + /** @var PreloadUrl $preloadAttribute */ + $preloadAttribute = $attribute->newInstance(); + yield from $this->findAllRoutesToPreload( + $preloadAttribute, + $reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) + ); + } catch (Throwable $e) { + throw new RuntimeException(sprintf('Unable to create attribute instance: %s', $e->getMessage()), 0, $e); + } + } + foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + foreach ($method->getAttributes(PreloadUrl::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) { + try { + /** @var PreloadUrl $preloadAttribute */ + $preloadAttribute = $attribute->newInstance(); + yield from $this->findAllRoutesForMethod($preloadAttribute, $method); + } catch (Throwable $e) { + throw new RuntimeException(sprintf( + 'Unable to create attribute instance: %s', + $e->getMessage() + ), 0, $e); + } + } + } + } + + /** + * @param array $methods + * @return iterable, pathTypeReference: int}> + */ + private function findAllRoutesToPreload(PreloadUrl $preloadAttribute, array $methods): iterable + { + foreach ($methods as $method) { + yield from $this->findAllRoutesForMethod($preloadAttribute, $method); + } + } + + /** + * @return iterable, pathTypeReference: int}> + */ + private function findAllRoutesForMethod(PreloadUrl $preloadAttribute, ReflectionMethod $method): iterable + { + foreach ($method->getAttributes(Route::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) { + try { + /** @var Route $routeAttribute */ + $routeAttribute = $attribute->newInstance(); + $routeName = $routeAttribute->getName(); + if ($routeName === null) { + continue; + } + yield [ + 'alias' => $preloadAttribute->alias, + 'route' => $routeName, + 'params' => $preloadAttribute->params, + 'pathTypeReference' => $preloadAttribute->pathTypeReference, + ]; + } catch (Throwable) { + continue; + } + } + } +} diff --git a/src/CachingStrategy/PreloadUrlsGeneratorInterface.php b/src/CachingStrategy/PreloadUrlsGeneratorInterface.php new file mode 100644 index 0000000..dbc3cd1 --- /dev/null +++ b/src/CachingStrategy/PreloadUrlsGeneratorInterface.php @@ -0,0 +1,17 @@ + + */ + public function generateUrls(): iterable; +} diff --git a/src/CachingStrategy/PreloadUrlsGeneratorManager.php b/src/CachingStrategy/PreloadUrlsGeneratorManager.php new file mode 100644 index 0000000..ef6f5f4 --- /dev/null +++ b/src/CachingStrategy/PreloadUrlsGeneratorManager.php @@ -0,0 +1,45 @@ + + */ + private array $generators = []; + + /** + * @param PreloadUrlsGeneratorInterface[] $generators + */ + public function __construct( + #[TaggedIterator('spomky_labs_pwa.preload_urls_generator')] + iterable $generators + ) { + foreach ($generators as $generator) { + $this->add($generator); + } + } + + public function add(PreloadUrlsGeneratorInterface $generator, PreloadUrlsGeneratorInterface ...$generators): void + { + $this->generators[$generator->getAlias()] = $generator; + foreach ($generators as $value) { + $this->generators[$generator->getAlias()] = $value; + } + } + + public function get(string $alias): PreloadUrlsGeneratorInterface + { + if (! array_key_exists($alias, $this->generators)) { + throw new InvalidArgumentException(sprintf('The generator with alias "%s" does not exist.', $alias)); + } + return $this->generators[$alias]; + } +} diff --git a/src/CachingStrategy/PreloadUrlsTagGenerator.php b/src/CachingStrategy/PreloadUrlsTagGenerator.php new file mode 100644 index 0000000..9181ff8 --- /dev/null +++ b/src/CachingStrategy/PreloadUrlsTagGenerator.php @@ -0,0 +1,41 @@ + + */ + private array $urls; + + /** + * @param array{route: string, params: array, pathTypeReference: int}[] $urls + */ + public function __construct( + private string $alias, + array $urls + ) { + $this->urls = array_map( + static fn (array $url): Url => Url::create($url['route'], $url['params'], $url['pathTypeReference']), + $urls + ); + } + + public function getAlias(): string + { + return $this->alias; + } + + /** + * @return iterable + */ + public function generateUrls(): iterable + { + return $this->urls; + } +} diff --git a/src/CachingStrategy/ResourceCaches.php b/src/CachingStrategy/ResourceCaches.php index 52831ff..15cb0f5 100644 --- a/src/CachingStrategy/ResourceCaches.php +++ b/src/CachingStrategy/ResourceCaches.php @@ -5,6 +5,7 @@ namespace SpomkyLabs\PwaBundle\CachingStrategy; use SpomkyLabs\PwaBundle\Dto\ServiceWorker; +use SpomkyLabs\PwaBundle\Dto\Url; use SpomkyLabs\PwaBundle\Dto\Workbox; use SpomkyLabs\PwaBundle\MatchCallbackHandler\MatchCallbackHandlerInterface; use SpomkyLabs\PwaBundle\WorkboxPlugin\BroadcastUpdatePlugin; @@ -31,6 +32,7 @@ * @param iterable $matchCallbackHandlers */ public function __construct( + private PreloadUrlsGeneratorManager $preloadUrlsGeneratorManager, ServiceWorker $serviceWorker, private SerializerInterface $serializer, #[TaggedIterator('spomky_labs_pwa.match_callback_handler')] @@ -50,11 +52,10 @@ public function getCacheStrategies(): array { $strategies = []; foreach ($this->workbox->resourceCaches as $id => $resourceCache) { - $routes = $this->serializer->serialize($resourceCache->urls, 'json', [ + $routes = $this->serializer->serialize($this->getUrls($resourceCache->urls), 'json', [ JsonEncode::OPTIONS => $this->jsonOptions, ]); $urls = json_decode($routes, true, 512, JSON_THROW_ON_ERROR); - $cacheName = $resourceCache->cacheName ?? sprintf('page-cache-%d', $id); $plugins = [ @@ -104,4 +105,26 @@ private function prepareMatchCallback(string $matchCallback): string return $matchCallback; } + + /** + * @param array $urls + * @return array + */ + private function getUrls(array $urls): array + { + $result = []; + foreach ($urls as $url) { + if (str_starts_with($url->path, '@')) { + $generator = $this->preloadUrlsGeneratorManager->get(mb_substr($url->path, 1)); + $list = $generator->generateUrls(); + foreach ($list as $item) { + $result[] = $item; + } + } else { + $result[] = $url; + } + } + + return $result; + } } diff --git a/src/Dto/PageCache.php b/src/Dto/PageCache.php index 3eb1245..069010f 100644 --- a/src/Dto/PageCache.php +++ b/src/Dto/PageCache.php @@ -4,44 +4,9 @@ namespace SpomkyLabs\PwaBundle\Dto; -use Symfony\Component\Serializer\Attribute\SerializedName; - -final class PageCache extends Cache +/** + * @deprecated since 1.2.0 and will be removed in 2.0.0. Use ResourceCache instead. + */ +final class PageCache extends ResourceCache { - #[SerializedName('match_callback')] - public string $matchCallback; - - #[SerializedName('network_timeout')] - public int $networkTimeout = 3; - - public string $strategy = 'NetworkFirst'; - - public bool $broadcast = false; - - #[SerializedName('range_requests')] - public bool $rangeRequests = false; - - /** - * @var int[] - */ - #[SerializedName('cacheable_response_statuses')] - public array $cacheableResponseStatuses = [0, 200]; - - /** - * @var null|array - */ - #[SerializedName('cacheable_response_headers')] - public array $cacheableResponseHeaders = []; - - /** - * @var array - */ - #[SerializedName('broadcast_headers')] - public array $broadcastHeaders = ['Content-Type', 'ETag', 'Last-Modified']; - - /** - * @var array - */ - #[SerializedName('preload_urls')] - public array $urls = []; } diff --git a/src/Dto/ResourceCache.php b/src/Dto/ResourceCache.php new file mode 100644 index 0000000..04971b8 --- /dev/null +++ b/src/Dto/ResourceCache.php @@ -0,0 +1,50 @@ + + */ + #[SerializedName('cacheable_response_headers')] + public array $cacheableResponseHeaders = []; + + /** + * @var array + */ + #[SerializedName('broadcast_headers')] + public array $broadcastHeaders = ['Content-Type', 'ETag', 'Last-Modified']; + + /** + * @var array + */ + #[SerializedName('preload_urls')] + public array $urls = []; +} diff --git a/src/Dto/Url.php b/src/Dto/Url.php index 0e9110e..d79562c 100644 --- a/src/Dto/Url.php +++ b/src/Dto/Url.php @@ -18,4 +18,20 @@ final class Url * @var array */ public array $params = []; + + /** + * @param array $params + */ + public static function create( + string $path, + array $params = [], + int $pathTypeReference = UrlGeneratorInterface::ABSOLUTE_PATH + ): self { + $url = new self(); + $url->path = $path; + $url->pathTypeReference = $pathTypeReference; + $url->params = $params; + + return $url; + } } diff --git a/src/Resources/config/services.php b/src/Resources/config/services.php index f446019..fb2a613 100644 --- a/src/Resources/config/services.php +++ b/src/Resources/config/services.php @@ -4,6 +4,8 @@ use Facebook\WebDriver\WebDriverDimension; use SpomkyLabs\PwaBundle\CachingStrategy\HasCacheStrategiesInterface; +use SpomkyLabs\PwaBundle\CachingStrategy\PreloadUrlsGeneratorManager; +use SpomkyLabs\PwaBundle\CachingStrategy\PreloadUrlsTagGenerator; use SpomkyLabs\PwaBundle\Command\CreateIconsCommand; use SpomkyLabs\PwaBundle\Command\CreateScreenshotCommand; use SpomkyLabs\PwaBundle\Command\ListCacheStrategiesCommand; @@ -21,11 +23,14 @@ use SpomkyLabs\PwaBundle\Subscriber\PwaDevServerSubscriber; use SpomkyLabs\PwaBundle\Subscriber\ServiceWorkerCompileEventListener; use SpomkyLabs\PwaBundle\Subscriber\WorkboxCompileEventListener; +use SpomkyLabs\PwaBundle\Twig\InstanceOfExtension; use SpomkyLabs\PwaBundle\Twig\PwaExtension; use SpomkyLabs\PwaBundle\Twig\PwaRuntime; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\Mime\MimeTypes; use Symfony\Component\Panther\Client; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use function Symfony\Component\DependencyInjection\Loader\Configurator\abstract_arg; use function Symfony\Component\DependencyInjection\Loader\Configurator\param; use function Symfony\Component\DependencyInjection\Loader\Configurator\service; @@ -126,6 +131,18 @@ ; $container->load('SpomkyLabs\\PwaBundle\\MatchCallbackHandler\\', '../../MatchCallbackHandler/*'); + $container->set(PreloadUrlsGeneratorManager::class); + $container->instanceof(UrlGeneratorInterface::class) + ->tag('spomky_labs_pwa.preload_urls_generator') + ; + $container->set(PreloadUrlsTagGenerator::class) + ->abstract() + ->args([ + '$alias' => abstract_arg('alias'), + '$urls' => abstract_arg('urls'), + ]) + ; + if ($configurator->env() !== 'prod') { $container->set(PwaCollector::class) ->tag('data_collector', [ @@ -133,5 +150,6 @@ 'id' => 'pwa', ]) ; + $container->set(InstanceOfExtension::class); } }; diff --git a/src/SpomkyLabsPwaBundle.php b/src/SpomkyLabsPwaBundle.php index f698c7f..77e87f4 100644 --- a/src/SpomkyLabsPwaBundle.php +++ b/src/SpomkyLabsPwaBundle.php @@ -4,6 +4,7 @@ namespace SpomkyLabs\PwaBundle; +use SpomkyLabs\PwaBundle\Attribute\PreloadUrlCompilerPass; use SpomkyLabs\PwaBundle\ImageProcessor\ImageProcessorInterface; use SpomkyLabs\PwaBundle\Subscriber\PwaDevServerSubscriber; use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator; @@ -21,6 +22,11 @@ public function configure(DefinitionConfigurator $definition): void $definition->import('Resources/config/definition/*.php'); } + public function build(ContainerBuilder $container): void + { + $container->addCompilerPass(new PreloadUrlCompilerPass()); + } + public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void { $container->import('Resources/config/services.php'); diff --git a/src/Twig/InstanceOfExtension.php b/src/Twig/InstanceOfExtension.php new file mode 100644 index 0000000..7e5cbcc --- /dev/null +++ b/src/Twig/InstanceOfExtension.php @@ -0,0 +1,38 @@ +isInstanceOf(...))]; + } + + public function getFilters(): array + { + return [new TwigFilter('instanceof', $this->isInstanceOf(...))]; + } + + public function getTests(): array + { + return [new TwigTest('instanceof', $this->isInstanceOf(...))]; + } + + /** + * @param class-string $instance + */ + public function isInstanceOf(object $var, string $instance): bool + { + $reflexionClass = new ReflectionClass($instance); + return $reflexionClass->isInstance($var); + } +} diff --git a/src/WorkboxPlugin/BackgroundSyncPlugin.php b/src/WorkboxPlugin/BackgroundSyncPlugin.php index 825a528..c1c9bea 100644 --- a/src/WorkboxPlugin/BackgroundSyncPlugin.php +++ b/src/WorkboxPlugin/BackgroundSyncPlugin.php @@ -4,7 +4,7 @@ namespace SpomkyLabs\PwaBundle\WorkboxPlugin; -final readonly class BackgroundSyncPlugin implements CachePluginInterface +final readonly class BackgroundSyncPlugin implements CachePluginInterface, HasDebugInterface { private const NAME = 'BackgroundSyncPlugin'; @@ -60,4 +60,14 @@ public static function create( ): static { return new self($queueName, $forceSyncFallback, $broadcastChannel, $maxRetentionTime); } + + public function getDebug(): array + { + return [ + 'queueName' => $this->queueName, + 'forceSyncFallback' => $this->forceSyncFallback, + 'broadcastChannel' => $this->broadcastChannel, + 'maxRetentionTime' => $this->maxRetentionTime, + ]; + } } diff --git a/src/WorkboxPlugin/BroadcastUpdatePlugin.php b/src/WorkboxPlugin/BroadcastUpdatePlugin.php index 6a97005..8d5011d 100644 --- a/src/WorkboxPlugin/BroadcastUpdatePlugin.php +++ b/src/WorkboxPlugin/BroadcastUpdatePlugin.php @@ -4,7 +4,7 @@ namespace SpomkyLabs\PwaBundle\WorkboxPlugin; -final readonly class BroadcastUpdatePlugin implements CachePluginInterface +final readonly class BroadcastUpdatePlugin implements CachePluginInterface, HasDebugInterface { private const NAME = 'BroadcastUpdatePlugin'; @@ -44,4 +44,11 @@ public static function create(array $headersToCheck = []): static { return new self($headersToCheck); } + + public function getDebug(): array + { + return [ + 'headersToCheck' => $this->headersToCheck, + ]; + } } diff --git a/src/WorkboxPlugin/CacheableResponsePlugin.php b/src/WorkboxPlugin/CacheableResponsePlugin.php index b55ccb2..011d145 100644 --- a/src/WorkboxPlugin/CacheableResponsePlugin.php +++ b/src/WorkboxPlugin/CacheableResponsePlugin.php @@ -4,7 +4,7 @@ namespace SpomkyLabs\PwaBundle\WorkboxPlugin; -final readonly class CacheableResponsePlugin implements CachePluginInterface +final readonly class CacheableResponsePlugin implements CachePluginInterface, HasDebugInterface { private const NAME = 'CacheableResponsePlugin'; @@ -49,4 +49,12 @@ public function getName(): string { return self::NAME; } + + public function getDebug(): array + { + return [ + 'statuses' => $this->options['statuses'] ?? [], + 'headers' => $this->options['headers'] ?? [], + ]; + } } diff --git a/src/WorkboxPlugin/ExpirationPlugin.php b/src/WorkboxPlugin/ExpirationPlugin.php index dff905a..79eb733 100644 --- a/src/WorkboxPlugin/ExpirationPlugin.php +++ b/src/WorkboxPlugin/ExpirationPlugin.php @@ -4,7 +4,7 @@ namespace SpomkyLabs\PwaBundle\WorkboxPlugin; -final readonly class ExpirationPlugin implements CachePluginInterface +final readonly class ExpirationPlugin implements CachePluginInterface, HasDebugInterface { private const NAME = 'ExpirationPlugin'; @@ -35,4 +35,12 @@ public function getName(): string { return self::NAME; } + + public function getDebug(): array + { + return [ + 'maxEntries' => $this->options['maxEntries'] ?? null, + 'maxAgeSeconds' => $this->options['maxAgeSeconds'] ?? null, + ]; + } } diff --git a/src/WorkboxPlugin/HasDebugInterface.php b/src/WorkboxPlugin/HasDebugInterface.php new file mode 100644 index 0000000..2b6132f --- /dev/null +++ b/src/WorkboxPlugin/HasDebugInterface.php @@ -0,0 +1,13 @@ + + */ + public function getDebug(): array; +} diff --git a/src/WorkboxPlugin/RangeRequestsPlugin.php b/src/WorkboxPlugin/RangeRequestsPlugin.php index d4adf80..38edf96 100644 --- a/src/WorkboxPlugin/RangeRequestsPlugin.php +++ b/src/WorkboxPlugin/RangeRequestsPlugin.php @@ -4,7 +4,7 @@ namespace SpomkyLabs\PwaBundle\WorkboxPlugin; -final readonly class RangeRequestsPlugin implements CachePluginInterface +final readonly class RangeRequestsPlugin implements CachePluginInterface, HasDebugInterface { private const NAME = 'RangeRequestsPlugin'; @@ -13,7 +13,7 @@ public function render(int $jsonOptions = 0): string return 'new workbox.rangeRequests.RangeRequestsPlugin()'; } - public static function create(): static + public static function create(): self { return new self(); } @@ -22,4 +22,9 @@ public function getName(): string { return self::NAME; } + + public function getDebug(): array + { + return []; + } } diff --git a/templates/Collector/serviceworker-tab.html.twig b/templates/Collector/serviceworker-tab.html.twig index af145d1..6de1d18 100644 --- a/templates/Collector/serviceworker-tab.html.twig +++ b/templates/Collector/serviceworker-tab.html.twig @@ -140,10 +140,19 @@ {{ cachingStrategy.matchCallback }}
{{ cachingStrategy.getMethod() ?? "GET" }} - - {% for plugin in cachingStrategy.plugins %} - {{ dump(plugin) }} - {% endfor %} + + {% if cachingStrategy.plugins|length == 0 %} + None + {% else %} + {% for plugin in cachingStrategy.plugins %} + {% if plugin is instanceof('SpomkyLabs\\PwaBundle\\WorkboxPlugin\\HasDebugInterface') %} +

{{ plugin.getName() }}

+
{{ plugin.debug()|json_encode(constant('JSON_PRETTY_PRINT'))|nl2br }}
+ {% else %} + {{ dump(plugin) }} + {% endif %} + {% endfor %} + {% endif %} {% set preloadedUrls = cachingStrategy.preloadUrls|length %} diff --git a/tests/Controller/DummyController.php b/tests/Controller/OtherPagesController.php similarity index 54% rename from tests/Controller/DummyController.php rename to tests/Controller/OtherPagesController.php index 032af58..4fd4883 100644 --- a/tests/Controller/DummyController.php +++ b/tests/Controller/OtherPagesController.php @@ -10,18 +10,8 @@ /** * @internal */ -final class DummyController extends AbstractController +final class OtherPagesController extends AbstractController { - #[Route('/privacy-policy', name: 'privacy_policy')] - public function privacyPolicy(string $param1): void - { - } - - #[Route('/terms-of-service', name: 'terms_of_service')] - public function tos(string $param1): void - { - } - #[Route('/audio-file-handler/{param1}', name: 'audio_file_handler')] public function dummy1(string $param1): void { @@ -36,14 +26,4 @@ public function dummy2(string $param1, string $param2): void public function agenda(string $date): void { } - - #[Route('/widget/template', name: 'app_widget_template')] - public function widgetTemplate(): void - { - } - - #[Route('/widget/data', name: 'app_widget_data')] - public function widgetData(): void - { - } } diff --git a/tests/Controller/StaticPagesController.php b/tests/Controller/StaticPagesController.php new file mode 100644 index 0000000..44a7ba5 --- /dev/null +++ b/tests/Controller/StaticPagesController.php @@ -0,0 +1,26 @@ +services() - ->set(DummyImageProcessor::class); - $container->services() - ->set('asset_mapper.local_public_assets_filesystem', TestFilesystem::class) + $services = $container + ->services() + ->defaults() + ->autowire() ->autoconfigure() - ->autowire(); - - $container->services() - ->load('SpomkyLabs\\PwaBundle\\Tests\\Controller\\', __DIR__ . '/Controller/') - ->tag('controller.service_arguments') + ; + $services->set(DummyImageProcessor::class); + $services->set('asset_mapper.local_public_assets_filesystem', TestFilesystem::class); + $services->load('SpomkyLabs\\PwaBundle\\Tests\\Controller\\', __DIR__ . '/Controller/'); + $services + ->set(DummyUrlsGenerator::class) + ->tag('spomky_labs_pwa.preload_urls_generator') ; $container->extension('framework', [ @@ -232,7 +235,7 @@ 'strategy' => 'StaleWhileRevalidate', 'cache_name' => 'page-cache', 'broadcast' => true, - 'preload_urls' => ['privacy_policy', 'terms_of_service'], + 'preload_urls' => ['privacy_policy', 'terms_of_service', '@static-pages', '@widgets'], ], ], 'offline_fallback' => [