Skip to content

Commit

Permalink
Dev server for the manifest file (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
Spomky authored Jan 15, 2024
1 parent 0504a55 commit e214d6a
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 34 deletions.
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@
"symfony/asset-mapper": "^6.4|^7.0",
"symfony/config": "^6.4|^7.0",
"symfony/dependency-injection": "^6.4|^7.0",
"symfony/filesystem": "^6.4|^7.0",
"symfony/finder": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/mime": "^6.4|^7.0",
"symfony/property-access": "^6.4|^7.0",
"symfony/property-info": "^7.0",
"symfony/routing": "^6.4|^7.0",
Expand All @@ -51,7 +49,9 @@
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^10.0",
"rector/rector": "^0.19",
"symfony/filesystem": "^6.4|^7.0",
"symfony/framework-bundle": "^6.4|^7.0",
"symfony/mime": "^6.4|^7.0",
"symfony/panther": "^2.1",
"symfony/phpunit-bridge": "^6.4|^7.0",
"symfony/yaml": "^6.4|^7.0",
Expand All @@ -67,6 +67,8 @@
"suggest": {
"ext-gd": "Required to generate icons (or Imagick).",
"ext-imagick": "Required to generate icons (or GD).",
"symfony/mime": "For generating and manipulating icons or screenshots",
"symfony/filesystem": "For generating and manipulating icons or screenshots",
"symfony/panther": "For generating screenshots directly from your application"
}
}
5 changes: 3 additions & 2 deletions src/Command/GenerateIconsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ protected function configure(): void
{
$this->addArgument('source', InputArgument::REQUIRED, 'The source image');
$this->addArgument('output', InputArgument::REQUIRED, 'The output directory');
$this->addArgument('filename', InputArgument::OPTIONAL, 'The output directory', 'icon');
$this->addOption('format', null, InputOption::VALUE_OPTIONAL, 'The format of the icons');
$this->addArgument(
'sizes',
Expand All @@ -46,6 +47,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$source = $input->getArgument('source');
$dest = $input->getArgument('output');
$filename = $input->getArgument('filename');
$format = $input->getOption('format');
$sizes = $input->getArgument('sizes');

Expand Down Expand Up @@ -73,8 +75,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
foreach ($sizes as $size) {

Check failure on line 75 in src/Command/GenerateIconsCommand.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 Test on ubuntu-latest

Argument of an invalid type mixed supplied for foreach, only iterables are supported.
$io->info('Generating icon ' . $size . 'x' . $size . '...');
$tmp = $this->imageProcessor->process(file_get_contents($source), (int) $size, (int) $size, $format);

Check failure on line 77 in src/Command/GenerateIconsCommand.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 Test on ubuntu-latest

Cannot cast mixed to int.

Check failure on line 77 in src/Command/GenerateIconsCommand.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 Test on ubuntu-latest

Cannot cast mixed to int.

Check failure on line 77 in src/Command/GenerateIconsCommand.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 Test on ubuntu-latest

Parameter #1 $filename of function file_get_contents expects string, mixed given.

Check failure on line 77 in src/Command/GenerateIconsCommand.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 Test on ubuntu-latest

Parameter #1 $image of method SpomkyLabs\PwaBundle\ImageProcessor\ImageProcessor::process() expects string, string|false given.
$filename = sprintf('%s/icon-%sx%s.%s', $dest, $size, $size, $format);
$this->filesystem->dumpFile($filename, $tmp);
$this->filesystem->dumpFile(sprintf('%s/%s-%sx%s.%s', $dest, $filename, $size, $size, $format), $tmp);
$io->info('Icon ' . $size . 'x' . $size . ' generated.');
}
$io->info('Done.');
Expand Down
34 changes: 32 additions & 2 deletions src/Command/TakeScreenshotCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Mime\MimeTypes;
use Symfony\Component\Panther\Client;
use function count;

#[AsCommand(
name: 'pwa:take-screenshot',
Expand Down Expand Up @@ -44,7 +46,14 @@ public function isEnabled(): bool
protected function configure(): void
{
$this->addArgument('url', InputArgument::REQUIRED, 'The URL to take a screenshot from');
$this->addArgument('output', InputArgument::REQUIRED, 'The output file');
$this->addArgument('output', InputArgument::REQUIRED, 'The output directory of the screenshot');
$this->addArgument(
'filename',
InputArgument::OPTIONAL,
'The output name of the screenshot',
'screenshot',
['homeage-android', 'feature1']
);
$this->addOption('width', null, InputOption::VALUE_OPTIONAL, 'The width of the screenshot');
$this->addOption('height', null, InputOption::VALUE_OPTIONAL, 'The height of the screenshot');
}
Expand Down Expand Up @@ -72,7 +81,28 @@ protected function execute(InputInterface $input, OutputInterface $output): int
->fullscreen();
$client->takeScreenshot($tmpName);

$this->filesystem->copy($tmpName, $input->getArgument('output'), true);
$mime = MimeTypes::getDefault();
$mimeType = $mime->guessMimeType($tmpName);
$extensions = $mime->getExtensions($mimeType);
if (count($extensions) === 0) {
$io->error(sprintf('Unable to guess the extension for the mime type "%s".', $mimeType));
return self::FAILURE;
}
$sizes = '';
if ($width !== null && $height !== null) {
$sizes = sprintf('-%dx%d', (int) $width, (int) $height);
}

$format = current($extensions);
$filename = sprintf(
'%s/%s%s.%s',
$input->getArgument('output'),
$input->getArgument('filename'),
$sizes,
$format
);

$this->filesystem->copy($tmpName, $filename, true);
$this->filesystem->remove($tmpName);
$io->success('Screenshot saved');

Expand Down
6 changes: 6 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,12 @@ private function setupSimpleOptions(ArrayNodeDefinition $node): void
->thenInvalid('Invalid path type reference "%s".')
->end()
->end()
->scalarNode('manifest_public_url')
->defaultValue('/site.manifest')
->cannotBeEmpty()
->info('The public URL of the manifest file.')
->example('/site.manifest')
->end()
->scalarNode('image_processor')
->defaultNull()
->info('The image processor to use to generate the icons of different sizes.')
Expand Down
15 changes: 13 additions & 2 deletions src/DependencyInjection/SpomkyLabsPwaExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
namespace SpomkyLabs\PwaBundle\DependencyInjection;

use SpomkyLabs\PwaBundle\ImageProcessor\ImageProcessor;
use SpomkyLabs\PwaBundle\Subscriber\PwaDevServerSubscriber;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use function in_array;

final class SpomkyLabsPwaExtension extends Extension
{
Expand All @@ -35,9 +37,18 @@ public function load(array $configs, ContainerBuilder $container): void
$container->setAlias('pwa.web_client', $config['web_client']);
}
$container->setParameter('spomky_labs_pwa.routes.reference_type', $config['path_type_reference']);
unset($config['image_processor'], $config['web_client'], $config['path_type_reference']);

$container->setParameter('spomky_labs_pwa.manifest_public_url', $config['manifest_public_url']);

unset(
$config['image_processor'],
$config['web_client'],
$config['path_type_reference'],
$config['manifest_public_url'],
);
$container->setParameter('spomky_labs_pwa.config', $config);
if (! in_array($container->getParameter('kernel.environment'), ['dev', 'test'], true)) {
$container->removeDefinition(PwaDevServerSubscriber::class);
}
}

public function getConfiguration(array $config, ContainerBuilder $container): ConfigurationInterface
Expand Down
1 change: 1 addition & 0 deletions src/Normalizer/IconNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function normalize(mixed $object, string $format = null, array $context =
$data,
static fn ($value) => ($value !== null && $value !== [])
);

return $cleanup($result);
}

Expand Down
73 changes: 64 additions & 9 deletions src/Normalizer/ScreenshotNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,43 @@
namespace SpomkyLabs\PwaBundle\Normalizer;

use SpomkyLabs\PwaBundle\Dto\Screenshot;
use SpomkyLabs\PwaBundle\ImageProcessor\ImageProcessor;
use Symfony\Component\AssetMapper\AssetMapperInterface;
use Symfony\Component\AssetMapper\MappedAsset;
use Symfony\Component\Mime\MimeTypes;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use function assert;

final readonly class ScreenshotNormalizer implements NormalizerInterface
{
public function __construct(
private AssetMapperInterface $assetMapper
private AssetMapperInterface $assetMapper,
private null|ImageProcessor $imageProcessor,
) {
}

public function normalize(mixed $object, string $format = null, array $context = []): array
{
assert($object instanceof Screenshot);
$url = null;
$asset = null;
if (! str_starts_with($object->src, '/')) {
$url = $this->assetMapper->getAsset($object->src)?->publicPath;
$asset = $this->assetMapper->getAsset($object->src);
$url = $asset?->publicPath;
}
if ($url === null) {
$url = $object->src;
}
$sizes = null;
if ($object->width !== null && $object->height !== null) {
$sizes = sprintf('%dx%d', $object->width, $object->height);
}
['sizes' => $sizes, 'formFactor' => $formFactor] = $this->getSizes($object, $asset);
$format = $this->getFormat($object, $asset);

$result = [
'src' => $url,
'sizes' => $sizes,
'width' => $object->width,
'form_factor' => $object->formFactor,
'form_factor' => $formFactor,
'label' => $object->label,
'platform' => $object->platform,
'format' => $object->format,
'format' => $format,
];

$cleanup = static fn (array $data): array => array_filter(
Expand All @@ -62,4 +65,56 @@ public function getSupportedTypes(?string $format): array
Screenshot::class => true,
];
}

/**
* @return array{sizes: string|null, formFactor: string|null}
*/
private function getSizes(Screenshot $object, null|MappedAsset $asset): array
{
if ($object->width !== null && $object->height !== null) {
return [
'sizes' => sprintf('%dx%d', $object->width, $object->height),
'formFactor' => $object->formFactor ?? $this->getFormFactor($object->width, $object->height),
];
}

if ($this->imageProcessor === null || $asset === null) {
return [
'sizes' => null,
'formFactor' => $object->formFactor,
];
}

['width' => $width, 'height' => $height] = $this->imageProcessor->getSizes(
file_get_contents($asset->sourcePath)
);

return [
'sizes' => sprintf('%dx%d', $width, $height),
'formFactor' => $object->formFactor ?? $this->getFormFactor($width, $height),
];
}

private function getFormat(Screenshot $object, ?MappedAsset $asset): ?string
{
if ($object->format !== null) {
return $object->format;
}

if ($this->imageProcessor === null || $asset === null) {
return null;
}

$mime = MimeTypes::getDefault();
return $mime->guessMimeType($asset->sourcePath);
}

private function getFormFactor(?int $width, ?int $height): ?string
{
if ($width === null || $height === null) {
return null;
}

return $width > $height ? 'wide' : 'narrow';
}
}
12 changes: 8 additions & 4 deletions src/Normalizer/ShortcutNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@
use SpomkyLabs\PwaBundle\Dto\Shortcut;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use function assert;
use const FILTER_VALIDATE_URL;

final readonly class ShortcutNormalizer implements NormalizerInterface
final class ShortcutNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;

public function __construct(
private RouterInterface $router,
private readonly RouterInterface $router,
#[Autowire('%spomky_labs_pwa.routes.reference_type%')]
private int $referenceType,
private readonly int $referenceType,
) {
}

Expand All @@ -33,7 +37,7 @@ public function normalize(mixed $object, string $format = null, array $context =
'short_name' => $object->shortName,
'description' => $object->description,
'url' => $url,
'icons' => $object->icons,
'icons' => $this->normalizer->normalize($object->icons, $format, $context),
];

$cleanup = static fn (array $data): array => array_filter(
Expand Down
18 changes: 18 additions & 0 deletions src/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
use SpomkyLabs\PwaBundle\ImageProcessor\GDImageProcessor;
use SpomkyLabs\PwaBundle\ImageProcessor\ImagickImageProcessor;
use SpomkyLabs\PwaBundle\Service\Builder;
use SpomkyLabs\PwaBundle\Subscriber\PwaDevServerSubscriber;
use SpomkyLabs\PwaBundle\Twig\PwaExtension;
use SpomkyLabs\PwaBundle\Twig\PwaRuntime;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;

Expand Down Expand Up @@ -46,4 +49,19 @@
->alias('pwa.image_processor.gd', GDImageProcessor::class)
;
}

$container->set(PwaDevServerSubscriber::class)
->args([
'$profiler' => service('profiler')
->nullOnInvalid(),
])
->tag('kernel.event_subscriber')
;

$container->set(PwaExtension::class)
->tag('twig.extension')
;
$container->set(PwaRuntime::class)
->tag('twig.runtime')
;
};
Loading

0 comments on commit e214d6a

Please sign in to comment.