Skip to content

Commit

Permalink
Add ApplicationIconCompiler and IconResolver services (#224)
Browse files Browse the repository at this point in the history
Introduced new services, `ApplicationIconCompiler` and `IconResolver`, for better structure. Updated related paths and dependencies. Modified existing services and tests for consistency and improved functionality with the new services.
  • Loading branch information
Spomky authored Jul 31, 2024
1 parent 2912947 commit d232e01
Show file tree
Hide file tree
Showing 21 changed files with 358 additions and 110 deletions.
27 changes: 26 additions & 1 deletion phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,16 @@ parameters:
count: 1
path: src/ImageProcessor/GDImageProcessor.php

-
message: "#^Parameter \\#1 \\$width of function imagecreatetruecolor expects int\\<1, max\\>, int given\\.$#"
count: 2
path: src/ImageProcessor/GDImageProcessor.php

-
message: "#^Parameter \\#2 \\$height of function imagecreatetruecolor expects int\\<1, max\\>, int given\\.$#"
count: 2
path: src/ImageProcessor/GDImageProcessor.php

-
message: "#^Parameter \\#2 \\$red of function imagecolorallocate expects int\\<0, 255\\>, int given\\.$#"
count: 1
Expand Down Expand Up @@ -620,6 +630,16 @@ parameters:
count: 1
path: src/Service/FaviconsCompiler.php

-
message: "#^Cannot access property \\$sourcePath on Symfony\\\\Component\\\\AssetMapper\\\\MappedAsset\\|null\\.$#"
count: 1
path: src/Service/IconResolver.php

-
message: "#^Parameter \\#3 \\$headers of class SpomkyLabs\\\\PwaBundle\\\\Service\\\\Data constructor expects array\\<string, bool\\|string\\>, array\\<string, string\\|true\\|null\\> given\\.$#"
count: 2
path: src/Service/IconResolver.php

-
message: "#^Attribute class Symfony\\\\Component\\\\DependencyInjection\\\\Attribute\\\\TaggedIterator is deprecated\\: since Symfony 7\\.1, use \\{@see AutowireIterator\\} instead\\.$#"
count: 1
Expand Down Expand Up @@ -668,4 +688,9 @@ parameters:
-
message: "#^Property SpomkyLabs\\\\PwaBundle\\\\Twig\\\\PwaRuntime\\:\\:\\$cspListener has unknown class Nelmio\\\\SecurityBundle\\\\EventListener\\\\ContentSecurityPolicyListener as its type\\.$#"
count: 1
path: src/Twig/PwaRuntime.php
path: src/Twig/PwaRuntime.php

-
message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 1
path: tests/Functional/TakeScreenshotCommandTest.php
2 changes: 1 addition & 1 deletion src/CachingStrategy/AssetCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function __construct(
PublicAssetsPathResolverInterface $publicAssetsPathResolver,
private readonly AssetMapperInterface $assetMapper,
private readonly SerializerInterface $serializer,
#[Autowire('%kernel.debug%')]
#[Autowire(param: 'kernel.debug')]
bool $debug,
) {
$this->workbox = $serviceWorker->workbox;
Expand Down
2 changes: 1 addition & 1 deletion src/CachingStrategy/FontCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function __construct(
ServiceWorker $serviceWorker,
private readonly AssetMapperInterface $assetMapper,
private readonly SerializerInterface $serializer,
#[Autowire('%kernel.debug%')]
#[Autowire(param: 'kernel.debug')]
bool $debug,
) {
$this->workbox = $serviceWorker->workbox;
Expand Down
2 changes: 1 addition & 1 deletion src/CachingStrategy/ManifestCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class ManifestCache implements HasCacheStrategiesInterface, CanLogInterfac

public function __construct(
ServiceWorker $serviceWorker,
#[Autowire('%spomky_labs_pwa.manifest.public_url%')]
#[Autowire(param: 'spomky_labs_pwa.manifest.public_url')]
string $manifestPublicUrl,
) {
$this->workbox = $serviceWorker->workbox;
Expand Down
2 changes: 1 addition & 1 deletion src/CachingStrategy/ResourceCaches.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function __construct(
private readonly SerializerInterface $serializer,
#[TaggedIterator('spomky_labs_pwa.match_callback_handler')]
private readonly iterable $matchCallbackHandlers,
#[Autowire('%kernel.debug%')]
#[Autowire(param: 'kernel.debug')]
bool $debug,
) {
$this->workbox = $serviceWorker->workbox;
Expand Down
2 changes: 1 addition & 1 deletion src/Command/CreateIconsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ final class CreateIconsCommand extends Command
public function __construct(
private readonly AssetMapperInterface $assetMapper,
private readonly Filesystem $filesystem,
#[Autowire('%kernel.project_dir%')]
#[Autowire(param: 'kernel.project_dir')]
private readonly string $projectDir,
private readonly null|ImageProcessorInterface $imageProcessor,
) {
Expand Down
2 changes: 1 addition & 1 deletion src/Command/CreateScreenshotCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ final class CreateScreenshotCommand extends Command
public function __construct(
private readonly AssetMapperInterface $assetMapper,
private readonly Filesystem $filesystem,
#[Autowire('%kernel.project_dir%')]
#[Autowire(param: 'kernel.project_dir')]
private readonly string $projectDir,
private readonly null|ImageProcessorInterface $imageProcessor,
#[Autowire('@pwa.web_client')]
Expand Down
11 changes: 11 additions & 0 deletions src/Dto/Icon.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ final class Icon

public null|string $type = null;

public null|string $format = null;

#[SerializedName('border_radius')]
public null|int $borderRadius = null;

#[SerializedName('image_scale')]
public null|int $imageScale = null;

#[SerializedName('background_color')]
public null|string $backgroundColor = null;

public null|string $purpose = null;

#[SerializedName('sizes')]
Expand Down
25 changes: 5 additions & 20 deletions src/Normalizer/IconNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
namespace SpomkyLabs\PwaBundle\Normalizer;

use SpomkyLabs\PwaBundle\Dto\Icon;
use Symfony\Component\AssetMapper\AssetMapperInterface;
use Symfony\Component\AssetMapper\MappedAsset;
use Symfony\Component\Mime\MimeTypes;
use SpomkyLabs\PwaBundle\Service\IconResolver;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
Expand All @@ -18,7 +16,7 @@ final class IconNormalizer implements NormalizerInterface, NormalizerAwareInterf
use NormalizerAwareTrait;

public function __construct(
private readonly AssetMapperInterface $assetMapper,
private readonly IconResolver $iconResolver,
) {
}

Expand All @@ -28,14 +26,11 @@ public function __construct(
public function normalize(mixed $object, string $format = null, array $context = []): array
{
assert($object instanceof Icon);
$imageType = $object->type;
if (! str_starts_with($object->src->src, '/')) {
$asset = $this->assetMapper->getAsset($object->src->src);
$imageType = $this->getType($asset);
}
$icon = $this->iconResolver->getIcon($object);
$imageType = $this->iconResolver->getType($object->type, $icon->url);

$result = [
'src' => $this->normalizer->normalize($object->src, $format, $context),
'src' => $icon->url,
'sizes' => $object->getSizeList(),
'type' => $imageType,
'purpose' => $object->purpose,
Expand Down Expand Up @@ -63,14 +58,4 @@ public function getSupportedTypes(?string $format): array
Icon::class => true,
];
}

private function getType(?MappedAsset $asset): ?string
{
if ($asset === null || ! class_exists(MimeTypes::class)) {
return null;
}

$mime = MimeTypes::getDefault();
return $mime->guessMimeType($asset->sourcePath);
}
}
102 changes: 62 additions & 40 deletions src/Resources/config/definition/utils/icons.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,50 +16,72 @@ function getIconsNode(string $info): ArrayNodeDefinition
->treatNullLike([])
->arrayPrototype()
->beforeNormalization()
->ifString()
->then(static fn (string $v): array => [
'src' => $v,
])
->ifString()
->then(static fn (string $v): array => [
'src' => $v,
])
->end()
->children()
->scalarNode('src')
->isRequired()
->info('The path to the icon. Can be served by Asset Mapper.')
->example('icon/logo.svg')
->end()
->arrayNode('sizes')
->beforeNormalization()
->ifTrue(static fn (mixed $v): bool => is_int($v))
->then(static fn (int $v): array => [$v])
->end()
->beforeNormalization()
->ifTrue(static fn (mixed $v): bool => is_string($v))
->then(static function (string $v): array {
if ($v === 'any') {
return [0];
}
->scalarNode('src')
->isRequired()
->info('The path to the icon. Can be served by Asset Mapper.')
->example('icon/logo.svg')
->end()
->arrayNode('sizes')
->beforeNormalization()
->ifTrue(static fn (mixed $v): bool => is_int($v))
->then(static fn (int $v): array => [$v])
->end()
->beforeNormalization()
->ifTrue(static fn (mixed $v): bool => is_string($v))
->then(static function (string $v): array {
if ($v === 'any') {
return [0];
}

return [(int) $v];
})
->end()
->info(
'The sizes of the icon. 16 means 16x16, 32 means 32x32, etc. 0 means "any" (i.e. it is a vector image).'
)
->example([['16', '32']])
->integerPrototype()
->end()
->end()
->scalarNode('type')
->info('The icon mime type.')
->example(['image/webp', 'image/png'])
->end()
->scalarNode('purpose')
->info('The purpose of the icon.')
->example(['any', 'maskable', 'monochrome'])
->end()
->end()
return [(int) $v];
})
->end()
->info(
'The sizes of the icon. 16 means 16x16, 32 means 32x32, etc. 0 means "any" (i.e. it is a vector image).'
)
->example([['16', '32']])
->integerPrototype()
->end()
->end()
->scalarNode('background_color')
->defaultNull()
->info(
'The background color of the application. If this value is not defined and that of the Manifest section is, the value of the latter will be used.'
)
->example(['red', '#f5ef06'])
->end()
->integerNode('border_radius')
->defaultNull()
->min(1)
->max(50)
->info('The border radius of the icon.')
->end()
->integerNode('image_scale')
->defaultNull()
->min(1)
->max(100)
->info('The scale of the icon.')
->end()
->scalarNode('type')
->info('The icon mime type.')
->example(['image/webp', 'image/png'])
->end()
->scalarNode('format')
->info('The icon format. When set, the "type" option is ignored and the image will be converted.')
->example(['image/webp', 'image/png'])
->end()
->scalarNode('purpose')
->info('The purpose of the icon.')
->example(['any', 'maskable', 'monochrome'])
->end()
->end()
;
->end();

return $node;
}
5 changes: 5 additions & 0 deletions src/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
use SpomkyLabs\PwaBundle\ImageProcessor\GDImageProcessor;
use SpomkyLabs\PwaBundle\ImageProcessor\ImagickImageProcessor;
use SpomkyLabs\PwaBundle\MatchCallbackHandler\MatchCallbackHandlerInterface;
use SpomkyLabs\PwaBundle\Service\ApplicationIconCompiler;
use SpomkyLabs\PwaBundle\Service\CanLogInterface;
use SpomkyLabs\PwaBundle\Service\FaviconsBuilder;
use SpomkyLabs\PwaBundle\Service\FaviconsCompiler;
use SpomkyLabs\PwaBundle\Service\FileCompilerInterface;
use SpomkyLabs\PwaBundle\Service\IconResolver;
use SpomkyLabs\PwaBundle\Service\ManifestBuilder;
use SpomkyLabs\PwaBundle\Service\ManifestCompiler;
use SpomkyLabs\PwaBundle\Service\ServiceWorkerBuilder;
Expand Down Expand Up @@ -73,6 +75,9 @@
;
$container->set(FaviconsCompiler::class);

$container->set(IconResolver::class);
$container->set(ApplicationIconCompiler::class);

/*** Service Worker ***/
$container->set(ServiceWorkerBuilder::class)
->args([
Expand Down
49 changes: 49 additions & 0 deletions src/Service/ApplicationIconCompiler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace SpomkyLabs\PwaBundle\Service;

use SpomkyLabs\PwaBundle\Dto\Manifest;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use function count;

final readonly class ApplicationIconCompiler implements FileCompilerInterface
{
public function __construct(
private IconResolver $iconResolver,
private Manifest $manifest,
#[Autowire(param: 'kernel.debug')]
public bool $debug,
) {
}

/**
* @return iterable<Data>
*/
public function getFiles(): iterable
{
$icons = [];
if ($this->manifest->enabled === false) {
yield from $icons;
return;
}
if (count($this->manifest->icons) !== 0) {
$icons = array_merge($icons, $this->manifest->icons);
}
if (count($this->manifest->shortcuts) !== 0) {
foreach ($this->manifest->shortcuts as $shortcut) {
$icons = array_merge($icons, $shortcut->icons);
}
}
if (count($this->manifest->widgets) !== 0) {
foreach ($this->manifest->widgets as $widget) {
$icons = array_merge($icons, $widget->icons);
}
}

foreach ($icons as $icon) {
yield $this->iconResolver->getIcon($icon);
}
}
}
Loading

0 comments on commit d232e01

Please sign in to comment.