Skip to content

Commit

Permalink
Add preload URLs generator and refactored caching strategy
Browse files Browse the repository at this point in the history
Introduced a preload URLs generator to efficiently handle URLs and refactored caching strategy to enhance efficiency. The changes include creating a preload URLs generator manager, implementing a dummy URLs generator for testing, and updating cache resource classes. Deprecated PageCache in favor of ResourceCache for better flexibility in handling resources.
  • Loading branch information
Spomky committed Apr 5, 2024
1 parent e518dac commit dd24a77
Show file tree
Hide file tree
Showing 14 changed files with 226 additions and 51 deletions.
22 changes: 16 additions & 6 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -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\\<string, string\\>\\|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

Expand All @@ -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\\<string, string\\>\\|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
Expand Down Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions src/CachingStrategy/PreloadUrlsGeneratorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace SpomkyLabs\PwaBundle\CachingStrategy;

use SpomkyLabs\PwaBundle\Dto\Url;

interface PreloadUrlsGeneratorInterface
{
/**
* @return iterable<Url>
*/
public function generateUrls(): iterable;
}
29 changes: 29 additions & 0 deletions src/CachingStrategy/PreloadUrlsGeneratorManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace SpomkyLabs\PwaBundle\CachingStrategy;

use InvalidArgumentException;
use function array_key_exists;

final class PreloadUrlsGeneratorManager
{
/**
* @var array<string, PreloadUrlsGeneratorInterface>
*/
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];
}
}
26 changes: 25 additions & 1 deletion src/CachingStrategy/ResourceCaches.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -31,6 +32,7 @@
* @param iterable<MatchCallbackHandlerInterface> $matchCallbackHandlers
*/
public function __construct(
private PreloadUrlsGeneratorManager $preloadUrlsGeneratorManager,
ServiceWorker $serviceWorker,
private SerializerInterface $serializer,
#[TaggedIterator('spomky_labs_pwa.match_callback_handler')]
Expand All @@ -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);
Expand Down Expand Up @@ -104,4 +106,26 @@ private function prepareMatchCallback(string $matchCallback): string

return $matchCallback;
}

/**
* @param array<Url> $urls
* @return array<Url>
*/
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;
}
}
32 changes: 32 additions & 0 deletions src/DependencyInjection/Compiler/AddPreloadUrlsGeneratorPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace SpomkyLabs\PwaBundle\DependencyInjection\Compiler;

use InvalidArgumentException;
use SpomkyLabs\PwaBundle\CachingStrategy\PreloadUrlsGeneratorManager;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

final readonly class AddPreloadUrlsGeneratorPass implements CompilerPassInterface
{
public const TAG = 'spomky_labs_pwa.preload_urls_generator';

public function process(ContainerBuilder $container): void
{
if (! $container->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)]);
}
}
}
}
43 changes: 4 additions & 39 deletions src/Dto/PageCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string>
*/
#[SerializedName('cacheable_response_headers')]
public array $cacheableResponseHeaders = [];

/**
* @var array<string>
*/
#[SerializedName('broadcast_headers')]
public array $broadcastHeaders = ['Content-Type', 'ETag', 'Last-Modified'];

/**
* @var array<Url>
*/
#[SerializedName('preload_urls')]
public array $urls = [];
}
50 changes: 50 additions & 0 deletions src/Dto/ResourceCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace SpomkyLabs\PwaBundle\Dto;

use Symfony\Component\Serializer\Attribute\SerializedName;

/**
* @final
*/
class ResourceCache extends Cache
{
#[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<string, string>
*/
#[SerializedName('cacheable_response_headers')]
public array $cacheableResponseHeaders = [];

/**
* @var array<string>
*/
#[SerializedName('broadcast_headers')]
public array $broadcastHeaders = ['Content-Type', 'ETag', 'Last-Modified'];

/**
* @var array<Url>
*/
#[SerializedName('preload_urls')]
public array $urls = [];
}
13 changes: 13 additions & 0 deletions src/Dto/Url.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,17 @@ final class Url
* @var array<string, mixed>
*/
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;
}
}
3 changes: 3 additions & 0 deletions src/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -124,4 +125,6 @@
->tag('spomky_labs_pwa.match_callback_handler')
;
$container->load('SpomkyLabs\\PwaBundle\\MatchCallbackHandler\\', '../../MatchCallbackHandler/*');

$container->set(PreloadUrlsGeneratorManager::class);
};
6 changes: 6 additions & 0 deletions src/SpomkyLabsPwaBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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', [
Expand Down
4 changes: 2 additions & 2 deletions tests/DummyImageProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
21 changes: 21 additions & 0 deletions tests/DummyUrlsGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace SpomkyLabs\PwaBundle\Tests;

use SpomkyLabs\PwaBundle\CachingStrategy\PreloadUrlsGeneratorInterface;

/**
* @internal
*/
class DummyUrlsGenerator implements PreloadUrlsGeneratorInterface
{
public function generateUrls(): iterable
{
yield '/dummy/1';
yield '/dummy/2';
yield '/dummy/3';
yield '/dummy/4';
}
}
4 changes: 2 additions & 2 deletions tests/TestFilesystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use function dirname;

final class TestFilesystem implements PublicAssetsFilesystemInterface
final readonly class TestFilesystem implements PublicAssetsFilesystemInterface
{
private readonly string $output;
private string $output;

public function __construct(
#[Autowire('%kernel.cache_dir%')]
Expand Down
Loading

0 comments on commit dd24a77

Please sign in to comment.