Skip to content

Commit

Permalink
feat: thumbnails (#185)
Browse files Browse the repository at this point in the history
* feat: yassg_thumbnail()

* feat: yassg_thumbnail()

* feat: yassg_thumbnail()
  • Loading branch information
dkarlovi authored Dec 8, 2023
1 parent e07feb5 commit afa5076
Show file tree
Hide file tree
Showing 13 changed files with 217 additions and 10 deletions.
8 changes: 6 additions & 2 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,14 @@ services:
class: Sigwin\YASSG\Bridge\Symfony\HttpKernel\Fragment\RelativeUrlInlineFragmentRenderer
decorates: fragment.renderer.inline

sigwin_yassg.file_decoder.caching_file_decoder:
sigwin_yassg.file_decoder.thumbnail_queue_file_decoder:
class: Sigwin\YASSG\Decoder\CachingFileDecoder
decorates: 'Sigwin\YASSG\FileDecoder'

decoration_priority: 200
sigwin_yassg.file_decoder.caching_file_decoder:
class: Sigwin\YASSG\Decoder\ThumbnailQueueFileDecoder
decorates: 'Sigwin\YASSG\FileDecoder'
decoration_priority: 100
Sigwin\YASSG\FileDecoder:
class: Sigwin\YASSG\Decoder\CompositeFileDecoder
arguments:
Expand Down
27 changes: 27 additions & 0 deletions psalm.baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,19 @@
<code>PaginatorExtension</code>
</UnusedClass>
</file>
<file src="src/Bridge/Twig/Extension/ThumbnailExtension.php">
<MixedArgument>
<code><![CDATA[$GLOBALS['YASSG_BASEDIR']]]></code>
<code><![CDATA[$context['_path']]]></code>
</MixedArgument>
<PossiblyUndefinedStringArrayOffset>
<code><![CDATA[$GLOBALS['YASSG_BASEDIR']]]></code>
<code><![CDATA[$context['_path']]]></code>
</PossiblyUndefinedStringArrayOffset>
<UnusedClass>
<code>ThumbnailExtension</code>
</UnusedClass>
</file>
<file src="src/Collection.php">
<PossiblyUnusedMethod>
<code>column</code>
Expand Down Expand Up @@ -536,7 +549,16 @@
<code>MarkdownFileDecoder</code>
</UnusedClass>
</file>
<file src="src/Decoder/ThumbnailQueueFileDecoder.php">
<UnusedClass>
<code>ThumbnailQueueFileDecoder</code>
</UnusedClass>
</file>
<file src="src/Decoder/YamlFileDecoder.php">
<MixedReturnTypeCoercion>
<code>$data</code>
<code>array</code>
</MixedReturnTypeCoercion>
<UnusedClass>
<code>YamlFileDecoder</code>
</UnusedClass>
Expand Down Expand Up @@ -648,6 +670,11 @@
<code>array</code>
</PossiblyUnusedReturnValue>
</file>
<file src="src/ThumbnailQueue.php">
<PossiblyUnusedMethod>
<code>__construct</code>
</PossiblyUnusedMethod>
</file>
<file src="tests/functional/site/src/Bridge/Symfony/EventSubscriber.php">
<UnusedClass>
<code>EventSubscriber</code>
Expand Down
47 changes: 47 additions & 0 deletions src/Bridge/Twig/Extension/ThumbnailExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sigwin Yassg project.
*
* (c) sigwin.hr
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sigwin\YASSG\Bridge\Twig\Extension;

use Sigwin\YASSG\ThumbnailQueue;
use Symfony\Component\Asset\Packages;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

final class ThumbnailExtension extends AbstractExtension
{
public function __construct(private readonly Packages $packages, private readonly ThumbnailQueue $thumbnailQueue) {}

public function getFunctions(): array
{
return [
new TwigFunction('yassg_thumbnail', function (array $context, string $path): string {
if (str_starts_with($path, './')) {
$newPath = realpath(\dirname($context['_path']).'/'.$path);
if ($newPath === false) {
throw new \RuntimeException('Invalid thumbnail path '.$path);
}
$path = $newPath;
}

$relative = str_replace($GLOBALS['YASSG_BASEDIR'], '', $path);
$this->thumbnailQueue->add([
'source' => $path,
'destination' => $relative,
]);

return $this->packages->getUrl(ltrim($relative, '/'));
}, ['needs_context' => true]),
];
}
}
2 changes: 1 addition & 1 deletion src/Decoder/CachingFileDecoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function decode(\SplFileInfo $file): array

$item = $this->cachePoolItem->getItem($key);
if ($item->isHit()) {
/** @var array $value */
/** @var array<string, string> $value */
$value = $item->get();

return $value;
Expand Down
7 changes: 6 additions & 1 deletion src/Decoder/MarkdownFileDecoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use League\CommonMark\ConverterInterface;
use League\CommonMark\Extension\FrontMatter\FrontMatterProviderInterface;
use Sigwin\YASSG\FileDecoder;
use Sigwin\YASSG\ThumbnailQueue;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
use Twig\Environment;
Expand All @@ -26,7 +27,7 @@

private const EXTENSIONS = ['md', 'markdown'];

public function __construct(private ConverterInterface $converter, private Environment $twig) {}
public function __construct(private ConverterInterface $converter, private Environment $twig, private ThumbnailQueue $thumbnailQueue) {}

public function decode(\SplFileInfo $file): array
{
Expand All @@ -41,6 +42,7 @@ public function decode(\SplFileInfo $file): array
}

$metadata = [];
$thumbnails = [];
if (str_contains($content, '{{') || str_contains($content, '{%')) {
if (str_starts_with($content, '---')) {
$end = mb_strpos($content, '---', 3);
Expand All @@ -59,7 +61,9 @@ public function decode(\SplFileInfo $file): array

$content = $this->twig->createTemplate($content)->render([
'item' => $metadata,
'_path' => $file->getPathname(),
]);
$thumbnails = $this->thumbnailQueue->flush();
}

$result = $this->converter->convert($content);
Expand All @@ -68,6 +72,7 @@ public function decode(\SplFileInfo $file): array
$metadata = $result->getFrontMatter();
}
$metadata['body'] = $result->getContent();
$metadata['@thumbnails'] = $thumbnails;

return $metadata;
}
Expand Down
45 changes: 45 additions & 0 deletions src/Decoder/ThumbnailQueueFileDecoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sigwin Yassg project.
*
* (c) sigwin.hr
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sigwin\YASSG\Decoder;

use Sigwin\YASSG\FileDecoder;
use Sigwin\YASSG\ThumbnailQueue;

/**
* @psalm-import-type TThumbnailOptions from \Sigwin\YASSG\ThumbnailQueue
*/
final readonly class ThumbnailQueueFileDecoder implements FileDecoder
{
public function __construct(private FileDecoder $decoder, private ThumbnailQueue $thumbnailQueue) {}

public function supports(\SplFileInfo $file): bool
{
return $this->decoder->supports($file);
}

public function decode(\SplFileInfo $file): array
{
/** @var array{"@thumbnails"?: list<TThumbnailOptions>} $decoded */
$decoded = $this->decoder->decode($file);

if (isset($decoded['@thumbnails'])) {
foreach ($decoded['@thumbnails'] as $thumbnail) {
$this->thumbnailQueue->add($thumbnail);
}
}
unset($decoded['@thumbnails']);

return $decoded;
}
}
3 changes: 3 additions & 0 deletions src/FileDecoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ interface FileDecoder
{
public function supports(\SplFileInfo $file): bool;

/**
* @return array<string, mixed>
*/
public function decode(\SplFileInfo $file): array;
}
16 changes: 15 additions & 1 deletion src/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,13 @@
*/
final readonly class Generator
{
public function __construct(private string $buildDir, private Permutator $permutator, private UrlGeneratorInterface $urlGenerator, private KernelInterface $kernel, private Filesystem $filesystem) {}
public function __construct(private string $buildDir, private Permutator $permutator, private UrlGeneratorInterface $urlGenerator, private KernelInterface $kernel, private Filesystem $filesystem, private ThumbnailQueue $thumbnailQueue) {}

/**
* @param callable(Request, Response, string): void $callable
*
* @throws \Exception
*/
public function generate(callable $callable): void
{
$requestContext = $this->urlGenerator->getContext();
Expand Down Expand Up @@ -71,6 +76,10 @@ public function generate(callable $callable): void

$response = $this->dumpRequest($callable, $request);
$urlSet->addUrl(new UrlConcrete($url, new \DateTimeImmutable($response->headers->get('Last-Modified', 'now'))));

$this->thumbnailQueue->flush(function (array $item) use ($callable): void {
$callable($this->createRequest($item['destination']), new Response('OK'), $item['destination']);
});
}
if ($urlSet !== null) {
$this->dumpSitemap($urlSet, $deflate);
Expand Down Expand Up @@ -105,6 +114,11 @@ private function generateUrl(string $path): string
return sprintf('%1$s://%2$s%3$s%4$s', $context->getScheme(), $context->getHost(), $context->getBaseUrl(), $path);
}

/**
* @param callable(Request, Response, string): void $callable
*
* @throws \Exception
*/
private function dumpRequest(callable $callable, Request $request, int $expectedStatusCode = 200): Response
{
try {
Expand Down
62 changes: 62 additions & 0 deletions src/ThumbnailQueue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sigwin Yassg project.
*
* (c) sigwin.hr
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sigwin\YASSG;

use Symfony\Component\Filesystem\Filesystem;

/**
* @psalm-type TThumbnailOptions = array{source: string, destination: string}
*/
final class ThumbnailQueue
{
/**
* @var array<string, TThumbnailOptions>
*/
private array $queue = [];

public function __construct(private string $buildDir, private Filesystem $filesystem) {}

/**
* @param TThumbnailOptions $specification
*/
public function add(array $specification): void
{
$this->queue[$specification['destination']] = $specification;
}

/**
* @param callable(TThumbnailOptions): void $callable
*
* @return list<TThumbnailOptions>
*/
public function flush(?callable $callable = null): array
{
foreach ($this->queue as $specification) {
$destination = $this->buildDir.'/'.ltrim($specification['destination'], '/');
if (file_exists($destination)) {
continue;
}

// TODO: ImgProxy
$this->filesystem->copy($specification['source'], $destination);
if ($callable !== null) {
$callable($specification);
}
}
$queue = array_values($this->queue);
$this->queue = [];

return $queue;
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Images!
slug: images
publishedAt: "2022-07-20 12:35:00"
image: assets/images/sigwin.svg
image: ./image.webp
---

| Column 1 | Column 2 | Column 3 |
Expand All @@ -13,7 +13,7 @@ image: assets/images/sigwin.svg

This is a database lookup example: {{yassg_get('articles', '/hello-world.md').title}}

This is an asset lookup: {{asset(item.image)}}
This is an asset lookup: {{ yassg_thumbnail(item.image) }}

![Logo]({{ asset(item.image) }})
![Logo]({{ yassg_thumbnail(item.image) }})

Binary file not shown.
4 changes: 2 additions & 2 deletions tests/functional/site/fixtures/en/article/images/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ <h1>Images!</h1>
</tbody>
</table>
<p>This is a database lookup example: Hello World!</p>
<p>This is an asset lookup: /sub/dir/another/assets/images/sigwin.6f9a3d5b.svg</p>
<p><img src="/sub/dir/another/assets/images/sigwin.6f9a3d5b.svg" alt="Logo" /></p>
<p>This is an asset lookup: /sub/dir/another/content/articles/images/image.webp</p>
<p><img src="/sub/dir/another/content/articles/images/image.webp" alt="Logo" /></p>

</div>
</div>
Expand Down

0 comments on commit afa5076

Please sign in to comment.