diff --git a/src/LazyImage/src/BlurHash/BlurHash.php b/src/LazyImage/src/BlurHash/BlurHash.php index 320d64913ad..4eef2fee7b5 100644 --- a/src/LazyImage/src/BlurHash/BlurHash.php +++ b/src/LazyImage/src/BlurHash/BlurHash.php @@ -13,6 +13,7 @@ use Intervention\Image\ImageManager; use kornrunner\Blurhash\Blurhash as BlurhashEncoder; +use Symfony\Contracts\Cache\CacheInterface; /** * @author Titouan Galopin @@ -23,6 +24,7 @@ class BlurHash implements BlurHashInterface { public function __construct( private ?ImageManager $imageManager = null, + private ?CacheInterface $cache = null, ) { } @@ -60,6 +62,18 @@ public function encode(string $filename, int $encodingWidth = 75, int $encodingH throw new \LogicException('To use the Blurhash feature, install kornrunner/blurhash.'); } + if ($this->cache) { + return $this->cache->get( + 'blurhash.'.hash('xxh3', $filename.$encodingWidth.$encodingHeight), + fn () => $this->doEncode($filename, $encodingWidth, $encodingHeight) + ); + } + + return $this->doEncode($filename, $encodingWidth, $encodingHeight); + } + + private function doEncode(string $filename, int $encodingWidth = 75, int $encodingHeight = 75): string + { // Resize image to increase encoding performance $image = $this->imageManager->make(file_get_contents($filename)); $image->resize($encodingWidth, $encodingHeight, static function ($constraint) { diff --git a/src/LazyImage/src/BlurHash/CachedBlurHash.php b/src/LazyImage/src/BlurHash/CachedBlurHash.php deleted file mode 100644 index e5dad760ee7..00000000000 --- a/src/LazyImage/src/BlurHash/CachedBlurHash.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\UX\LazyImage\BlurHash; - -use Symfony\Contracts\Cache\CacheInterface; - -/** - * Decorate a BlurHashInterface to cache the result of the encoding, for performance purposes. - * - * @author Hugo Alliaume - * - * @final - */ -class CachedBlurHash implements BlurHashInterface -{ - public function __construct( - private BlurHashInterface $blurHash, - private CacheInterface $cache, - ) { - } - - public function createDataUriThumbnail(string $filename, int $width, int $height, int $encodingWidth = 75, int $encodingHeight = 75): string - { - return $this->blurHash->createDataUriThumbnail($filename, $width, $height, $encodingWidth, $encodingHeight); - } - - public function encode(string $filename, int $encodingWidth = 75, int $encodingHeight = 75): string - { - return $this->cache->get( - 'blurhash.'.hash('xxh3', $filename.$encodingWidth.$encodingHeight), - fn () => $this->blurHash->encode($filename, $encodingWidth, $encodingHeight) - ); - } -} diff --git a/src/LazyImage/src/DependencyInjection/LazyImageExtension.php b/src/LazyImage/src/DependencyInjection/LazyImageExtension.php index be5686f8400..8089ed5b0bc 100644 --- a/src/LazyImage/src/DependencyInjection/LazyImageExtension.php +++ b/src/LazyImage/src/DependencyInjection/LazyImageExtension.php @@ -21,7 +21,6 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\UX\LazyImage\BlurHash\BlurHash; use Symfony\UX\LazyImage\BlurHash\BlurHashInterface; -use Symfony\UX\LazyImage\BlurHash\CachedBlurHash; use Symfony\UX\LazyImage\Twig\BlurHashExtension; /** @@ -45,23 +44,19 @@ public function load(array $configs, ContainerBuilder $container) $container ->setDefinition('lazy_image.blur_hash', new Definition(BlurHash::class)) - ->addArgument(new Reference('lazy_image.image_manager', ContainerInterface::NULL_ON_INVALID_REFERENCE)) + ->setArgument(0, new Reference('lazy_image.image_manager', ContainerInterface::NULL_ON_INVALID_REFERENCE)) ->setPublic(false) ; - $container->setAlias(BlurHashInterface::class, 'lazy_image.blur_hash')->setPublic(false); - if (isset($config['cache'])) { $container - ->setDefinition('lazy_image.cached_blur_hash', new Definition(CachedBlurHash::class)) - ->setDecoratedService('lazy_image.blur_hash') - ->addArgument(new Reference('lazy_image.cached_blur_hash.inner')) - ->addArgument(new Reference($config['cache'])) + ->getDefinition('lazy_image.blur_hash') + ->setArgument(1, new Reference($config['cache'])) ; - - $container->setAlias(BlurHashInterface::class, 'lazy_image.blur_hash')->setPublic(false); } + $container->setAlias(BlurHashInterface::class, 'lazy_image.blur_hash')->setPublic(false); + $container ->setDefinition('twig.extension.blur_hash', new Definition(BlurHashExtension::class)) ->addArgument(new Reference('lazy_image.blur_hash')) diff --git a/src/LazyImage/tests/BlurHash/BlurHashTest.php b/src/LazyImage/tests/BlurHash/BlurHashTest.php index 56ad512b89c..503c5234eba 100644 --- a/src/LazyImage/tests/BlurHash/BlurHashTest.php +++ b/src/LazyImage/tests/BlurHash/BlurHashTest.php @@ -15,8 +15,9 @@ use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\UX\LazyImage\BlurHash\BlurHash; use Symfony\UX\LazyImage\BlurHash\BlurHashInterface; -use Symfony\UX\LazyImage\BlurHash\CachedBlurHash; use Symfony\UX\LazyImage\Tests\Kernel\TwigAppKernel; /** @@ -50,7 +51,8 @@ public function testEnsureCacheIsNotUsedWhenNotConfigured() /** @var BlurHashInterface $blurHash */ $blurHash = $container->get('test.lazy_image.blur_hash'); - static::assertNotInstanceOf(CachedBlurHash::class, $blurHash); + $this->assertInstanceOf(BlurHash::class, $blurHash); + $this->assertNull($this->extractCache($blurHash)); } public function testEnsureCacheIsUsedWhenConfigured() @@ -86,43 +88,83 @@ public function registerContainerConfiguration(LoaderInterface $loader) /** @var BlurHashInterface $blurHash */ $blurHash = $container->get('test.lazy_image.blur_hash'); - static::assertInstanceOf(CachedBlurHash::class, $blurHash); + $this->assertInstanceOf(BlurHash::class, $blurHash); + $this->assertInstanceOf(CacheInterface::class, $this->extractCache($blurHash)); } - public function testEncodeShouldBeCalledOnceWhenCached() + public function testCreateDataUriThumbnail() { - $blurHash = $this->createMock(BlurHashInterface::class); - $blurHash->expects($this->once())->method('encode')->with(__DIR__.'/../Fixtures/logo.png')->willReturn('L54ec*~q_3?bofoffQWB9F9FD%IU'); - $cache = new ArrayAdapter(); - $cachedBlurHash = new CachedBlurHash($blurHash, $cache); - - $this->assertEmpty($cache->getValues()); + $kernel = new TwigAppKernel('test', true); + $kernel->boot(); + $container = $kernel->getContainer()->get('test.service_container'); - $this->assertSame( - 'L54ec*~q_3?bofoffQWB9F9FD%IU', - $cachedBlurHash->encode(__DIR__.'/../Fixtures/logo.png') - ); + /** @var BlurHashInterface $blurHash */ + $blurHash = $container->get('test.lazy_image.blur_hash'); - $this->assertNotEmpty($cache->getValues()); + $this->assertInstanceOf(BlurHash::class, $blurHash); + $this->assertNull($this->extractCache($blurHash)); $this->assertSame( - 'L54ec*~q_3?bofoffQWB9F9FD%IU', - $cachedBlurHash->encode(__DIR__.'/../Fixtures/logo.png') + 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBxdWFsaXR5ID0gODAK/9sAQwAGBAUGBQQGBgUGBwcGCAoQCgoJCQoUDg8MEBcUGBgXFBYWGh0lHxobIxwWFiAsICMmJykqKRkfLTAtKDAlKCko/9sAQwEHBwcKCAoTCgoTKBoWGigoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgo/8AAEQgAOgDqAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A8k8g00wH0rofsftTTZ+1AHOtAaieA10bWftUL2ftQBzbwGq0kBrppLT2qrLae1AHMSwGs+4tyc11ctr7VRntfagDj5oWQk44qGuluLQc8Vk3VngkrxQBQopWUqcGkoAKKKKACiiigAooqRIXbtQBHRVtLMnrUy2Q9KAM6itQWQ9KDZD0oAy6K0Gsh6VE9oR0oAqUVI8Lr2qMjHWgAooooAKKKKAPov7OPSmm3HpWhgU1gKAM1rcelQPbj0rUcCoJAKAMmSAelVJYB6VsSgVTlAoAxpoR6VRnhHpWzMBWfOBzQBi3EI5rLuYRg8Vu3GOayrnHNAHO3sA5IrPPBravMYNYz/eNACUUUUAFKqljgUlTWwGaALFvbjvV+KAelNgA4q7EBQAiQj0qVYR6VKgqZRQBX8kelBhHpVoCgigCk0I9KheEelaDAVC4FAGZLAKpT249K2JAKpzAUAY0iFTTKuXAHNU6ACiiigD6S84U1phWP9s96abz3oA1XmFQSTCs1rv3qB7v3oA0JZh61TllFUpbv3qpLd+9AFqaUVnzyiq812Oeaz7i7HPNAE1xKOeayrqYc81Dd3ygHJrGubxpCQvT1oAde3GThapUHmigAooooAKdG21s02igDUt5gQOavxSCueRyh4q3Dd44NAHQJJUyyVix3QPerC3I9aANTzKDIKzhcj1pDcj1oAvtJULyVSa5HrVeS7A70AXJZBVGeYDPNVpbvPSqruzHk0APmk3HioqKKACiiigD1X7WfWmm7PrVA000AXGuz61C92fWqrVA9AFiS8PrVSa896hlqlP3oAfcX+M81lXF+zkhfzqO8NVKAFd2c5Y5pKKKACiiigAooooAKKKKACiiigBQxHQ08TOO9R0UATfaHpDcOaiooAeZXPemEk9aKKACiiigAooooAKKKKAP/9k=', + $blurHash->createDataUriThumbnail(__DIR__.'/../Fixtures/logo.png', 234, 58) ); } - public function testCreateDataUriThumbnail() + public function testCreateDataUriThumbnailWithCache() { - $kernel = new TwigAppKernel('test', true); + $kernel = new class('test', true) extends TwigAppKernel { + public function registerContainerConfiguration(LoaderInterface $loader) + { + parent::registerContainerConfiguration($loader); + + $loader->load(static function (ContainerBuilder $container) { + $container->loadFromExtension('framework', [ + 'cache' => [ + 'pools' => [ + 'cache.lazy_image' => [ + 'adapter' => 'cache.adapter.array', + ], + ], + ], + ]); + + $container->loadFromExtension('lazy_image', [ + 'cache' => 'cache.lazy_image', + ]); + + $container->setAlias('test.cache.lazy_image', 'cache.lazy_image')->setPublic(true); + }); + } + }; + $kernel->boot(); $container = $kernel->getContainer()->get('test.service_container'); /** @var BlurHashInterface $blurHash */ $blurHash = $container->get('test.lazy_image.blur_hash'); + $this->assertInstanceOf(BlurHash::class, $blurHash); + $this->assertInstanceOf(ArrayAdapter::class, $cache = $this->extractCache($blurHash)); + + $this->assertEmpty($cache->getValues()); + + $this->assertSame( + 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBxdWFsaXR5ID0gODAK/9sAQwAGBAUGBQQGBgUGBwcGCAoQCgoJCQoUDg8MEBcUGBgXFBYWGh0lHxobIxwWFiAsICMmJykqKRkfLTAtKDAlKCko/9sAQwEHBwcKCAoTCgoTKBoWGigoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgo/8AAEQgAOgDqAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A8k8g00wH0rofsftTTZ+1AHOtAaieA10bWftUL2ftQBzbwGq0kBrppLT2qrLae1AHMSwGs+4tyc11ctr7VRntfagDj5oWQk44qGuluLQc8Vk3VngkrxQBQopWUqcGkoAKKKKACiiigAooqRIXbtQBHRVtLMnrUy2Q9KAM6itQWQ9KDZD0oAy6K0Gsh6VE9oR0oAqUVI8Lr2qMjHWgAooooAKKKKAPov7OPSmm3HpWhgU1gKAM1rcelQPbj0rUcCoJAKAMmSAelVJYB6VsSgVTlAoAxpoR6VRnhHpWzMBWfOBzQBi3EI5rLuYRg8Vu3GOayrnHNAHO3sA5IrPPBravMYNYz/eNACUUUUAFKqljgUlTWwGaALFvbjvV+KAelNgA4q7EBQAiQj0qVYR6VKgqZRQBX8kelBhHpVoCgigCk0I9KheEelaDAVC4FAGZLAKpT249K2JAKpzAUAY0iFTTKuXAHNU6ACiiigD6S84U1phWP9s96abz3oA1XmFQSTCs1rv3qB7v3oA0JZh61TllFUpbv3qpLd+9AFqaUVnzyiq812Oeaz7i7HPNAE1xKOeayrqYc81Dd3ygHJrGubxpCQvT1oAde3GThapUHmigAooooAKdG21s02igDUt5gQOavxSCueRyh4q3Dd44NAHQJJUyyVix3QPerC3I9aANTzKDIKzhcj1pDcj1oAvtJULyVSa5HrVeS7A70AXJZBVGeYDPNVpbvPSqruzHk0APmk3HioqKKACiiigD1X7WfWmm7PrVA000AXGuz61C92fWqrVA9AFiS8PrVSa896hlqlP3oAfcX+M81lXF+zkhfzqO8NVKAFd2c5Y5pKKKACiiigAooooAKKKKACiiigBQxHQ08TOO9R0UATfaHpDcOaiooAeZXPemEk9aKKACiiigAooooAKKKKAP/9k=', + $blurHash->createDataUriThumbnail(__DIR__.'/../Fixtures/logo.png', 234, 58) + ); + + $this->assertNotEmpty($cache->getValues()); + $this->assertSame( 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBxdWFsaXR5ID0gODAK/9sAQwAGBAUGBQQGBgUGBwcGCAoQCgoJCQoUDg8MEBcUGBgXFBYWGh0lHxobIxwWFiAsICMmJykqKRkfLTAtKDAlKCko/9sAQwEHBwcKCAoTCgoTKBoWGigoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgo/8AAEQgAOgDqAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A8k8g00wH0rofsftTTZ+1AHOtAaieA10bWftUL2ftQBzbwGq0kBrppLT2qrLae1AHMSwGs+4tyc11ctr7VRntfagDj5oWQk44qGuluLQc8Vk3VngkrxQBQopWUqcGkoAKKKKACiiigAooqRIXbtQBHRVtLMnrUy2Q9KAM6itQWQ9KDZD0oAy6K0Gsh6VE9oR0oAqUVI8Lr2qMjHWgAooooAKKKKAPov7OPSmm3HpWhgU1gKAM1rcelQPbj0rUcCoJAKAMmSAelVJYB6VsSgVTlAoAxpoR6VRnhHpWzMBWfOBzQBi3EI5rLuYRg8Vu3GOayrnHNAHO3sA5IrPPBravMYNYz/eNACUUUUAFKqljgUlTWwGaALFvbjvV+KAelNgA4q7EBQAiQj0qVYR6VKgqZRQBX8kelBhHpVoCgigCk0I9KheEelaDAVC4FAGZLAKpT249K2JAKpzAUAY0iFTTKuXAHNU6ACiiigD6S84U1phWP9s96abz3oA1XmFQSTCs1rv3qB7v3oA0JZh61TllFUpbv3qpLd+9AFqaUVnzyiq812Oeaz7i7HPNAE1xKOeayrqYc81Dd3ygHJrGubxpCQvT1oAde3GThapUHmigAooooAKdG21s02igDUt5gQOavxSCueRyh4q3Dd44NAHQJJUyyVix3QPerC3I9aANTzKDIKzhcj1pDcj1oAvtJULyVSa5HrVeS7A70AXJZBVGeYDPNVpbvPSqruzHk0APmk3HioqKKACiiigD1X7WfWmm7PrVA000AXGuz61C92fWqrVA9AFiS8PrVSa896hlqlP3oAfcX+M81lXF+zkhfzqO8NVKAFd2c5Y5pKKKACiiigAooooAKKKKACiiigBQxHQ08TOO9R0UATfaHpDcOaiooAeZXPemEk9aKKACiiigAooooAKKKKAP/9k=', $blurHash->createDataUriThumbnail(__DIR__.'/../Fixtures/logo.png', 234, 58) ); + + $this->assertNotEmpty($cache->getValues()); + } + + private function extractCache(BlurHash $blurHash): ?CacheInterface + { + return \Closure::bind(fn () => $this->cache, $blurHash, BlurHash::class)(); } }