diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e53359a..b5f0f29 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,16 @@ 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: "#^PHPDoc tag @var for property SpomkyLabs\\\\PwaBundle\\\\Dto\\\\ResourceCache\\:\\:\\$cacheableResponseHeaders with type array\\\\|null is not subtype of native type array\\.$#" + 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 @@ -340,6 +345,11 @@ parameters: count: 1 path: src/Dto/Url.php + - + message: "#^Method SpomkyLabs\\\\PwaBundle\\\\Dto\\\\Url\\:\\:create\\(\\) has parameter \\$params with no value type specified in iterable type array\\.$#" + count: 1 + path: src/Dto/Url.php + - message: "#^Class SpomkyLabs\\\\PwaBundle\\\\Dto\\\\Widget has an uninitialized property \\$adaptativeCardTemplate\\. Give it default value or assign it in the constructor\\.$#" count: 1 diff --git a/src/CachingStrategy/PreloadUrlsGeneratorInterface.php b/src/CachingStrategy/PreloadUrlsGeneratorInterface.php new file mode 100644 index 0000000..fa1497d --- /dev/null +++ b/src/CachingStrategy/PreloadUrlsGeneratorInterface.php @@ -0,0 +1,15 @@ + + */ + public function generateUrls(): iterable; +} diff --git a/src/CachingStrategy/PreloadUrlsGeneratorManager.php b/src/CachingStrategy/PreloadUrlsGeneratorManager.php new file mode 100644 index 0000000..97f0e18 --- /dev/null +++ b/src/CachingStrategy/PreloadUrlsGeneratorManager.php @@ -0,0 +1,29 @@ + + */ + private array $generators = []; + + public function add(string $alias, PreloadUrlsGeneratorInterface $generator): void + { + $this->generators[$alias] = $generator; + } + + 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/ResourceCaches.php b/src/CachingStrategy/ResourceCaches.php index 52831ff..ffa374b 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,7 +52,7 @@ 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); @@ -104,4 +106,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/DependencyInjection/Compiler/AddPreloadUrlsGeneratorPass.php b/src/DependencyInjection/Compiler/AddPreloadUrlsGeneratorPass.php new file mode 100644 index 0000000..db465dd --- /dev/null +++ b/src/DependencyInjection/Compiler/AddPreloadUrlsGeneratorPass.php @@ -0,0 +1,32 @@ +has(PreloadUrlsGeneratorManager::class)) { + return; + } + $definition = $container->findDefinition(PreloadUrlsGeneratorManager::class); + foreach ($container->findTaggedServiceIds(self::TAG) as $id => $tags) { + foreach ($tags as $attributes) { + if (! isset($attributes['alias'])) { + throw new InvalidArgumentException('The alias is required'); + } + $definition->addMethodCall('add', [$attributes['alias'], new Reference($id)]); + } + } + } +} 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..bfa376f --- /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..5b0937f 100644 --- a/src/Dto/Url.php +++ b/src/Dto/Url.php @@ -18,4 +18,17 @@ final class Url * @var array */ public 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 a368deb..9831c93 100644 --- a/src/Resources/config/services.php +++ b/src/Resources/config/services.php @@ -4,6 +4,7 @@ use Facebook\WebDriver\WebDriverDimension; use SpomkyLabs\PwaBundle\CachingStrategy\HasCacheStrategiesInterface; +use SpomkyLabs\PwaBundle\CachingStrategy\PreloadUrlsGeneratorManager; use SpomkyLabs\PwaBundle\Command\CreateIconsCommand; use SpomkyLabs\PwaBundle\Command\CreateScreenshotCommand; use SpomkyLabs\PwaBundle\Command\ListCacheStrategiesCommand; @@ -124,4 +125,6 @@ ->tag('spomky_labs_pwa.match_callback_handler') ; $container->load('SpomkyLabs\\PwaBundle\\MatchCallbackHandler\\', '../../MatchCallbackHandler/*'); + + $container->set(PreloadUrlsGeneratorManager::class); }; diff --git a/src/SpomkyLabsPwaBundle.php b/src/SpomkyLabsPwaBundle.php index f698c7f..1af1d51 100644 --- a/src/SpomkyLabsPwaBundle.php +++ b/src/SpomkyLabsPwaBundle.php @@ -4,6 +4,7 @@ namespace SpomkyLabs\PwaBundle; +use SpomkyLabs\PwaBundle\DependencyInjection\Compiler\AddPreloadUrlsGeneratorPass; use SpomkyLabs\PwaBundle\ImageProcessor\ImageProcessorInterface; use SpomkyLabs\PwaBundle\Subscriber\PwaDevServerSubscriber; use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator; @@ -57,6 +58,11 @@ public function prependExtension(ContainerConfigurator $container, ContainerBuil $this->setAssetMapperPath($builder); } + public function build(ContainerBuilder $container): void + { + $container->addCompilerPass(new AddPreloadUrlsGeneratorPass()); + } + private function setAssetMapperPath(ContainerBuilder $builder): void { $builder->prependExtensionConfig('framework', [ diff --git a/tests/DummyImageProcessor.php b/tests/DummyImageProcessor.php index a5e9cba..8eb07f1 100644 --- a/tests/DummyImageProcessor.php +++ b/tests/DummyImageProcessor.php @@ -4,12 +4,12 @@ namespace SpomkyLabs\PwaBundle\Tests; -use SpomkyLabs\PwaBundle\ImageProcessor\ImageProcessor; +use SpomkyLabs\PwaBundle\ImageProcessor\ImageProcessorInterface; /** * @internal */ -class DummyImageProcessor implements ImageProcessor +class DummyImageProcessor implements ImageProcessorInterface { public function process(string $image, ?int $width, ?int $height, ?string $format): string { diff --git a/tests/DummyUrlsGenerator.php b/tests/DummyUrlsGenerator.php new file mode 100644 index 0000000..e33f470 --- /dev/null +++ b/tests/DummyUrlsGenerator.php @@ -0,0 +1,21 @@ +load('SpomkyLabs\\PwaBundle\\Tests\\Controller\\', __DIR__ . '/Controller/') ->tag('controller.service_arguments') ; + $container->services() + ->set(DummyUrlsGenerator::class) + ->tag('spomky_labs_pwa.preload_urls_generator', [ + 'alias' => 'dummy', + ]) + ; $container->extension('framework', [ 'test' => true, @@ -232,7 +239,7 @@ 'strategy' => 'StaleWhileRevalidate', 'cache_name' => 'page-cache', 'broadcast' => true, - 'preload_urls' => ['privacy_policy', 'terms_of_service'], + 'preload_urls' => ['privacy_policy', 'terms_of_service', '@dummy'], ], ], 'offline_fallback' => [