From 4be0084e9c6ee26080b66b3a9d62407c06b39f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20de=20Guillebon?= Date: Tue, 26 Aug 2025 10:57:44 +0200 Subject: [PATCH 01/27] refactor: review default value configuration for s3 cache --- DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php b/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php index 75991911d..f50f04e27 100644 --- a/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php +++ b/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php @@ -85,7 +85,7 @@ public function addConfiguration(ArrayNodeDefinition $builder) ->cannotBeEmpty() ->end() ->scalarNode('cache') - ->defaultValue(false) + ->defaultFalse() ->end() ->scalarNode('acl') ->defaultValue('public-read') From 87bf4aa5b6b16c6c115119d220289597d55b7372 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Wed, 27 Aug 2025 15:13:12 +0200 Subject: [PATCH 02/27] use ubuntu-latest to build, 20.04 has been discontinued --- .github/workflows/php-cs-fixer.yml | 4 ++-- .github/workflows/phpstan.yml | 4 ++-- .github/workflows/phpunit.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index db14da50d..7d44869bc 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -9,10 +9,10 @@ on: jobs: php-cs-fixer: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 5f47ec054..099c13f1a 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -9,10 +9,10 @@ on: jobs: phpstan: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 20005486e..331aa0640 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -10,7 +10,7 @@ on: jobs: phpunit: name: "PHP ${{ matrix.php }} + ${{ matrix.dependencies }} dependencies + Symfony ${{ matrix.symfony }}" - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: @@ -60,7 +60,7 @@ jobs: stability: 'dev' steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Configure coverage driver id: coverage @@ -128,7 +128,7 @@ jobs: coveralls-finish: needs: [phpunit] - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Notify Coveralls when build is finished uses: coverallsapp/github-action@master From 4b5d7bca14c92e8c1ccc9c8b80cd3eae3ffcfe78 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Wed, 27 Aug 2025 15:22:24 +0200 Subject: [PATCH 03/27] fix latest cs, pin enqueue version in php 7.4 --- .github/workflows/phpunit.yml | 5 +++++ LiipImagineBundle.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 331aa0640..c7bf2fb88 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -93,6 +93,11 @@ jobs: if: ${{ matrix.php == '7.2' && matrix.symfony == '3.4.*' }} run: composer remove --dev --no-update symfony/messenger + # Latest enqueue install on PHP 7.4 but uses PHP 8 features + - name: Pin enqueue/enqueue on PHP 7.4 + if: ${{ matrix.php == '7.4' }} + run: composer require --no-update enqueue/enqueue 0.10.18 + - name: Update project dependencies uses: ramsey/composer-install@v2 with: diff --git a/LiipImagineBundle.php b/LiipImagineBundle.php index 8e9fd75e8..f3457915a 100644 --- a/LiipImagineBundle.php +++ b/LiipImagineBundle.php @@ -59,7 +59,7 @@ public function build(ContainerBuilder $container): void ); } - /** @var $extension LiipImagineExtension */ + /** @var LiipImagineExtension $extension */ $extension = $container->getExtension('liip_imagine'); $extension->addResolverFactory(new WebPathResolverFactory()); From e1cb843b80dfba4382d176341ef1a1a48ff4116d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20de=20Guillebon?= Date: Fri, 29 Aug 2025 17:54:27 +0200 Subject: [PATCH 04/27] feature: enable autowiring for filter service --- Resources/config/imagine.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/config/imagine.xml b/Resources/config/imagine.xml index 68329a1ff..0d78911f8 100644 --- a/Resources/config/imagine.xml +++ b/Resources/config/imagine.xml @@ -158,6 +158,7 @@ %liip_imagine.webp.options% + From 761745b602fb68f56949dfd015bd22c0c20d33bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20de=20Guillebon?= Date: Wed, 27 Aug 2025 14:40:42 +0200 Subject: [PATCH 05/27] feature: support psr cache on s3 resolver --- CHANGELOG.md | 4 ++ .../Factory/Resolver/AwsS3ResolverFactory.php | 9 ++- Resources/doc/cache-resolver/aws_s3.rst | 6 +- .../Resolver/AwsS3ResolverFactoryTest.php | 57 +++++++++++++++++++ composer.json | 1 + 5 files changed, 75 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30ef53c70..82cc170fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic # 2.x +## Next Release + +- Add `use_psr_cache` option to AWS S3 resolver configuration in order to support PSR cache. Configuring a doctrine cache now will trigger a deprecation ([deguif](https://github.com/liip/LiipImagineBundle/pull/1630)) + ## [2.13.3](https://github.com/liip/LiipImagineBundle/tree/2.13.3) - Prevent InvalidArgumentException from FileinfoMimeTypeGuesser when chain loading an image that is not a file ([revoltek-daniel](https://github.com/liip/LiipImagineBundle/pull/1614)) diff --git a/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php b/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php index f50f04e27..8ce6dd2e0 100644 --- a/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php +++ b/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php @@ -57,7 +57,11 @@ public function create(ContainerBuilder $container, $resolverName, array $config $container->setDefinition($cachedResolverId, $container->getDefinition($resolverId)); - $cacheResolverDefinition = $this->getChildResolverDefinition('cache'); + if (false === $config['use_psr_cache']) { + trigger_deprecation('liip/imagine-bundle', '2.13.4', \sprintf('Setting the "liip_imagine.resolvers.%s.%s.use_psr_cache" config option to "false" is deprecated.', $resolverName, $this->getName())); + } + + $cacheResolverDefinition = $this->getChildResolverDefinition($config['use_psr_cache'] ? 'psr_cache' : 'cache'); $cacheResolverDefinition->replaceArgument(0, new Reference($config['cache'])); $cacheResolverDefinition->replaceArgument(1, new Reference($cachedResolverId)); @@ -87,6 +91,9 @@ public function addConfiguration(ArrayNodeDefinition $builder) ->scalarNode('cache') ->defaultFalse() ->end() + ->booleanNode('use_psr_cache') + ->defaultFalse() + ->end() ->scalarNode('acl') ->defaultValue('public-read') ->cannotBeEmpty() diff --git a/Resources/doc/cache-resolver/aws_s3.rst b/Resources/doc/cache-resolver/aws_s3.rst index a8748db8a..891813a49 100644 --- a/Resources/doc/cache-resolver/aws_s3.rst +++ b/Resources/doc/cache-resolver/aws_s3.rst @@ -204,8 +204,12 @@ current. You just need to configure them with defined options. aws_s3: #... proxies: ["https://one.domain.com", "https://two.domain.com"] - cache: true + cache: 'cache_name' +.. note:: + + The ``cache`` option accepts a doctrine cache, but this is now deprecated. + Use the ``use_psr_cache`` boolean option set to ``true`` so that a psr cache can be used instead. If enabled both first one will be :ref:`Cache `, then :ref:`Proxy ` and after all process delegates to AwsS3 resolver. diff --git a/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php b/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php index 19f4d7a08..9805bcead 100644 --- a/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php +++ b/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php @@ -15,6 +15,7 @@ use Liip\ImagineBundle\DependencyInjection\Factory\Resolver\AwsS3ResolverFactory; use Liip\ImagineBundle\DependencyInjection\Factory\Resolver\ResolverFactoryInterface; use Liip\ImagineBundle\Tests\AbstractTest; +use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\Processor; use Symfony\Component\DependencyInjection\ChildDefinition; @@ -26,6 +27,8 @@ */ class AwsS3ResolverFactoryTest extends AbstractTest { + use ExpectDeprecationTrait; + public function testImplementsResolverFactoryInterface(): void { $rc = new \ReflectionClass(AwsS3ResolverFactory::class); @@ -155,8 +158,13 @@ public function testWrapResolverWithProxyOnCreateWithoutCache(): void $this->assertSame(['foo'], $resolverDefinition->getArgument(1)); } + /** + * @group legacy + */ public function testWrapResolverWithCacheOnCreateWithoutProxy(): void { + $this->expectDeprecation('Since liip/imagine-bundle 2.13.4: Setting the "liip_imagine.resolvers.the_resolver_name.aws_s3.use_psr_cache" config option to "false" is deprecated.'); + $container = new ContainerBuilder(); $resolver = new AwsS3ResolverFactory(); @@ -168,6 +176,7 @@ public function testWrapResolverWithCacheOnCreateWithoutProxy(): void 'get_options' => [], 'put_options' => [], 'cache' => 'the_cache_service_id', + 'use_psr_cache' => false, 'proxies' => [], ]); @@ -190,8 +199,49 @@ public function testWrapResolverWithCacheOnCreateWithoutProxy(): void $this->assertSame('liip_imagine.cache.resolver.the_resolver_name.cached', (string) $resolverDefinition->getArgument(1)); } + public function testWrapResolverWithPsrCacheOnCreateWithoutProxy(): void + { + $container = new ContainerBuilder(); + + $resolver = new AwsS3ResolverFactory(); + + $resolver->create($container, 'the_resolver_name', [ + 'client_config' => [], + 'bucket' => 'aBucket', + 'acl' => 'aAcl', + 'get_options' => [], + 'put_options' => [], + 'cache' => 'the_cache_service_id', + 'use_psr_cache' => true, + 'proxies' => [], + ]); + + $this->assertTrue($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name.cached')); + $cachedResolverDefinition = $container->getDefinition('liip_imagine.cache.resolver.the_resolver_name.cached'); + $this->assertInstanceOf(ChildDefinition::class, $cachedResolverDefinition); + $this->assertSame('liip_imagine.cache.resolver.prototype.aws_s3', $cachedResolverDefinition->getParent()); + + $this->assertFalse($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name.proxied')); + + $this->assertTrue($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name')); + $resolverDefinition = $container->getDefinition('liip_imagine.cache.resolver.the_resolver_name'); + $this->assertInstanceOf(ChildDefinition::class, $resolverDefinition); + $this->assertSame('liip_imagine.cache.resolver.prototype.psr_cache', $resolverDefinition->getParent()); + + $this->assertInstanceOf(Reference::class, $resolverDefinition->getArgument(0)); + $this->assertSame('the_cache_service_id', (string) $resolverDefinition->getArgument(0)); + + $this->assertInstanceOf(Reference::class, $resolverDefinition->getArgument(1)); + $this->assertSame('liip_imagine.cache.resolver.the_resolver_name.cached', (string) $resolverDefinition->getArgument(1)); + } + + /** + * @group legacy + */ public function testWrapResolverWithProxyAndCacheOnCreate(): void { + $this->expectDeprecation('Since liip/imagine-bundle 2.13.4: Setting the "liip_imagine.resolvers.the_resolver_name.aws_s3.use_psr_cache" config option to "false" is deprecated.'); + $container = new ContainerBuilder(); $resolver = new AwsS3ResolverFactory(); @@ -203,6 +253,7 @@ public function testWrapResolverWithProxyAndCacheOnCreate(): void 'get_options' => [], 'put_options' => [], 'cache' => 'the_cache_service_id', + 'use_psr_cache' => false, 'proxies' => ['foo'], ]); @@ -233,8 +284,13 @@ public function testWrapResolverWithProxyAndCacheOnCreate(): void $this->assertSame('liip_imagine.cache.resolver.the_resolver_name.cached', (string) $resolverDefinition->getArgument(1)); } + /** + * @group legacy + */ public function testWrapResolverWithProxyMatchReplaceStrategyOnCreate(): void { + $this->expectDeprecation('Since liip/imagine-bundle 2.13.4: Setting the "liip_imagine.resolvers.the_resolver_name.aws_s3.use_psr_cache" config option to "false" is deprecated.'); + $container = new ContainerBuilder(); $resolver = new AwsS3ResolverFactory(); @@ -246,6 +302,7 @@ public function testWrapResolverWithProxyMatchReplaceStrategyOnCreate(): void 'get_options' => [], 'put_options' => [], 'cache' => 'the_cache_service_id', + 'use_psr_cache' => false, 'proxies' => ['foo' => 'bar'], ]); diff --git a/composer.json b/composer.json index 933da3d3d..a1e0da6df 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "php": "^7.2|^8.0", "ext-mbstring": "*", "imagine/imagine": "^1.3.2", + "symfony/deprecation-contracts": "^2.5 || ^3", "symfony/filesystem": "^3.4|^4.4|^5.3|^6.0|^7.0", "symfony/finder": "^3.4|^4.4|^5.3|^6.0|^7.0", "symfony/framework-bundle": "^3.4.23|^4.4|^5.3|^6.0|^7.0", From 8463162dfd239e09cd99c2625696e5dfce9d9aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20de=20Guillebon?= Date: Tue, 26 Aug 2025 12:10:40 +0200 Subject: [PATCH 06/27] feature: support disabled acls on s3 buckets --- CHANGELOG.md | 1 + .../Factory/Resolver/AwsS3ResolverFactory.php | 1 - Imagine/Cache/Resolver/AwsS3Resolver.php | 35 +++++++++---------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82cc170fb..55f1dea6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic ## Next Release +- Allow configuring empty ACLs on AWS S3 resolver to skip ACLs ([deguif](https://github.com/liip/LiipImagineBundle/pull/1629)) - Add `use_psr_cache` option to AWS S3 resolver configuration in order to support PSR cache. Configuring a doctrine cache now will trigger a deprecation ([deguif](https://github.com/liip/LiipImagineBundle/pull/1630)) ## [2.13.3](https://github.com/liip/LiipImagineBundle/tree/2.13.3) diff --git a/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php b/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php index 8ce6dd2e0..dbdb66051 100644 --- a/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php +++ b/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php @@ -96,7 +96,6 @@ public function addConfiguration(ArrayNodeDefinition $builder) ->end() ->scalarNode('acl') ->defaultValue('public-read') - ->cannotBeEmpty() ->end() ->scalarNode('cache_prefix') ->defaultValue('') diff --git a/Imagine/Cache/Resolver/AwsS3Resolver.php b/Imagine/Cache/Resolver/AwsS3Resolver.php index 75ee2f112..258ba9052 100644 --- a/Imagine/Cache/Resolver/AwsS3Resolver.php +++ b/Imagine/Cache/Resolver/AwsS3Resolver.php @@ -58,17 +58,17 @@ class AwsS3Resolver implements ResolverInterface /** * Constructs a cache resolver storing images on Amazon S3. * - * @param S3Client $storage The Amazon S3 storage API. It's required to know authentication information - * @param string $bucket The bucket name to operate on - * @param string $acl The ACL to use when storing new objects. Default: owner read/write, public read - * @param array $getOptions A list of options to be passed when retrieving the object url from Amazon S3 - * @param array $putOptions A list of options to be passed when saving the object to Amazon S3 + * @param S3Client $storage The Amazon S3 storage API. It's required to know authentication information + * @param string $bucket The bucket name to operate on + * @param string|null $acl The ACL to use when storing new objects. Default: owner read/write, public read + * @param array $getOptions A list of options to be passed when retrieving the object url from Amazon S3 + * @param array $putOptions A list of options to be passed when saving the object to Amazon S3 */ public function __construct(S3Client $storage, $bucket, $acl = 'public-read', array $getOptions = [], $putOptions = []) { $this->storage = $storage; $this->bucket = $bucket; - $this->acl = $acl; + $this->acl = $acl ?? ''; $this->getOptions = $getOptions; $this->putOptions = $putOptions; } @@ -99,20 +99,19 @@ public function resolve($path, $filter) public function store(BinaryInterface $binary, $path, $filter) { $objectPath = $this->getObjectPath($path, $filter); + $options = [ + 'Bucket' => $this->bucket, + 'Key' => $objectPath, + 'Body' => $binary->getContent(), + 'ContentType' => $binary->getMimeType(), + ]; + + if ('' !== $this->acl) { + $options['ACL'] = $this->acl; + } try { - $this->storage->putObject( - array_merge( - $this->putOptions, - [ - 'ACL' => $this->acl, - 'Bucket' => $this->bucket, - 'Key' => $objectPath, - 'Body' => $binary->getContent(), - 'ContentType' => $binary->getMimeType(), - ] - ) - ); + $this->storage->putObject(array_merge($this->putOptions, $options)); } catch (\Exception $e) { $this->logError('The object could not be created on Amazon S3.', [ 'objectPath' => $objectPath, From 676cfd14c290db703493a5b1a1434b7b77731fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20de=20Guillebon?= Date: Wed, 27 Aug 2025 17:20:42 +0200 Subject: [PATCH 07/27] feature: add ability to inject a custom S3 client on aws s3 resolver --- CHANGELOG.md | 1 + .../Factory/Resolver/AwsS3ResolverFactory.php | 36 +++++++++++-- Resources/doc/cache-resolver/aws_s3.rst | 18 +++++++ .../Resolver/AwsS3ResolverFactoryTest.php | 54 +++++++++++++++++++ 4 files changed, 105 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82cc170fb..9d23f19a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic ## Next Release - Add `use_psr_cache` option to AWS S3 resolver configuration in order to support PSR cache. Configuring a doctrine cache now will trigger a deprecation ([deguif](https://github.com/liip/LiipImagineBundle/pull/1630)) +- Add ability to specify a custom s3 client service in aws s3 resolver configuration ([deguif](https://github.com/liip/LiipImagineBundle/pull/1632)) ## [2.13.3](https://github.com/liip/LiipImagineBundle/tree/2.13.3) diff --git a/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php b/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php index 8ce6dd2e0..1825cea45 100644 --- a/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php +++ b/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php @@ -12,6 +12,8 @@ namespace Liip\ImagineBundle\DependencyInjection\Factory\Resolver; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; +use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; @@ -21,10 +23,15 @@ class AwsS3ResolverFactory extends AbstractResolverFactory public function create(ContainerBuilder $container, $resolverName, array $config) { $awsS3ClientId = 'liip_imagine.cache.resolver.'.$resolverName.'.client'; - $awsS3ClientDefinition = new Definition('Aws\S3\S3Client'); - $awsS3ClientDefinition->setFactory(['Aws\S3\S3Client', 'factory']); - $awsS3ClientDefinition->addArgument($config['client_config']); - $container->setDefinition($awsS3ClientId, $awsS3ClientDefinition); + + if ($config['client_id']) { + $container->setAlias($awsS3ClientId, new Alias($config['client_id'])); + } else { + $container->setDefinition($awsS3ClientId, (new Definition('Aws\S3\S3Client')) + ->setFactory(['Aws\S3\S3Client', 'factory']) + ->addArgument($config['client_config']) + ); + } $resolverDefinition = $this->getChildResolverDefinition(); $resolverDefinition->replaceArgument(0, new Reference($awsS3ClientId)); @@ -101,6 +108,9 @@ public function addConfiguration(ArrayNodeDefinition $builder) ->scalarNode('cache_prefix') ->defaultValue('') ->end() + ->scalarNode('client_id') + ->defaultNull() + ->end() ->arrayNode('client_config') ->isRequired() ->prototype('variable') @@ -123,6 +133,24 @@ public function addConfiguration(ArrayNodeDefinition $builder) ->prototype('scalar') ->end() ->end() + ->end() + ->beforeNormalization() + ->ifTrue(static function ($v) { + return isset($v['client_id']) && isset($v['client_config']); + }) + ->then(static function ($v) { + throw new InvalidConfigurationException('Children config "client_id" and "client_config" cannot be configured at the same time.'); + }) + ->end() + ->beforeNormalization() + ->ifTrue(static function ($v) { + return isset($v['client_id']); + }) + ->then(function ($config) { + $config['client_config'] = []; + + return $config; + }) ->end(); } } diff --git a/Resources/doc/cache-resolver/aws_s3.rst b/Resources/doc/cache-resolver/aws_s3.rst index 891813a49..f9535a14a 100644 --- a/Resources/doc/cache-resolver/aws_s3.rst +++ b/Resources/doc/cache-resolver/aws_s3.rst @@ -83,6 +83,24 @@ Create Resolver from a Factory region: "%amazon.s3.region%" bucket: "%amazon.s3.bucket%" +Create Resolver from a custom S3 client service +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: yaml + + # app/config/config.yml + + liip_imagine: + resolvers: + aws_s3_resolver: + aws_s3: + client_id: 'custom_aws_s3_client_service' + bucket: "%amazon.s3.bucket%" + get_options: + Scheme: https + put_options: + CacheControl: "max-age=86400" + Create Resolver as a Service ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php b/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php index 9805bcead..3c5f2f882 100644 --- a/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php +++ b/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php @@ -57,6 +57,7 @@ public function testCreateResolverDefinitionOnCreate(): void $resolver = new AwsS3ResolverFactory(); $resolver->create($container, 'the_resolver_name', [ + 'client_id' => null, 'client_config' => [], 'bucket' => 'theBucket', 'acl' => 'theAcl', @@ -88,6 +89,7 @@ public function testCreateS3ClientDefinitionOnCreate(): void $resolver = new AwsS3ResolverFactory(); $resolver->create($container, 'the_resolver_name', [ + 'client_id' => null, 'client_config' => ['theClientConfigKey' => 'theClientConfigVal'], 'bucket' => 'aBucket', 'acl' => 'aAcl', @@ -111,6 +113,7 @@ public function testCreateS3ClientDefinitionWithFactoryOnCreate(): void $resolver = new AwsS3ResolverFactory(); $resolver->create($container, 'the_resolver_name', [ + 'client_id' => null, 'client_config' => ['theClientConfigKey' => 'theClientConfigVal'], 'bucket' => 'aBucket', 'acl' => 'aAcl', @@ -124,6 +127,29 @@ public function testCreateS3ClientDefinitionWithFactoryOnCreate(): void $this->assertSame([S3Client::class, 'factory'], $clientDefinition->getFactory()); } + public function testCreateS3ClientAliasOnCreate(): void + { + $container = new ContainerBuilder(); + + $resolver = new AwsS3ResolverFactory(); + + $resolver->create($container, 'the_resolver_name', [ + 'client_id' => 's3.client.default', + 'client_config' => [], + 'bucket' => 'aBucket', + 'acl' => 'aAcl', + 'get_options' => [], + 'put_options' => [], + 'cache' => false, + 'proxies' => [], + ]); + + $this->assertTrue($container->hasAlias('liip_imagine.cache.resolver.the_resolver_name.client')); + + $clientAlias = $container->getAlias('liip_imagine.cache.resolver.the_resolver_name.client'); + $this->assertSame('s3.client.default', (string) $clientAlias); + } + public function testWrapResolverWithProxyOnCreateWithoutCache(): void { $container = new ContainerBuilder(); @@ -131,6 +157,7 @@ public function testWrapResolverWithProxyOnCreateWithoutCache(): void $resolver = new AwsS3ResolverFactory(); $resolver->create($container, 'the_resolver_name', [ + 'client_id' => null, 'client_config' => [], 'bucket' => 'aBucket', 'acl' => 'aAcl', @@ -170,6 +197,7 @@ public function testWrapResolverWithCacheOnCreateWithoutProxy(): void $resolver = new AwsS3ResolverFactory(); $resolver->create($container, 'the_resolver_name', [ + 'client_id' => null, 'client_config' => [], 'bucket' => 'aBucket', 'acl' => 'aAcl', @@ -206,6 +234,7 @@ public function testWrapResolverWithPsrCacheOnCreateWithoutProxy(): void $resolver = new AwsS3ResolverFactory(); $resolver->create($container, 'the_resolver_name', [ + 'client_id' => null, 'client_config' => [], 'bucket' => 'aBucket', 'acl' => 'aAcl', @@ -247,6 +276,7 @@ public function testWrapResolverWithProxyAndCacheOnCreate(): void $resolver = new AwsS3ResolverFactory(); $resolver->create($container, 'the_resolver_name', [ + 'client_id' => null, 'client_config' => [], 'bucket' => 'aBucket', 'acl' => 'aAcl', @@ -296,6 +326,7 @@ public function testWrapResolverWithProxyMatchReplaceStrategyOnCreate(): void $resolver = new AwsS3ResolverFactory(); $resolver->create($container, 'the_resolver_name', [ + 'client_id' => null, 'client_config' => [], 'bucket' => 'aBucket', 'acl' => 'aAcl', @@ -329,6 +360,7 @@ public function testSetCachePrefixIfDefined(): void $resolver = new AwsS3ResolverFactory(); $resolver->create($container, 'the_resolver_name', [ + 'client_id' => null, 'client_config' => [], 'bucket' => 'aBucket', 'acl' => 'aAcl', @@ -406,6 +438,28 @@ public function testThrowClientConfigNotArrayOnAddConfiguration(): void ]); } + public function testThrowClientConfigAmbiguousOnAddConfiguration(): void + { + $this->expectException(\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException::class); + $this->expectExceptionMessageMatchesBC('/Children config "client_id" and "client_config" cannot be configured at the same time./'); + + $treeBuilder = new TreeBuilder('aws_s3'); + $rootNode = method_exists(TreeBuilder::class, 'getRootNode') + ? $treeBuilder->getRootNode() + : $treeBuilder->root('aws_s3'); + + $resolver = new AwsS3ResolverFactory(); + $resolver->addConfiguration($rootNode); + + $this->processConfigTree($treeBuilder, [ + 'aws_s3' => [ + 'bucket' => 'aBucket', + 'client_id' => 'aClientId', + 'client_config' => [], + ], + ]); + } + public function testProcessCorrectlyOptionsOnAddConfiguration(): void { $expectedClientConfig = [ From f80dc13e9a454682b8c2255b3487829d2f8a7fe4 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Wed, 3 Sep 2025 08:33:10 +0200 Subject: [PATCH 08/27] prepare release --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0847a3cfe..0b9252c28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic # 2.x -## Next Release +## [2.14.0](https://github.com/liip/LiipImagineBundle/tree/2.14.0) - Allow configuring empty ACLs on AWS S3 resolver to skip ACLs ([deguif](https://github.com/liip/LiipImagineBundle/pull/1629)) - Add `use_psr_cache` option to AWS S3 resolver configuration in order to support PSR cache. Configuring a doctrine cache now will trigger a deprecation ([deguif](https://github.com/liip/LiipImagineBundle/pull/1630)) From 876d2331e2134a69600025a5f7a55a10e78c671f Mon Sep 17 00:00:00 2001 From: David Maicher Date: Wed, 8 Oct 2025 19:58:38 +0200 Subject: [PATCH 09/27] Refactor `Request::get()` usages --- Controller/ImagineController.php | 4 ++-- Tests/Controller/ImagineControllerTest.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Controller/ImagineController.php b/Controller/ImagineController.php index c21a8cd5d..876d7be08 100644 --- a/Controller/ImagineController.php +++ b/Controller/ImagineController.php @@ -85,7 +85,7 @@ public function __construct( public function filterAction(Request $request, $path, $filter) { $path = PathHelper::urlPathToFilePath($path); - $resolver = $request->get('resolver'); + $resolver = $request->query->has('resolver') ? (string) $request->query->get('resolver') : null; return $this->createRedirectResponse(function () use ($path, $filter, $resolver, $request) { return $this->filterService->getUrlOfFilteredImage( @@ -116,7 +116,7 @@ public function filterAction(Request $request, $path, $filter) */ public function filterRuntimeAction(Request $request, $hash, $path, $filter) { - $resolver = $request->get('resolver'); + $resolver = $request->query->has('resolver') ? (string) $request->query->get('resolver') : null; $path = PathHelper::urlPathToFilePath($path); $runtimeConfig = $this->getFiltersBc($request); diff --git a/Tests/Controller/ImagineControllerTest.php b/Tests/Controller/ImagineControllerTest.php index ae7ec25f9..40e7485b6 100644 --- a/Tests/Controller/ImagineControllerTest.php +++ b/Tests/Controller/ImagineControllerTest.php @@ -90,9 +90,9 @@ public function testInvalidRedirectResponseCode(int $redirectResponseCode): void { $this->expectException(InvalidArgumentException::class); $this->createControllerInstance( - $path = '/foo', - $filter = 'filter', - $hash = 'hash', + '/foo', + 'filter', + 'hash', $redirectResponseCode, false ); From 4678f7fae389210adb23c2d1a43203fc96dc2cd2 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 9 Oct 2025 08:46:39 +0200 Subject: [PATCH 10/27] add note for future improvement --- Controller/ImagineController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Controller/ImagineController.php b/Controller/ImagineController.php index 876d7be08..8dc842654 100644 --- a/Controller/ImagineController.php +++ b/Controller/ImagineController.php @@ -85,6 +85,7 @@ public function __construct( public function filterAction(Request $request, $path, $filter) { $path = PathHelper::urlPathToFilePath($path); + // TODO once we limit `symfony/http-foundation` to 6.4 or newer, use `$request->query->getString()` $resolver = $request->query->has('resolver') ? (string) $request->query->get('resolver') : null; return $this->createRedirectResponse(function () use ($path, $filter, $resolver, $request) { From f8c98a5a962806f26571db219412b64266c763d8 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 9 Oct 2025 08:49:28 +0200 Subject: [PATCH 11/27] prepare release --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b9252c28..b1f2b1993 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic # 2.x +## [2.15.0](https://github.com/liip/LiipImagineBundle/tree/2.14.0) + +- Refactored `Request::get()` to `Request::query::get()` to avoid deprecation with Symfony 7.4 ([dmaicher](https://github.com/liip/LiipImagineBundle/pull/1636)) + ## [2.14.0](https://github.com/liip/LiipImagineBundle/tree/2.14.0) - Allow configuring empty ACLs on AWS S3 resolver to skip ACLs ([deguif](https://github.com/liip/LiipImagineBundle/pull/1629)) From 3fcf2b782e21d41d4fb40b129fb87a593ab227a4 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Mon, 13 Oct 2025 18:37:11 +0200 Subject: [PATCH 12/27] drop support for unmaintained Symfony versions --- .github/workflows/phpunit.yml | 30 ++++------------ Controller/ImagineController.php | 23 ++++--------- DependencyInjection/Configuration.php | 4 +-- DependencyInjection/LiipImagineExtension.php | 6 +--- .../Factory/Loader/ChainLoaderFactoryTest.php | 4 +-- .../Loader/FileSystemLoaderFactoryTest.php | 12 ++----- .../Loader/FlysystemLoaderFactoryTest.php | 8 ++--- .../Loader/StreamLoaderFactoryTest.php | 12 ++----- .../Resolver/AwsS3ResolverFactoryTest.php | 28 ++++----------- .../Resolver/FlysystemResolverFactoryTest.php | 8 ++--- .../Resolver/WebPathResolverFactoryTest.php | 8 ++--- .../LiipImagineExtensionTest.php | 2 +- Tests/Functional/app/AppKernel.php | 6 +--- .../Functional/app/config/symfony_legacy.yaml | 3 -- composer.json | 34 +++++++++---------- 15 files changed, 54 insertions(+), 134 deletions(-) delete mode 100644 Tests/Functional/app/config/symfony_legacy.yaml diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index c7bf2fb88..06910c7a5 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] dependencies: [highest] symfony: ['*'] stability: ['stable'] @@ -26,7 +26,7 @@ jobs: stability: 'stable' # Minimum supported dependencies with the latest supported PHP version - - php: '8.2' + - php: '8.4' dependencies: lowest symfony: '*' stability: 'stable' @@ -34,29 +34,18 @@ jobs: # Test each supported Symfony version with the lowest supported PHP version - php: '7.2' dependencies: highest - symfony: '3.4.*' + symfony: '5.4.*' stability: 'stable' - - php: '7.2' - dependencies: highest - symfony: '4.4.*' - stability: 'stable' - - - php: '7.2' - dependencies: highest - symfony: '5.3.*' - stability: 'stable' - - # Test Symfony 6.4 dev version - - php: '8.2' + - php: '8.1' dependencies: highest symfony: '6.4.*' - stability: 'dev' + stability: 'stable' - # Test Symfony 7.0 dev version + # Test Symfony 7.3 dev version - php: '8.2' dependencies: highest - symfony: '7.0.*' + symfony: '7.3.*' stability: 'dev' steps: - name: Checkout @@ -88,11 +77,6 @@ jobs: - name: Set minimum-stability run: composer config minimum-stability ${{ matrix.stability }} - # Incompatible with symfony/framework-bundle v3 - - name: Remove symfony/messenger - if: ${{ matrix.php == '7.2' && matrix.symfony == '3.4.*' }} - run: composer remove --dev --no-update symfony/messenger - # Latest enqueue install on PHP 7.4 but uses PHP 8 features - name: Pin enqueue/enqueue on PHP 7.4 if: ${{ matrix.php == '7.4' }} diff --git a/Controller/ImagineController.php b/Controller/ImagineController.php index 8dc842654..6acb16248 100644 --- a/Controller/ImagineController.php +++ b/Controller/ImagineController.php @@ -24,7 +24,6 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Symfony\Component\HttpKernel\Kernel; class ImagineController { @@ -138,23 +137,13 @@ public function filterRuntimeAction(Request $request, $hash, $path, $filter) private function getFiltersBc(Request $request): array { - if (version_compare(Kernel::VERSION, '5.1', '>=')) { - try { - return $request->query->all('filters'); - } catch (BadRequestException $e) { - // for strict BC - BadRequestException seems more suited to this situation. - // remove the try-catch in version 3 - throw new NotFoundHttpException(\sprintf('Filters must be an array. Value was "%s"', $request->query->get('filters'))); - } - } - - $runtimeConfig = $request->query->get('filters', []); - - if (!\is_array($runtimeConfig)) { - throw new NotFoundHttpException(\sprintf('Filters must be an array. Value was "%s"', $runtimeConfig)); + try { + return $request->query->all('filters'); + } catch (BadRequestException $e) { + // for strict BC - BadRequestException seems more suited to this situation. + // remove the try-catch in version 3 + throw new NotFoundHttpException(\sprintf('Filters must be an array. Value was "%s"', $request->query->get('filters'))); } - - return $runtimeConfig; } private function createRedirectResponse(\Closure $url, string $path, string $filter, ?string $hash = null): RedirectResponse diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 8648eea92..37085126a 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -46,9 +46,7 @@ public function __construct(array $resolversFactories, array $loadersFactories) public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('liip_imagine'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('liip_imagine'); + $rootNode = $treeBuilder->getRootNode(); $resolversPrototypeNode = $rootNode ->children() diff --git a/DependencyInjection/LiipImagineExtension.php b/DependencyInjection/LiipImagineExtension.php index d58add348..34e2ff1e7 100644 --- a/DependencyInjection/LiipImagineExtension.php +++ b/DependencyInjection/LiipImagineExtension.php @@ -202,11 +202,7 @@ private function deprecationTemplatingFilterHelper(ContainerBuilder $container): $message = 'The "%service_id%" service is deprecated since LiipImagineBundle 2.2 and will be removed in 3.0.'; $definition = $container->getDefinition('liip_imagine.templating.filter_helper'); - if (method_exists(Definition::class, 'getDeprecation')) { - $definition->setDeprecated('liip/imagine-bundle', '2.2', $message); - } else { - $definition->setDeprecated(true, $message); - } + $definition->setDeprecated('liip/imagine-bundle', '2.2', $message); } private function loadTwig(array $config, XmlFileLoader $loader, ContainerBuilder $container): void diff --git a/Tests/DependencyInjection/Factory/Loader/ChainLoaderFactoryTest.php b/Tests/DependencyInjection/Factory/Loader/ChainLoaderFactoryTest.php index 86fdda485..fbf473d7f 100644 --- a/Tests/DependencyInjection/Factory/Loader/ChainLoaderFactoryTest.php +++ b/Tests/DependencyInjection/Factory/Loader/ChainLoaderFactoryTest.php @@ -64,9 +64,7 @@ public function testCreateLoaderDefinition(): void public function testProcessOptionsOnAddConfiguration(): void { $treeBuilder = new TreeBuilder('chain'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('chain'); + $rootNode = $treeBuilder->getRootNode(); $loader = new ChainLoaderFactory(); $loader->addConfiguration($rootNode); diff --git a/Tests/DependencyInjection/Factory/Loader/FileSystemLoaderFactoryTest.php b/Tests/DependencyInjection/Factory/Loader/FileSystemLoaderFactoryTest.php index 646ad948c..197d0ecb7 100644 --- a/Tests/DependencyInjection/Factory/Loader/FileSystemLoaderFactoryTest.php +++ b/Tests/DependencyInjection/Factory/Loader/FileSystemLoaderFactoryTest.php @@ -299,9 +299,7 @@ public function testProcessCorrectlyOptionsOnAddConfiguration(): void $expectedDataRoot = ['theDataRoot']; $treeBuilder = new TreeBuilder('filesystem'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('filesystem'); + $rootNode = $treeBuilder->getRootNode(); $loader = new FileSystemLoaderFactory(); $loader->addConfiguration($rootNode); @@ -321,9 +319,7 @@ public function testAddDefaultOptionsIfNotSetOnAddConfiguration(): void $expectedDataRoot = [SymfonyFramework::getContainerResolvableRootWebPath()]; $treeBuilder = new TreeBuilder('filesystem'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('filesystem'); + $rootNode = $treeBuilder->getRootNode(); $loader = new FileSystemLoaderFactory(); $loader->addConfiguration($rootNode); @@ -341,9 +337,7 @@ public function testAddAsScalarExpectingArrayNormalizationOfConfiguration(): voi $expectedDataRoot = [SymfonyFramework::getContainerResolvableRootWebPath()]; $treeBuilder = new TreeBuilder('filesystem'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('filesystem'); + $rootNode = $treeBuilder->getRootNode(); $loader = new FileSystemLoaderFactory(); $loader->addConfiguration($rootNode); diff --git a/Tests/DependencyInjection/Factory/Loader/FlysystemLoaderFactoryTest.php b/Tests/DependencyInjection/Factory/Loader/FlysystemLoaderFactoryTest.php index 2bc70c117..8381023c0 100644 --- a/Tests/DependencyInjection/Factory/Loader/FlysystemLoaderFactoryTest.php +++ b/Tests/DependencyInjection/Factory/Loader/FlysystemLoaderFactoryTest.php @@ -89,9 +89,7 @@ public function testThrowIfFileSystemServiceNotSetOnAddConfiguration(): void $this->expectExceptionMessageMatchesBC('/^The child (node|config) "filesystem_service" (at path|under) "flysystem" must be configured\.$/'); $treeBuilder = new TreeBuilder('flysystem'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('flysystem'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new FlysystemLoaderFactory(); $resolver->addConfiguration($rootNode); @@ -104,9 +102,7 @@ public function testProcessCorrectlyOptionsOnAddConfiguration(): void $expectedService = 'theService'; $treeBuilder = new TreeBuilder('flysystem'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('flysystem'); + $rootNode = $treeBuilder->getRootNode(); $loader = new FlysystemLoaderFactory(); $loader->addConfiguration($rootNode); diff --git a/Tests/DependencyInjection/Factory/Loader/StreamLoaderFactoryTest.php b/Tests/DependencyInjection/Factory/Loader/StreamLoaderFactoryTest.php index c5a2be454..3dbbd83d1 100644 --- a/Tests/DependencyInjection/Factory/Loader/StreamLoaderFactoryTest.php +++ b/Tests/DependencyInjection/Factory/Loader/StreamLoaderFactoryTest.php @@ -72,9 +72,7 @@ public function testThrowIfWrapperNotSetOnAddConfiguration(): void $this->expectExceptionMessageMatchesBC('/^The child (node|config) "wrapper" (at path|under) "stream" must be configured\.$/'); $treeBuilder = new TreeBuilder('stream'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('stream'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new StreamLoaderFactory(); $resolver->addConfiguration($rootNode); @@ -88,9 +86,7 @@ public function testProcessCorrectlyOptionsOnAddConfiguration(): void $expectedContext = 'theContext'; $treeBuilder = new TreeBuilder('stream'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('stream'); + $rootNode = $treeBuilder->getRootNode(); $loader = new StreamLoaderFactory(); $loader->addConfiguration($rootNode); @@ -112,9 +108,7 @@ public function testProcessCorrectlyOptionsOnAddConfiguration(): void public function testAddDefaultOptionsIfNotSetOnAddConfiguration(): void { $treeBuilder = new TreeBuilder('stream'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('stream'); + $rootNode = $treeBuilder->getRootNode(); $loader = new StreamLoaderFactory(); $loader->addConfiguration($rootNode); diff --git a/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php b/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php index 3c5f2f882..4f401ad12 100644 --- a/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php +++ b/Tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php @@ -387,9 +387,7 @@ public function testThrowBucketNotSetOnAddConfiguration(): void $this->expectExceptionMessageMatchesBC('/^The child (node|config) "bucket" (at path|under) "aws_s3" must be configured\.$/'); $treeBuilder = new TreeBuilder('aws_s3'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('aws_s3'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new AwsS3ResolverFactory(); $resolver->addConfiguration($rootNode); @@ -403,9 +401,7 @@ public function testThrowClientConfigNotSetOnAddConfiguration(): void $this->expectExceptionMessageMatchesBC('/^The child (node|config) "client_config" (at path|under) "aws_s3" must be configured\.$/'); $treeBuilder = new TreeBuilder('aws_s3'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('aws_s3'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new AwsS3ResolverFactory(); $resolver->addConfiguration($rootNode); @@ -423,9 +419,7 @@ public function testThrowClientConfigNotArrayOnAddConfiguration(): void $this->expectExceptionMessageMatchesBC('{^Invalid type for path "aws_s3.client_config". Expected (\")?array(\")?, but got (\")?string(\")?$}'); $treeBuilder = new TreeBuilder('aws_s3'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('aws_s3'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new AwsS3ResolverFactory(); $resolver->addConfiguration($rootNode); @@ -444,9 +438,7 @@ public function testThrowClientConfigAmbiguousOnAddConfiguration(): void $this->expectExceptionMessageMatchesBC('/Children config "client_id" and "client_config" cannot be configured at the same time./'); $treeBuilder = new TreeBuilder('aws_s3'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('aws_s3'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new AwsS3ResolverFactory(); $resolver->addConfiguration($rootNode); @@ -479,9 +471,7 @@ public function testProcessCorrectlyOptionsOnAddConfiguration(): void $expectedCachePrefix = 'theCachePrefix'; $treeBuilder = new TreeBuilder('aws_s3'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('aws_s3'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new AwsS3ResolverFactory(); $resolver->addConfiguration($rootNode); @@ -521,9 +511,7 @@ public function testAddDefaultOptionsIfNotSetOnAddConfiguration(): void $expectedAcl = 'public-read'; $treeBuilder = new TreeBuilder('aws_s3'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('aws_s3'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new AwsS3ResolverFactory(); $resolver->addConfiguration($rootNode); @@ -569,9 +557,7 @@ public function testSupportAwsV3ClientConfig(): void $expectedCachePrefix = 'theCachePrefix'; $treeBuilder = new TreeBuilder('aws_s3'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('aws_s3'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new AwsS3ResolverFactory(); $resolver->addConfiguration($rootNode); diff --git a/Tests/DependencyInjection/Factory/Resolver/FlysystemResolverFactoryTest.php b/Tests/DependencyInjection/Factory/Resolver/FlysystemResolverFactoryTest.php index aa11e39e5..66a8a1935 100644 --- a/Tests/DependencyInjection/Factory/Resolver/FlysystemResolverFactoryTest.php +++ b/Tests/DependencyInjection/Factory/Resolver/FlysystemResolverFactoryTest.php @@ -95,9 +95,7 @@ public function testProcessCorrectlyOptionsOnAddConfiguration(): void $expectedVisibility = 'public'; $treeBuilder = new TreeBuilder('flysystem'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('flysystem'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new FlysystemResolverFactory(); $resolver->addConfiguration($rootNode); @@ -129,9 +127,7 @@ public function testAddDefaultOptionsIfNotSetOnAddConfiguration(): void $this->expectException(\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException::class); $treeBuilder = new TreeBuilder('flysystem'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('flysystem'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new FlysystemResolverFactory(); $resolver->addConfiguration($rootNode); diff --git a/Tests/DependencyInjection/Factory/Resolver/WebPathResolverFactoryTest.php b/Tests/DependencyInjection/Factory/Resolver/WebPathResolverFactoryTest.php index f25391ec3..21a6237bb 100644 --- a/Tests/DependencyInjection/Factory/Resolver/WebPathResolverFactoryTest.php +++ b/Tests/DependencyInjection/Factory/Resolver/WebPathResolverFactoryTest.php @@ -73,9 +73,7 @@ public function testProcessCorrectlyOptionsOnAddConfiguration(): void $expectedCachePrefix = 'theCachePrefix'; $treeBuilder = new TreeBuilder('web_path'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('web_path'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new WebPathResolverFactory(); $resolver->addConfiguration($rootNode); @@ -97,9 +95,7 @@ public function testProcessCorrectlyOptionsOnAddConfiguration(): void public function testAddDefaultOptionsIfNotSetOnAddConfiguration(): void { $treeBuilder = new TreeBuilder('web_path'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') - ? $treeBuilder->getRootNode() - : $treeBuilder->root('web_path'); + $rootNode = $treeBuilder->getRootNode(); $resolver = new WebPathResolverFactory(); $resolver->addConfiguration($rootNode); diff --git a/Tests/DependencyInjection/LiipImagineExtensionTest.php b/Tests/DependencyInjection/LiipImagineExtensionTest.php index 9291859ac..e399f739c 100644 --- a/Tests/DependencyInjection/LiipImagineExtensionTest.php +++ b/Tests/DependencyInjection/LiipImagineExtensionTest.php @@ -346,7 +346,7 @@ private function assertDefinitionIsDeprecated(string $id, string $message): void $definition = $this->containerBuilder->getDefinition($id); $this->assertTrue($definition->isDeprecated()); - $deprecation = method_exists(Definition::class, 'getDeprecation') ? $definition->getDeprecation($id)['message'] : $definition->getDeprecationMessage($id); + $deprecation = $definition->getDeprecation($id)['message']; $this->assertSame($message, $deprecation); } } diff --git a/Tests/Functional/app/AppKernel.php b/Tests/Functional/app/AppKernel.php index 310f32050..f781c0560 100644 --- a/Tests/Functional/app/AppKernel.php +++ b/Tests/Functional/app/AppKernel.php @@ -50,11 +50,7 @@ public function getProjectDir(): string public function registerContainerConfiguration(LoaderInterface $loader): void { $loader->load(function (ContainerBuilder $container) use ($loader) { - if (version_compare(self::VERSION, '5.3', '>=')) { - $loader->load($this->getProjectDir().'/config/symfony_5-3.yaml'); - } else { - $loader->load($this->getProjectDir().'/config/symfony_legacy.yaml'); - } + $loader->load($this->getProjectDir().'/config/symfony_5-3.yaml'); $loader->load($this->getProjectDir().'/config/config.yml'); diff --git a/Tests/Functional/app/config/symfony_legacy.yaml b/Tests/Functional/app/config/symfony_legacy.yaml deleted file mode 100644 index 06e6bb543..000000000 --- a/Tests/Functional/app/config/symfony_legacy.yaml +++ /dev/null @@ -1,3 +0,0 @@ -framework: - session: - storage_id: session.storage.mock_file diff --git a/composer.json b/composer.json index a1e0da6df..09cf6c0d1 100644 --- a/composer.json +++ b/composer.json @@ -22,12 +22,12 @@ "ext-mbstring": "*", "imagine/imagine": "^1.3.2", "symfony/deprecation-contracts": "^2.5 || ^3", - "symfony/filesystem": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/finder": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/framework-bundle": "^3.4.23|^4.4|^5.3|^6.0|^7.0", - "symfony/mime": "^4.4|^5.3|^6.0|^7.0", - "symfony/options-resolver": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/process": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.4|^7.3", + "symfony/finder": "^5.4|^6.4|^7.3", + "symfony/framework-bundle": "^5.4|^6.4|^7.3", + "symfony/mime": "^5.4|^6.4|^7.3", + "symfony/options-resolver": "^5.4|^6.4|^7.3", + "symfony/process": "^5.4|^6.4|^7.3", "twig/twig": "^1.44|^2.9|^3.0" }, "require-dev": { @@ -41,17 +41,17 @@ "phpstan/phpstan": "^1.10.0", "psr/cache": "^1.0|^2.0|^3.0", "psr/log": "^1.0", - "symfony/asset": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/browser-kit": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/cache": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/console": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/dependency-injection": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/form": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/messenger": "^4.4|^5.3|^6.0|^7.0", - "symfony/phpunit-bridge": "^7.0.2", - "symfony/templating": "^3.4|^4.4|^5.3|^6.0", - "symfony/validator": "^3.4|^4.4|^5.3|^6.0|^7.0", - "symfony/yaml": "^3.4|^4.4|^5.3|^6.0|^7.0" + "symfony/asset": "^5.4|^6.4|^7.3", + "symfony/browser-kit": "^5.4|^6.4|^7.3", + "symfony/cache": "^5.4|^6.4|^7.3", + "symfony/console": "^5.4|^6.4|^7.3", + "symfony/dependency-injection": "^5.4|^6.4|^7.3", + "symfony/form": "^5.4|^6.4|^7.3", + "symfony/messenger": "^5.4|^6.4|^7.3", + "symfony/phpunit-bridge": "^7.3", + "symfony/templating": "^5.4|^6.4|^7.3", + "symfony/validator": "^5.4|^6.4|^7.3", + "symfony/yaml": "^5.4|^6.4|^7.3" }, "suggest": { "ext-exif": "required to read EXIF metadata from images", From 079e74383a34cba0eec8a2c5e88d48b9cd604a76 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Tue, 14 Oct 2025 11:14:40 +0200 Subject: [PATCH 13/27] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1f2b1993..cfa902bde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic # 2.x +## 2.16.0 (unreleased) + +- Drop support for unmaintained Symfony versions ([dmaicher](https://github.com/liip/LiipImagineBundle/pull/1639)) + ## [2.15.0](https://github.com/liip/LiipImagineBundle/tree/2.14.0) - Refactored `Request::get()` to `Request::query::get()` to avoid deprecation with Symfony 7.4 ([dmaicher](https://github.com/liip/LiipImagineBundle/pull/1636)) From e49bfc9e196019fdc07a92ae35333d942dec4891 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Mon, 13 Oct 2025 18:11:55 +0200 Subject: [PATCH 14/27] Start moving Symfony DI config from XML to PHP format --- DependencyInjection/LiipImagineExtension.php | 29 ++++++----------- Resources/config/commands.php | 34 ++++++++++++++++++++ Resources/config/commands.xml | 23 ------------- Resources/config/enqueue.php | 28 ++++++++++++++++ Resources/config/enqueue.xml | 16 --------- Resources/config/messenger.php | 25 ++++++++++++++ Resources/config/messenger.xml | 12 ------- Resources/config/templating.php | 24 ++++++++++++++ Resources/config/templating.xml | 13 -------- composer.json | 2 +- 10 files changed, 121 insertions(+), 85 deletions(-) create mode 100644 Resources/config/commands.php delete mode 100644 Resources/config/commands.xml create mode 100644 Resources/config/enqueue.php delete mode 100644 Resources/config/enqueue.xml create mode 100644 Resources/config/messenger.php delete mode 100644 Resources/config/messenger.xml create mode 100644 Resources/config/templating.php delete mode 100644 Resources/config/templating.xml diff --git a/DependencyInjection/LiipImagineExtension.php b/DependencyInjection/LiipImagineExtension.php index 34e2ff1e7..c45d7e556 100644 --- a/DependencyInjection/LiipImagineExtension.php +++ b/DependencyInjection/LiipImagineExtension.php @@ -20,12 +20,14 @@ use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; +use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Mime\MimeTypeGuesserInterface; @@ -81,6 +83,7 @@ public function load(array $configs, ContainerBuilder $container): void $this->loadResolvers($config['resolvers'], $container); $this->loadLoaders($config['loaders'], $container); + $phpLoader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('imagine.xml'); @@ -88,18 +91,18 @@ public function load(array $configs, ContainerBuilder $container): void $this->loadTwig($config['twig'], $loader, $container); } - $loader->load('commands.xml'); + $phpLoader->load('commands.php'); if ($this->isConfigEnabled($container, $config['messenger'])) { - $this->registerMessengerConfiguration($loader); + $this->registerMessengerConfiguration($phpLoader); } if ($config['enqueue']) { - $loader->load('enqueue.xml'); + $phpLoader->load('enqueue.php'); } if ($config['templating']) { - $loader->load('templating.xml'); + $phpLoader->load('templating.php'); } $driver = $config['driver']; @@ -145,8 +148,6 @@ public function load(array $configs, ContainerBuilder $container): void ->replaceArgument(1, $mimeTypes); } - $this->deprecationTemplatingFilterHelper($container); - $container->setParameter('liip_imagine.webp.generate', $config['webp']['generate']); $webpOptions = $config['webp']; unset($webpOptions['generate']); @@ -184,25 +185,13 @@ private function createFactories(array $factories, array $configurations, Contai } } - private function registerMessengerConfiguration(XmlFileLoader $loader): void + private function registerMessengerConfiguration(LoaderInterface $loader): void { if (!interface_exists(MessageBusInterface::class)) { throw new LogicException('Messenger support cannot be enabled as the Messenger component is not installed. Try running "composer require symfony/messenger".'); } - $loader->load('messenger.xml'); - } - - private function deprecationTemplatingFilterHelper(ContainerBuilder $container): void - { - if (!$container->hasDefinition('liip_imagine.templating.filter_helper')) { - return; - } - - $message = 'The "%service_id%" service is deprecated since LiipImagineBundle 2.2 and will be removed in 3.0.'; - $definition = $container->getDefinition('liip_imagine.templating.filter_helper'); - - $definition->setDeprecated('liip/imagine-bundle', '2.2', $message); + $loader->load('messenger.php'); } private function loadTwig(array $config, XmlFileLoader $loader, ContainerBuilder $container): void diff --git a/Resources/config/commands.php b/Resources/config/commands.php new file mode 100644 index 000000000..504978a20 --- /dev/null +++ b/Resources/config/commands.php @@ -0,0 +1,34 @@ +services() + ->set('liip_imagine.command.cache_remove', RemoveCacheCommand::class) + ->tag('console.command', ['command' => 'liip:imagine:cache:remove', 'alias' => 'imagine:del']) + ->args([ + service('liip_imagine.cache.manager'), + service('liip_imagine.filter.manager'), + service('liip_imagine.service.filter'), + ]) + + ->set('liip_imagine.command.cache_resolve', ResolveCacheCommand::class) + ->tag('console.command', ['command' => 'liip:imagine:cache:resolve', 'alias' => 'imagine:get']) + ->args([ + service('liip_imagine.cache.manager'), + service('liip_imagine.filter.manager'), + service('liip_imagine.service.filter'), + ]); +}; diff --git a/Resources/config/commands.xml b/Resources/config/commands.xml deleted file mode 100644 index 4b8fac819..000000000 --- a/Resources/config/commands.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/Resources/config/enqueue.php b/Resources/config/enqueue.php new file mode 100644 index 000000000..0cff213d5 --- /dev/null +++ b/Resources/config/enqueue.php @@ -0,0 +1,28 @@ +services() + ->set('liip_imagine.async.resolve_cache_processor', ResolveCacheProcessor::class) + ->public() + ->tag('enqueue.command_subscriber') + ->tag('enqueue.transport.processor') + ->args([ + service('liip_imagine.filter.manager'), + service('liip_imagine.service.filter'), + service(ProducerInterface::class), + ]); +}; diff --git a/Resources/config/enqueue.xml b/Resources/config/enqueue.xml deleted file mode 100644 index 3cd8649da..000000000 --- a/Resources/config/enqueue.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - diff --git a/Resources/config/messenger.php b/Resources/config/messenger.php new file mode 100644 index 000000000..766000920 --- /dev/null +++ b/Resources/config/messenger.php @@ -0,0 +1,25 @@ +services() + ->set('liip_imagine.messenger.warmup_cache_processor', WarmupCacheHandler::class) + ->tag('messenger.message_handler', ['handles' => WarmupCache::class]) + ->args([ + service('liip_imagine.filter.manager'), + service('liip_imagine.service.filter'), + ]); +}; diff --git a/Resources/config/messenger.xml b/Resources/config/messenger.xml deleted file mode 100644 index f88874d00..000000000 --- a/Resources/config/messenger.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/Resources/config/templating.php b/Resources/config/templating.php new file mode 100644 index 000000000..44d8d4d59 --- /dev/null +++ b/Resources/config/templating.php @@ -0,0 +1,24 @@ +services() + ->set('liip_imagine.templating.filter_helper', FilterHelper::class) + ->tag('templating.helper', ['alias' => 'imagine']) + ->args([ + service('liip_imagine.cache.manager'), + ]) + ->deprecate('liip/imagine-bundle', '2.2', 'The "%service_id%" service is deprecated since LiipImagineBundle 2.2 and will be removed in 3.0.'); +}; diff --git a/Resources/config/templating.xml b/Resources/config/templating.xml deleted file mode 100644 index e708a71ac..000000000 --- a/Resources/config/templating.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/composer.json b/composer.json index 09cf6c0d1..6b911b558 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "php": "^7.2|^8.0", "ext-mbstring": "*", "imagine/imagine": "^1.3.2", + "symfony/dependency-injection": "^5.4|^6.4|^7.4", "symfony/deprecation-contracts": "^2.5 || ^3", "symfony/filesystem": "^5.4|^6.4|^7.3", "symfony/finder": "^5.4|^6.4|^7.3", @@ -45,7 +46,6 @@ "symfony/browser-kit": "^5.4|^6.4|^7.3", "symfony/cache": "^5.4|^6.4|^7.3", "symfony/console": "^5.4|^6.4|^7.3", - "symfony/dependency-injection": "^5.4|^6.4|^7.3", "symfony/form": "^5.4|^6.4|^7.3", "symfony/messenger": "^5.4|^6.4|^7.3", "symfony/phpunit-bridge": "^7.3", From b111bdace5cd365edad528f8160bc5bb27b7209e Mon Sep 17 00:00:00 2001 From: David Maicher Date: Tue, 21 Oct 2025 19:01:18 +0200 Subject: [PATCH 15/27] Migrate `imagine.xml` config to php format --- DependencyInjection/LiipImagineExtension.php | 2 +- Resources/config/imagine.php | 575 +++++++++++++++++++ Resources/config/imagine.xml | 460 --------------- 3 files changed, 576 insertions(+), 461 deletions(-) create mode 100644 Resources/config/imagine.php delete mode 100644 Resources/config/imagine.xml diff --git a/DependencyInjection/LiipImagineExtension.php b/DependencyInjection/LiipImagineExtension.php index c45d7e556..73a8ebfe2 100644 --- a/DependencyInjection/LiipImagineExtension.php +++ b/DependencyInjection/LiipImagineExtension.php @@ -85,7 +85,7 @@ public function load(array $configs, ContainerBuilder $container): void $phpLoader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); - $loader->load('imagine.xml'); + $phpLoader->load('imagine.php'); if ('none' !== $config['twig']['mode']) { $this->loadTwig($config['twig'], $loader, $container); diff --git a/Resources/config/imagine.php b/Resources/config/imagine.php new file mode 100644 index 000000000..045b526f3 --- /dev/null +++ b/Resources/config/imagine.php @@ -0,0 +1,575 @@ +services(); + $parameters = $container->parameters(); + + // JpegOptim parameters + $parameters->set('liip_imagine.jpegoptim.binary', '/usr/bin/jpegoptim'); + $parameters->set('liip_imagine.jpegoptim.stripAll', true); + $parameters->set('liip_imagine.jpegoptim.max', null); + $parameters->set('liip_imagine.jpegoptim.progressive', true); + $parameters->set('liip_imagine.jpegoptim.tempDir', null); + + // OptiPng parameters + $parameters->set('liip_imagine.optipng.binary', '/usr/bin/optipng'); + $parameters->set('liip_imagine.optipng.level', 7); + $parameters->set('liip_imagine.optipng.stripAll', true); + $parameters->set('liip_imagine.optipng.tempDir', null); + + // Pngquant parameters + $parameters->set('liip_imagine.pngquant.binary', '/usr/bin/pngquant'); + + // MozJpeg parameters + $parameters->set('liip_imagine.mozjpeg.binary', '/opt/mozjpeg/bin/cjpeg'); + + // cwebp parameters + $parameters->set('liip_imagine.cwebp.binary', '/usr/bin/cwebp'); + $parameters->set('liip_imagine.cwebp.tempDir', null); + $parameters->set('liip_imagine.cwebp.q', 75); + $parameters->set('liip_imagine.cwebp.alphaQ', 100); + $parameters->set('liip_imagine.cwebp.m', 4); + $parameters->set('liip_imagine.cwebp.alphaFilter', 'fast'); + $parameters->set('liip_imagine.cwebp.alphaMethod', 1); + $parameters->set('liip_imagine.cwebp.exact', false); + $parameters->set('liip_imagine.cwebp.metadata', ['none']); + + // Factory services + $services->set('liip_imagine.factory.config.filter.argument.point', PointFactory::class); + + $services->set('liip_imagine.factory.config.filter.argument.size', SizeFactory::class); + + $services->set('liip_imagine.factory.config.stack', StackFactory::class); + + $services->set('liip_imagine.factory.config.filter.auto_rotate', AutoRotateFactory::class); + + $services->set('liip_imagine.factory.config.filter.background', BackgroundFactory::class) + ->args([service('liip_imagine.factory.config.filter.argument.size')]); + + $services->set('liip_imagine.factory.config.filter.crop', CropFactory::class) + ->args([ + service('liip_imagine.factory.config.filter.argument.size'), + service('liip_imagine.factory.config.filter.argument.point'), + ]); + + $services->set('liip_imagine.factory.config.filter.downscale', DownscaleFactory::class) + ->args([service('liip_imagine.factory.config.filter.argument.size')]); + + $services->set('liip_imagine.factory.config.filter.flip', FlipFactory::class); + + $services->set('liip_imagine.factory.config.filter.grayscale', GrayscaleFactory::class); + + $services->set('liip_imagine.factory.config.filter.interlace', InterlaceFactory::class); + + $services->set('liip_imagine.factory.config.filter.paste', PasteFactory::class) + ->args([service('liip_imagine.factory.config.filter.argument.point')]); + + $services->set('liip_imagine.factory.config.filter.relative_resize', RelativeResizeFactory::class); + + $services->set('liip_imagine.factory.config.filter.resize', ResizeFactory::class) + ->args([service('liip_imagine.factory.config.filter.argument.size')]); + + $services->set('liip_imagine.factory.config.filter.rotate', RotateFactory::class); + + $services->set('liip_imagine.factory.config.filter.scale', ScaleFactory::class) + ->args([service('liip_imagine.factory.config.filter.argument.size')]); + + $services->set('liip_imagine.factory.config.filter.strip', StripFactory::class); + + $services->set('liip_imagine.factory.config.filter.thumbnail', ThumbnailFactory::class) + ->args([service('liip_imagine.factory.config.filter.argument.size')]); + + $services->set('liip_imagine.factory.config.filter.upscale', UpscaleFactory::class) + ->args([service('liip_imagine.factory.config.filter.argument.size')]); + + $services->set('liip_imagine.factory.config.filter.watermark', WatermarkFactory::class); + + // Config services + $services->set('liip_imagine.config.filter_factory_collection', FilterFactoryCollection::class) + ->args([ + service('liip_imagine.factory.config.filter.auto_rotate'), + service('liip_imagine.factory.config.filter.background'), + service('liip_imagine.factory.config.filter.crop'), + service('liip_imagine.factory.config.filter.downscale'), + service('liip_imagine.factory.config.filter.flip'), + service('liip_imagine.factory.config.filter.grayscale'), + service('liip_imagine.factory.config.filter.interlace'), + service('liip_imagine.factory.config.filter.paste'), + service('liip_imagine.factory.config.filter.relative_resize'), + service('liip_imagine.factory.config.filter.resize'), + service('liip_imagine.factory.config.filter.rotate'), + service('liip_imagine.factory.config.filter.scale'), + service('liip_imagine.factory.config.filter.strip'), + service('liip_imagine.factory.config.filter.thumbnail'), + service('liip_imagine.factory.config.filter.upscale'), + service('liip_imagine.factory.config.filter.watermark'), + ]); + + $services->alias(FilterFactoryCollection::class, 'liip_imagine.config.filter_factory_collection'); + + $services->set('liip_imagine.config.stack_builder', StackBuilder::class) + ->args([ + service('liip_imagine.factory.config.stack'), + service('liip_imagine.config.filter_factory_collection'), + ]); + + $services->alias(StackBuilder::class, 'liip_imagine.config.stack_builder'); + + $services->set('liip_imagine.config.stack_collection', StackCollection::class) + ->public() + ->args([ + service('liip_imagine.config.stack_builder'), + '%liip_imagine.filter_sets%', + ]); + + $services->alias(StackCollection::class, 'liip_imagine.config.stack_collection'); + + // Utility services + $services->set('liip_imagine.filter.manager', FilterManager::class) + ->public() + ->args([ + service('liip_imagine.filter.configuration'), + service('liip_imagine'), + service('liip_imagine.binary.mime_type_guesser'), + ]); + + $services->alias(FilterManager::class, 'liip_imagine.filter.manager'); + + $services->set('liip_imagine.data.manager', DataManager::class) + ->public() + ->args([ + service('liip_imagine.binary.mime_type_guesser'), + service('liip_imagine.extension_guesser'), + service('liip_imagine.filter.configuration'), + '%liip_imagine.binary.loader.default%', + '%liip_imagine.default_image%', + ]); + + $services->alias(DataManager::class, 'liip_imagine.data.manager'); + + $services->set('liip_imagine.cache.manager', CacheManager::class) + ->public() + ->args([ + service('liip_imagine.filter.configuration'), + service('router'), + service('liip_imagine.cache.signer'), + service('event_dispatcher'), + '%liip_imagine.cache.resolver.default%', + '%liip_imagine.webp.generate%', + ]); + + $services->alias(CacheManager::class, 'liip_imagine.cache.manager'); + + $services->set('liip_imagine.filter.configuration', FilterConfiguration::class) + ->args(['%liip_imagine.filter_sets%']); + + $services->set('liip_imagine.service.filter', FilterService::class) + ->args([ + service('liip_imagine.data.manager'), + service('liip_imagine.filter.manager'), + service('liip_imagine.cache.manager'), + '%liip_imagine.webp.generate%', + '%liip_imagine.webp.options%', + service('logger')->ignoreOnInvalid(), + ]); + + $services->alias(FilterService::class, 'liip_imagine.service.filter'); + + // Config + $services->set('liip_imagine.controller.config', ControllerConfig::class) + ->private() + ->args(['']); + + // Controller + $services->set(ImagineController::class) + ->public() + ->args([ + service('liip_imagine.service.filter'), + service('liip_imagine.data.manager'), + service('liip_imagine.cache.signer'), + service('liip_imagine.controller.config'), + ]); + + $services->alias('liip_imagine.controller', ImagineController::class) + ->public(); + + $services->set('liip_imagine.meta_data.reader', ExifMetadataReader::class) + ->private(); + + // ImagineInterface instances + $services->alias('liip_imagine', 'liip_imagine.gd'); + + $services->alias(ImagineInterface::class, 'liip_imagine'); + + $services->set('liip_imagine.gd', Imagine::class) + ->private() + ->call('setMetadataReader', [service('liip_imagine.meta_data.reader')]); + + $services->set('liip_imagine.imagick', \Imagine\Imagick\Imagine::class) + ->private() + ->call('setMetadataReader', [service('liip_imagine.meta_data.reader')]); + + $services->set('liip_imagine.gmagick', \Imagine\Gmagick\Imagine::class) + ->private() + ->call('setMetadataReader', [service('liip_imagine.meta_data.reader')]); + + // Filter loaders + $services->set('liip_imagine.filter.loader.relative_resize', RelativeResizeFilterLoader::class) + ->tag('liip_imagine.filter.loader', ['loader' => 'relative_resize']); + + $services->set('liip_imagine.filter.loader.resize', ResizeFilterLoader::class) + ->tag('liip_imagine.filter.loader', ['loader' => 'resize']); + + $services->set('liip_imagine.filter.loader.thumbnail', ThumbnailFilterLoader::class) + ->tag('liip_imagine.filter.loader', ['loader' => 'thumbnail']); + + $services->set('liip_imagine.filter.loader.crop', CropFilterLoader::class) + ->tag('liip_imagine.filter.loader', ['loader' => 'crop']); + + $services->set('liip_imagine.filter.loader.grayscale', GrayscaleFilterLoader::class) + ->public() + ->tag('liip_imagine.filter.loader', ['loader' => 'grayscale']); + + $services->set('liip_imagine.filter.loader.paste_image', PasteFilterLoader::class) + ->args([ + service('liip_imagine'), + '%kernel.project_dir%', + ]) + ->tag('liip_imagine.filter.loader', ['loader' => 'paste_image']); + + // not officially deprecated because still injected and appears "used" + $services->set('liip_imagine.filter.loader.paste', PasteFilterLoader::class) + ->args([ + service('liip_imagine'), + '%kernel.root_dir%', + ]) + ->tag('liip_imagine.filter.loader', ['loader' => 'paste']); + + // not officially deprecated because still injected and appears "used" + $services->set('liip_imagine.filter.loader.watermark', WatermarkFilterLoader::class) + ->args([ + service('liip_imagine'), + '%kernel.root_dir%', + ]) + ->tag('liip_imagine.filter.loader', ['loader' => 'watermark']); + + $services->set('liip_imagine.filter.loader.watermark_image', WatermarkFilterLoader::class) + ->args([ + service('liip_imagine'), + '%kernel.project_dir%', + ]) + ->tag('liip_imagine.filter.loader', ['loader' => 'watermark_image']); + + $services->set('liip_imagine.filter.loader.background', BackgroundFilterLoader::class) + ->args([service('liip_imagine')]) + ->tag('liip_imagine.filter.loader', ['loader' => 'background']); + + $services->set('liip_imagine.filter.loader.strip', StripFilterLoader::class) + ->tag('liip_imagine.filter.loader', ['loader' => 'strip']); + + $services->set('liip_imagine.filter.loader.scale', ScaleFilterLoader::class) + ->tag('liip_imagine.filter.loader', ['loader' => 'scale']); + + $services->set('liip_imagine.filter.loader.upscale', UpscaleFilterLoader::class) + ->tag('liip_imagine.filter.loader', ['loader' => 'upscale']); + + $services->set('liip_imagine.filter.loader.downscale', DownscaleFilterLoader::class) + ->public() + ->tag('liip_imagine.filter.loader', ['loader' => 'downscale']); + + $services->set('liip_imagine.filter.loader.auto_rotate', AutoRotateFilterLoader::class) + ->tag('liip_imagine.filter.loader', ['loader' => 'auto_rotate']); + + $services->set('liip_imagine.filter.loader.rotate', RotateFilterLoader::class) + ->public() + ->tag('liip_imagine.filter.loader', ['loader' => 'rotate']); + + $services->set('liip_imagine.filter.loader.flip', FlipFilterLoader::class) + ->public() + ->tag('liip_imagine.filter.loader', ['loader' => 'flip']); + + $services->set('liip_imagine.filter.loader.interlace', InterlaceFilterLoader::class) + ->public() + ->tag('liip_imagine.filter.loader', ['loader' => 'interlace']); + + $services->set('liip_imagine.filter.loader.resample', ResampleFilterLoader::class) + ->public() + ->args([service('liip_imagine')]) + ->tag('liip_imagine.filter.loader', ['loader' => 'resample']); + + $services->set('liip_imagine.filter.loader.fixed', FixedFilterLoader::class) + ->public() + ->tag('liip_imagine.filter.loader', ['loader' => 'fixed']); + + // Data loaders + $services->set('liip_imagine.binary.loader.prototype.filesystem', FileSystemLoader::class) + ->args([ + service('liip_imagine.mime_type_guesser'), + service('liip_imagine.extension_guesser'), + '', // will be injected by FileSystemLoaderFactory + ]); + + $services->set('liip_imagine.binary.loader.prototype.stream', StreamLoader::class) + ->args([ + '', // will be injected by StreamLoaderFactory + '', // will be injected by StreamLoaderFactory + ]); + + $services->set('liip_imagine.binary.loader.prototype.flysystem', FlysystemLoader::class) + ->abstract() + ->args([ + service('liip_imagine.extension_guesser'), + '', // will be injected by FlysystemLoaderFactory + ]); + + $services->set('liip_imagine.binary.loader.prototype.flysystem2', FlysystemV2Loader::class) + ->abstract() + ->args([ + service('liip_imagine.extension_guesser'), + '', // will be injected by FlysystemV2LoaderFactory + ]); + + $services->set('liip_imagine.binary.loader.prototype.chain', ChainLoader::class) + ->abstract() + ->args(['']); // will be injected by ChainLoaderFactory + + // Data loader locators + $services->set('liip_imagine.binary.locator.filesystem', FileSystemLocator::class) + ->share(false) + ->private() + ->args([ + '', // will be injected by FilesystemLoaderFactory + '', // will be injected by FilesystemLoaderFactory + ]) + ->tag('liip_imagine.binary.locator', ['shared' => false]); + + $services->set('liip_imagine.binary.locator.filesystem_insecure', FileSystemInsecureLocator::class) + ->share(false) + ->private() + ->args([ + '', // will be injected by FilesystemLoaderFactory + '', // will be injected by FilesystemLoaderFactory + ]) + ->tag('liip_imagine.binary.locator', ['shared' => false]); + + // Cache resolver + $services->set('liip_imagine.cache.resolver.prototype.web_path', WebPathResolver::class) + ->public() + ->abstract() + ->args([ + service('filesystem'), + service('router.request_context'), + '', // will be injected by WebPathResolverFactory + '', // will be injected by WebPathResolverFactory + ]); + + $services->set('liip_imagine.cache.resolver.prototype.aws_s3', AwsS3Resolver::class) + ->public() + ->abstract() + ->args([ + '', // will be injected by AwsS3ResolverFactory + '', // will be injected by AwsS3ResolverFactory + '', // will be injected by AwsS3ResolverFactory + '', // will be injected by AwsS3ResolverFactory + '', // will be injected by AwsS3ResolverFactory + ]); + + $services->set('liip_imagine.cache.resolver.prototype.cache', CacheResolver::class) + ->public() + ->abstract() + ->args([ + // args will be injected by a ResolverFactory + '', + '', + ]); + + $services->set('liip_imagine.cache.resolver.prototype.flysystem', FlysystemResolver::class) + ->public() + ->abstract() + ->args([ + '', // will be injected by a ResolverFactory + service('router.request_context'), + '', // will be injected by a ResolverFactory + '', // will be injected by a ResolverFactory + '', // will be injected by a ResolverFactory + ]); + + $services->set('liip_imagine.cache.resolver.prototype.flysystem2', FlysystemV2Resolver::class) + ->public() + ->abstract() + ->args([ + '', + service('router.request_context'), + '', + '', + '', + ]); + + $services->set('liip_imagine.cache.resolver.prototype.proxy', ProxyResolver::class) + ->public() + ->abstract() + ->args([ + '', // will be injected by AwsS3ResolverFactory + '', // will be injected by AwsS3ResolverFactory + ]); + + $services->set('liip_imagine.cache.resolver.prototype.psr_cache', PsrCacheResolver::class) + ->public() + ->abstract() + ->args([ + '', // will be injected by a ResolverFactory + '', // will be injected by a ResolverFactory + ]); + + $services->set('liip_imagine.cache.resolver.no_cache_web_path', NoCacheWebPathResolver::class) + ->public() + ->args([service('router.request_context')]) + ->tag('liip_imagine.cache.resolver', ['resolver' => 'no_cache']); + + // Form types + $services->set('liip_imagine.form.type.image', ImageType::class) + ->tag('form.type', ['alias' => 'liip_imagine_image']); + + // Guessers + $services->set('liip_imagine.mime_type_guesser', 'Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface') + ->factory(['Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser', 'getInstance']); + + $services->set('liip_imagine.extension_guesser', 'Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesserInterface') + ->factory(['Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser', 'getInstance']); + + $services->set('liip_imagine.binary.mime_type_guesser', SimpleMimeTypeGuesser::class) + ->args([service('liip_imagine.mime_type_guesser')]); + + $services->set('liip_imagine.cache.signer', Signer::class) + ->public() + ->args(['%kernel.secret%']); + + // Post processors + $services->set('liip_imagine.filter.post_processor.jpegoptim', JpegOptimPostProcessor::class) + ->args([ + '%liip_imagine.jpegoptim.binary%', + '%liip_imagine.jpegoptim.stripAll%', + '%liip_imagine.jpegoptim.max%', + '%liip_imagine.jpegoptim.progressive%', + '%liip_imagine.jpegoptim.tempDir%', + ]) + ->tag('liip_imagine.filter.post_processor', ['post_processor' => 'jpegoptim']); + + $services->set('liip_imagine.filter.post_processor.optipng', OptiPngPostProcessor::class) + ->args([ + '%liip_imagine.optipng.binary%', + '%liip_imagine.optipng.level%', + '%liip_imagine.optipng.stripAll%', + '%liip_imagine.optipng.tempDir%', + ]) + ->tag('liip_imagine.filter.post_processor', ['post_processor' => 'optipng']); + + $services->set('liip_imagine.filter.post_processor.pngquant', PngquantPostProcessor::class) + ->args(['%liip_imagine.pngquant.binary%']) + ->tag('liip_imagine.filter.post_processor', ['post_processor' => 'pngquant']); + + $services->set('liip_imagine.filter.post_processor.mozjpeg', MozJpegPostProcessor::class) + ->args(['%liip_imagine.mozjpeg.binary%']) + ->tag('liip_imagine.filter.post_processor', ['post_processor' => 'mozjpeg']); + + $services->set('liip_imagine.filter.post_processor.cwebp', CwebpPostProcessor::class) + ->args([ + '%liip_imagine.cwebp.binary%', + '%liip_imagine.cwebp.tempDir%', + '%liip_imagine.cwebp.q%', + '%liip_imagine.cwebp.alphaQ%', + '%liip_imagine.cwebp.m%', + '%liip_imagine.cwebp.alphaFilter%', + '%liip_imagine.cwebp.alphaMethod%', + '%liip_imagine.cwebp.exact%', + '%liip_imagine.cwebp.metadata%', + ]) + ->tag('liip_imagine.filter.post_processor', ['post_processor' => 'cwebp']); +}; diff --git a/Resources/config/imagine.xml b/Resources/config/imagine.xml deleted file mode 100644 index 0d78911f8..000000000 --- a/Resources/config/imagine.xml +++ /dev/null @@ -1,460 +0,0 @@ - - - - - - - - /usr/bin/jpegoptim - true - null - true - null - - - - /usr/bin/optipng - 7 - true - null - - - - /usr/bin/pngquant - - - - /opt/mozjpeg/bin/cjpeg - - - - /usr/bin/cwebp - null - 75 - 100 - 4 - fast - 1 - false - - none - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - %liip_imagine.filter_sets% - - - - - - - - - - - - - - - - - %liip_imagine.binary.loader.default% - %liip_imagine.default_image% - - - - - - - - - %liip_imagine.cache.resolver.default% - %liip_imagine.webp.generate% - - - - - %liip_imagine.filter_sets% - - - - - - - %liip_imagine.webp.generate% - %liip_imagine.webp.options% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - %kernel.project_dir% - - - - - - - - %kernel.root_dir% - - - - - %kernel.root_dir% - - - - - - - %kernel.project_dir% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - %kernel.secret% - - - - - - %liip_imagine.jpegoptim.binary% - %liip_imagine.jpegoptim.stripAll% - %liip_imagine.jpegoptim.max% - %liip_imagine.jpegoptim.progressive% - %liip_imagine.jpegoptim.tempDir% - - - - - %liip_imagine.optipng.binary% - %liip_imagine.optipng.level% - %liip_imagine.optipng.stripAll% - %liip_imagine.optipng.tempDir% - - - - - %liip_imagine.pngquant.binary% - - - - - %liip_imagine.mozjpeg.binary% - - - - - %liip_imagine.cwebp.binary% - %liip_imagine.cwebp.tempDir% - %liip_imagine.cwebp.q% - %liip_imagine.cwebp.alphaQ% - %liip_imagine.cwebp.m% - %liip_imagine.cwebp.alphaFilter% - %liip_imagine.cwebp.alphaMethod% - %liip_imagine.cwebp.exact% - %liip_imagine.cwebp.metadata% - - - - - From ea394ecfb6eba485f9515d2ad2f307721766e3f6 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Sun, 26 Oct 2025 19:25:18 +0100 Subject: [PATCH 16/27] Migrate remaining xml config files to php --- DependencyInjection/LiipImagineExtension.php | 22 ++++++------- Resources/config/imagine_twig_mode_lazy.php | 33 +++++++++++++++++++ Resources/config/imagine_twig_mode_lazy.xml | 21 ------------ Resources/config/imagine_twig_mode_legacy.php | 24 ++++++++++++++ Resources/config/imagine_twig_mode_legacy.xml | 16 --------- Resources/config/imagine_vips.php | 22 +++++++++++++ Resources/config/imagine_vips.xml | 15 --------- 7 files changed, 89 insertions(+), 64 deletions(-) create mode 100644 Resources/config/imagine_twig_mode_lazy.php delete mode 100644 Resources/config/imagine_twig_mode_lazy.xml create mode 100644 Resources/config/imagine_twig_mode_legacy.php delete mode 100644 Resources/config/imagine_twig_mode_legacy.xml create mode 100644 Resources/config/imagine_vips.php delete mode 100644 Resources/config/imagine_vips.xml diff --git a/DependencyInjection/LiipImagineExtension.php b/DependencyInjection/LiipImagineExtension.php index 73a8ebfe2..461beb1ca 100644 --- a/DependencyInjection/LiipImagineExtension.php +++ b/DependencyInjection/LiipImagineExtension.php @@ -28,7 +28,6 @@ use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Mime\MimeTypeGuesserInterface; use Symfony\Component\Mime\MimeTypes; @@ -83,26 +82,25 @@ public function load(array $configs, ContainerBuilder $container): void $this->loadResolvers($config['resolvers'], $container); $this->loadLoaders($config['loaders'], $container); - $phpLoader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); - $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); - $phpLoader->load('imagine.php'); + $loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('imagine.php'); if ('none' !== $config['twig']['mode']) { $this->loadTwig($config['twig'], $loader, $container); } - $phpLoader->load('commands.php'); + $loader->load('commands.php'); if ($this->isConfigEnabled($container, $config['messenger'])) { - $this->registerMessengerConfiguration($phpLoader); + $this->registerMessengerConfiguration($loader); } if ($config['enqueue']) { - $phpLoader->load('enqueue.php'); + $loader->load('enqueue.php'); } if ($config['templating']) { - $phpLoader->load('templating.php'); + $loader->load('templating.php'); } $driver = $config['driver']; @@ -113,7 +111,7 @@ public function load(array $configs, ContainerBuilder $container): void throw new \RuntimeException("Unable to use 'vips' driver without '{$vipsImagineClass}' class."); } - $loader->load('imagine_vips.xml'); + $loader->load('imagine_vips.php'); } $container->setParameter('liip_imagine.driver_service', "liip_imagine.{$driver}"); @@ -194,16 +192,16 @@ private function registerMessengerConfiguration(LoaderInterface $loader): void $loader->load('messenger.php'); } - private function loadTwig(array $config, XmlFileLoader $loader, ContainerBuilder $container): void + private function loadTwig(array $config, LoaderInterface $loader, ContainerBuilder $container): void { if ('legacy' === $config['mode']) { - $loader->load('imagine_twig_mode_legacy.xml'); + $loader->load('imagine_twig_mode_legacy.php'); return; } if ('lazy' === $config['mode']) { - $loader->load('imagine_twig_mode_lazy.xml'); + $loader->load('imagine_twig_mode_lazy.php'); if (\array_key_exists('assets_version', $config) && null !== $config['assets_version']) { $runtime = $container->getDefinition('liip_imagine.templating.filter_runtime'); $runtime->setArgument(1, $config['assets_version']); diff --git a/Resources/config/imagine_twig_mode_lazy.php b/Resources/config/imagine_twig_mode_lazy.php new file mode 100644 index 000000000..eb5718853 --- /dev/null +++ b/Resources/config/imagine_twig_mode_lazy.php @@ -0,0 +1,33 @@ +services(); + + // Templating helpers and extensions + $services->set('liip_imagine.templating.filter_extension', LazyFilterExtension::class) + ->private() + ->tag('twig.extension'); + + $services->set('liip_imagine.templating.filter_runtime', LazyFilterRuntime::class) + ->private() + ->args([ + service('liip_imagine.cache.manager'), + null, + null, + ]) + ->tag('twig.runtime'); +}; diff --git a/Resources/config/imagine_twig_mode_lazy.xml b/Resources/config/imagine_twig_mode_lazy.xml deleted file mode 100644 index ac9ec6f19..000000000 --- a/Resources/config/imagine_twig_mode_lazy.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - null - null - - - - diff --git a/Resources/config/imagine_twig_mode_legacy.php b/Resources/config/imagine_twig_mode_legacy.php new file mode 100644 index 000000000..7e86ebece --- /dev/null +++ b/Resources/config/imagine_twig_mode_legacy.php @@ -0,0 +1,24 @@ +services(); + + // Templating helpers and extensions + $services->set('liip_imagine.templating.filter_extension', FilterExtension::class) + ->private() + ->args([service('liip_imagine.cache.manager')]) + ->tag('twig.extension'); +}; diff --git a/Resources/config/imagine_twig_mode_legacy.xml b/Resources/config/imagine_twig_mode_legacy.xml deleted file mode 100644 index dc5be5e6d..000000000 --- a/Resources/config/imagine_twig_mode_legacy.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - diff --git a/Resources/config/imagine_vips.php b/Resources/config/imagine_vips.php new file mode 100644 index 000000000..c9b874430 --- /dev/null +++ b/Resources/config/imagine_vips.php @@ -0,0 +1,22 @@ +services(); + + $services->set('liip_imagine.vips', Imagine::class) + ->private() + ->call('setMetadataReader', [service('liip_imagine.meta_data.reader')]); +}; diff --git a/Resources/config/imagine_vips.xml b/Resources/config/imagine_vips.xml deleted file mode 100644 index de460af51..000000000 --- a/Resources/config/imagine_vips.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - From 809ee3d5e8deaea31f5eeb073a5d70ca3f6aa54d Mon Sep 17 00:00:00 2001 From: David Maicher Date: Wed, 29 Oct 2025 18:58:22 +0100 Subject: [PATCH 17/27] Allow Symfony 8 --- .github/workflows/phpunit.yml | 27 ++++++++++++++++----------- composer.json | 32 ++++++++++++++++---------------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 06910c7a5..4aacf82c6 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -42,10 +42,16 @@ jobs: symfony: '6.4.*' stability: 'stable' - # Test Symfony 7.3 dev version - - php: '8.2' + # Test Symfony 7.4 dev version + - php: '8.4' + dependencies: highest + symfony: '7.4.*' + stability: 'dev' + + # Test Symfony 8.0 dev version + - php: '8.4' dependencies: highest - symfony: '7.3.*' + symfony: '8.0.*' stability: 'dev' steps: - name: Checkout @@ -62,21 +68,18 @@ jobs: coverage: ${{ steps.coverage.outputs.driver }} extensions: gd, imagick - - name: Require Symfony version - if: matrix.symfony != '*' + - name: Install symfony/flex run: | composer global config --no-plugins allow-plugins.symfony/flex true composer global require --no-interaction --no-progress symfony/flex - composer config extra.symfony.require ${{ matrix.symfony }} - - - name: Remove non-compatible dependencies with Symfony 7 - if: matrix.symfony == '7.0.*' - run: | - composer remove enqueue/enqueue-bundle symfony/templating --dev --no-update - name: Set minimum-stability run: composer config minimum-stability ${{ matrix.stability }} + - name: Remove enqueue/enqueue-bundle for Symfony 8 + if: matrix.symfony == '8.0.*' + run: composer remove --no-update enqueue/enqueue-bundle --dev + # Latest enqueue install on PHP 7.4 but uses PHP 8 features - name: Pin enqueue/enqueue on PHP 7.4 if: ${{ matrix.php == '7.4' }} @@ -86,6 +89,8 @@ jobs: uses: ramsey/composer-install@v2 with: dependency-versions: ${{ matrix.dependencies }} + env: + SYMFONY_REQUIRE: "${{ matrix.symfony }}" - name: Cache PHPUnit uses: actions/cache@v3 diff --git a/composer.json b/composer.json index 6b911b558..ca6f5c739 100644 --- a/composer.json +++ b/composer.json @@ -21,14 +21,14 @@ "php": "^7.2|^8.0", "ext-mbstring": "*", "imagine/imagine": "^1.3.2", - "symfony/dependency-injection": "^5.4|^6.4|^7.4", + "symfony/dependency-injection": "^5.4|^6.4|^7.4|^8.0", "symfony/deprecation-contracts": "^2.5 || ^3", - "symfony/filesystem": "^5.4|^6.4|^7.3", - "symfony/finder": "^5.4|^6.4|^7.3", - "symfony/framework-bundle": "^5.4|^6.4|^7.3", - "symfony/mime": "^5.4|^6.4|^7.3", - "symfony/options-resolver": "^5.4|^6.4|^7.3", - "symfony/process": "^5.4|^6.4|^7.3", + "symfony/filesystem": "^5.4|^6.4|^7.3|^8.0", + "symfony/finder": "^5.4|^6.4|^7.3|^8.0", + "symfony/framework-bundle": "^5.4|^6.4|^7.3|^8.0", + "symfony/mime": "^5.4|^6.4|^7.3|^8.0", + "symfony/options-resolver": "^5.4|^6.4|^7.3|^8.0", + "symfony/process": "^5.4|^6.4|^7.3|^8.0", "twig/twig": "^1.44|^2.9|^3.0" }, "require-dev": { @@ -42,16 +42,16 @@ "phpstan/phpstan": "^1.10.0", "psr/cache": "^1.0|^2.0|^3.0", "psr/log": "^1.0", - "symfony/asset": "^5.4|^6.4|^7.3", - "symfony/browser-kit": "^5.4|^6.4|^7.3", - "symfony/cache": "^5.4|^6.4|^7.3", - "symfony/console": "^5.4|^6.4|^7.3", - "symfony/form": "^5.4|^6.4|^7.3", - "symfony/messenger": "^5.4|^6.4|^7.3", + "symfony/asset": "^5.4|^6.4|^7.3|^8.0", + "symfony/browser-kit": "^5.4|^6.4|^7.3|^8.0", + "symfony/cache": "^5.4|^6.4|^7.3|^8.0", + "symfony/console": "^5.4|^6.4|^7.3|^8.0", + "symfony/form": "^5.4|^6.4|^7.3|^8.0", + "symfony/messenger": "^5.4|^6.4|^7.3|^8.0", "symfony/phpunit-bridge": "^7.3", - "symfony/templating": "^5.4|^6.4|^7.3", - "symfony/validator": "^5.4|^6.4|^7.3", - "symfony/yaml": "^5.4|^6.4|^7.3" + "symfony/templating": "^5.4|^6.4|^7.3|^8.0", + "symfony/validator": "^5.4|^6.4|^7.3|^8.0", + "symfony/yaml": "^5.4|^6.4|^7.3|^8.0" }, "suggest": { "ext-exif": "required to read EXIF metadata from images", From 3c197bce3884822c7f198315eb4807c617f8aa8a Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 24 Nov 2025 21:47:37 +0100 Subject: [PATCH 18/27] test with php 8.5 --- .github/workflows/phpunit.yml | 16 +++++++-------- CHANGELOG.md | 6 ++++-- Imagine/Data/DataManager.php | 2 +- Tests/AbstractTest.php | 5 ++++- .../Binary/Locator/FileSystemLocatorTest.php | 5 ++++- .../MetadataReaderCompilerPassTest.php | 5 ++++- Tests/Functional/AbstractWebTestCase.php | 5 ++++- .../Controller/ImagineControllerTest.php | 5 ++++- .../Cache/Resolver/WebPathResolverTest.php | 20 +++++++++++++++---- Tests/Imagine/Data/DataManagerTest.php | 3 ++- .../AbstractPostProcessorTestCase.php | 10 ++++++++-- phpunit.xml.dist | 2 ++ 12 files changed, 61 insertions(+), 23 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 4aacf82c6..f6067a22f 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] dependencies: [highest] symfony: ['*'] stability: ['stable'] @@ -26,7 +26,7 @@ jobs: stability: 'stable' # Minimum supported dependencies with the latest supported PHP version - - php: '8.4' + - php: '8.5' dependencies: lowest symfony: '*' stability: 'stable' @@ -42,17 +42,17 @@ jobs: symfony: '6.4.*' stability: 'stable' - # Test Symfony 7.4 dev version - - php: '8.4' + # Test Symfony 7.4 + - php: '8.5' dependencies: highest symfony: '7.4.*' - stability: 'dev' + stability: 'stable' - # Test Symfony 8.0 dev version - - php: '8.4' + # Test Symfony 8.0 + - php: '8.5' dependencies: highest symfony: '8.0.*' - stability: 'dev' + stability: 'stable' steps: - name: Checkout uses: actions/checkout@v5 diff --git a/CHANGELOG.md b/CHANGELOG.md index cfa902bde..44abd57b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,13 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic # 2.x -## 2.16.0 (unreleased) +## [2.16.0](https://github.com/liip/LiipImagineBundle/tree/2.16.0) +- Compatible with Symfony 8 ([dmaicher](https://github.com/liip/LiipImagineBundle/pull/1642)) (including a bunch of PRs to change all XML configuration to PHP configuration) +- Test with PHP 8.5 and fix deprecations([dbu](https://github.com/liip/LiipImagineBundle/pull/1644)) - Drop support for unmaintained Symfony versions ([dmaicher](https://github.com/liip/LiipImagineBundle/pull/1639)) -## [2.15.0](https://github.com/liip/LiipImagineBundle/tree/2.14.0) +## [2.15.0](https://github.com/liip/LiipImagineBundle/tree/2.15.0) - Refactored `Request::get()` to `Request::query::get()` to avoid deprecation with Symfony 7.4 ([dmaicher](https://github.com/liip/LiipImagineBundle/pull/1636)) diff --git a/Imagine/Data/DataManager.php b/Imagine/Data/DataManager.php index 0f4ff7273..cb00a0970 100644 --- a/Imagine/Data/DataManager.php +++ b/Imagine/Data/DataManager.php @@ -105,7 +105,7 @@ public function getLoader($filter) $loaderName = empty($config['data_loader']) ? $this->defaultLoader : $config['data_loader']; - if (!isset($this->loaders[$loaderName])) { + if (null === $loaderName || !\array_key_exists($loaderName, $this->loaders)) { throw new \InvalidArgumentException(\sprintf('Could not find data loader "%s" for "%s" filter type', $loaderName, $filter)); } diff --git a/Tests/AbstractTest.php b/Tests/AbstractTest.php index 4a981bc6d..49b38618e 100644 --- a/Tests/AbstractTest.php +++ b/Tests/AbstractTest.php @@ -293,7 +293,10 @@ protected function getVisibilityRestrictedMethod($object, string $name): \Reflec $r = new \ReflectionObject($object); $m = $r->getMethod($name); - $m->setAccessible(true); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $m->setAccessible(true); + } return $m; } diff --git a/Tests/Binary/Locator/FileSystemLocatorTest.php b/Tests/Binary/Locator/FileSystemLocatorTest.php index 48e6b7dbf..ba56e7b17 100644 --- a/Tests/Binary/Locator/FileSystemLocatorTest.php +++ b/Tests/Binary/Locator/FileSystemLocatorTest.php @@ -23,7 +23,10 @@ public function testAllowInvalidPaths(): void { $locator = new FileSystemLocator(['/does/not/exist/foo', '/does/not/exist/bar', $temp = sys_get_temp_dir()], true); $roots = (new \ReflectionObject($locator))->getProperty('roots'); - $roots->setAccessible(true); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $roots->setAccessible(true); + } $array = [ '', '', diff --git a/Tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php b/Tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php index 9f4e86cec..b3cbdfa24 100644 --- a/Tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php +++ b/Tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php @@ -76,7 +76,10 @@ public function testDoesNotOverrideCustomReaderWhenExifNotAvailable(): void private static function getVisibilityRestrictedStaticProperty(\ReflectionClass $r, string $p): string { $property = $r->getProperty($p); - $property->setAccessible(true); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $property->setAccessible(true); + } return $property->getValue(); } diff --git a/Tests/Functional/AbstractWebTestCase.php b/Tests/Functional/AbstractWebTestCase.php index a598e9e5f..acf5f16be 100644 --- a/Tests/Functional/AbstractWebTestCase.php +++ b/Tests/Functional/AbstractWebTestCase.php @@ -52,7 +52,10 @@ protected function getPrivateProperty($object, string $name) $r = new \ReflectionObject($object); $p = $r->getProperty($name); - $p->setAccessible(true); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $p->setAccessible(true); + } return $p->getValue($object); } diff --git a/Tests/Functional/Controller/ImagineControllerTest.php b/Tests/Functional/Controller/ImagineControllerTest.php index bb08d6714..8ca657c25 100644 --- a/Tests/Functional/Controller/ImagineControllerTest.php +++ b/Tests/Functional/Controller/ImagineControllerTest.php @@ -41,7 +41,10 @@ protected function setUp(): void if ($this->webp_generate) { $filterService = $this->getService('test.liip_imagine.service.filter'); $webpGenerate = new \ReflectionProperty($filterService, 'webpGenerate'); - $webpGenerate->setAccessible(true); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $webpGenerate->setAccessible(true); + } $webpGenerate->setValue($filterService, true); } } diff --git a/Tests/Imagine/Cache/Resolver/WebPathResolverTest.php b/Tests/Imagine/Cache/Resolver/WebPathResolverTest.php index 798e140c3..24106133b 100644 --- a/Tests/Imagine/Cache/Resolver/WebPathResolverTest.php +++ b/Tests/Imagine/Cache/Resolver/WebPathResolverTest.php @@ -462,7 +462,10 @@ public function testShouldRemoveDoubleSlashInUrl(): void $rc = new \ReflectionClass($resolver); $method = $rc->getMethod('getFileUrl'); - $method->setAccessible(true); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $method->setAccessible(true); + } $result = $method->invokeArgs($resolver, ['/cats.jpg', 'some_filter']); @@ -480,7 +483,10 @@ public function testShouldSanitizeSeparatorBetweenSchemeAndAuthorityInUrl(): voi $rc = new \ReflectionClass($resolver); $method = $rc->getMethod('getFileUrl'); - $method->setAccessible(true); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $method->setAccessible(true); + } $result = $method->invokeArgs($resolver, ['https://some.meme.com/cute/cats.jpg', 'some_filter']); @@ -494,9 +500,15 @@ public static function assertAttributeSame($expected, string $actualAttributeNam { $reflector = new \ReflectionObject($actualClassOrObject); $attribute = $reflector->getProperty($actualAttributeName); - $attribute->setAccessible(true); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $attribute->setAccessible(true); + } $actual = $attribute->getValue($actualClassOrObject); - $attribute->setAccessible(false); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $attribute->setAccessible(false); + } self::assertSame($expected, $actual, $message); } diff --git a/Tests/Imagine/Data/DataManagerTest.php b/Tests/Imagine/Data/DataManagerTest.php index d92494b6f..27b2b3fcd 100644 --- a/Tests/Imagine/Data/DataManagerTest.php +++ b/Tests/Imagine/Data/DataManagerTest.php @@ -11,6 +11,7 @@ namespace Liip\ImagineBundle\Tests\Imagine\Data; +use Liip\ImagineBundle\Exception\InvalidArgumentException; use Liip\ImagineBundle\Imagine\Data\DataManager; use Liip\ImagineBundle\Model\Binary; use Liip\ImagineBundle\Tests\AbstractTest; @@ -23,7 +24,7 @@ class DataManagerTest extends AbstractTest { public function testThrowsIfConstructedWithWrongTypeArguments(): void { - $this->expectException(\Liip\ImagineBundle\Exception\InvalidArgumentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$extensionGuesser must be an instance of Symfony\Component\Mime\MimeTypesInterface or Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesserInterface'); $mimeTypeGuesser = $this->createMimeTypeGuesserInterfaceMock(); diff --git a/Tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php b/Tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php index 414f600ab..a05a76632 100644 --- a/Tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php +++ b/Tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php @@ -68,7 +68,10 @@ protected function getProtectedReflectionMethodVisible($object, string $method): } $m = $r->getMethod($method); - $m->setAccessible(true); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $m->setAccessible(true); + } return $m; } @@ -85,7 +88,10 @@ protected function getProtectedReflectionPropertyVisible($object, string $proper } $p = $r->getProperty($property); - $p->setAccessible(true); + // remove when we drop support for PHP older than 8.1 + if (PHP_VERSION_ID < 80100) { + $p->setAccessible(true); + } return $p; } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 8360fd847..fa4da3b71 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -36,6 +36,8 @@ + + From ddcd347c43227807a63c53f8c3cb674c5f6265f1 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 5 Jan 2026 11:25:30 +0100 Subject: [PATCH 19/27] dummy commit --- .github/workflows/php-cs-fixer.yml | 2 +- .github/workflows/phpunit.yml | 34 ++++++------------------------ CHANGELOG.md | 4 ++++ composer.json | 2 +- 4 files changed, 12 insertions(+), 30 deletions(-) diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index 7d44869bc..ca3cffee5 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -17,7 +17,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 coverage: none tools: php-cs-fixer diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index f6067a22f..03161ea9b 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -14,45 +14,31 @@ jobs: strategy: fail-fast: false matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] + php: ['8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] dependencies: [highest] symfony: ['*'] - stability: ['stable'] include: # Minimum supported dependencies with the oldest supported PHP version - - php: '7.2' + - php: '8.0' dependencies: lowest symfony: '*' - stability: 'stable' # Minimum supported dependencies with the latest supported PHP version - php: '8.5' dependencies: lowest symfony: '*' - stability: 'stable' # Test each supported Symfony version with the lowest supported PHP version - - php: '7.2' - dependencies: highest - symfony: '5.4.*' - stability: 'stable' - - php: '8.1' dependencies: highest symfony: '6.4.*' - stability: 'stable' - - # Test Symfony 7.4 - - php: '8.5' + - php: '8.2' dependencies: highest symfony: '7.4.*' - stability: 'stable' - - # Test Symfony 8.0 - - php: '8.5' + - php: '8.4' dependencies: highest - symfony: '8.0.*' - stability: 'stable' + symfony: '8.*' + steps: - name: Checkout uses: actions/checkout@v5 @@ -73,18 +59,10 @@ jobs: composer global config --no-plugins allow-plugins.symfony/flex true composer global require --no-interaction --no-progress symfony/flex - - name: Set minimum-stability - run: composer config minimum-stability ${{ matrix.stability }} - - name: Remove enqueue/enqueue-bundle for Symfony 8 if: matrix.symfony == '8.0.*' run: composer remove --no-update enqueue/enqueue-bundle --dev - # Latest enqueue install on PHP 7.4 but uses PHP 8 features - - name: Pin enqueue/enqueue on PHP 7.4 - if: ${{ matrix.php == '7.4' }} - run: composer require --no-update enqueue/enqueue 0.10.18 - - name: Update project dependencies uses: ramsey/composer-install@v2 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 44abd57b0..6fdec6c5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic # 2.x +## [2.17.0](https://github.com/liip/LiipImagineBundle/tree/2.17.0) + +- Drop support for PHP 7 ([dbu](https://github.com/liip/LiipImagineBundle/pull/1646)) + ## [2.16.0](https://github.com/liip/LiipImagineBundle/tree/2.16.0) - Compatible with Symfony 8 ([dmaicher](https://github.com/liip/LiipImagineBundle/pull/1642)) (including a bunch of PRs to change all XML configuration to PHP configuration) diff --git a/composer.json b/composer.json index ca6f5c739..c08526455 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "exclude-from-classmap": [ "/Tests/" ] }, "require": { - "php": "^7.2|^8.0", + "php": "^8.0", "ext-mbstring": "*", "imagine/imagine": "^1.3.2", "symfony/dependency-injection": "^5.4|^6.4|^7.4|^8.0", From 9fe7089b2ae346f0a66987f925554546b91b1d8f Mon Sep 17 00:00:00 2001 From: Jozef Mostka Date: Mon, 5 Jan 2026 15:47:20 +0100 Subject: [PATCH 20/27] Add AssetMapper support (#1645) --- .github/workflows/phpstan.yml | 3 + .github/workflows/phpunit.yml | 5 ++ Binary/Locator/AssetMapperLocator.php | 61 +++++++++++++++ .../Loader/AssetMapperLoaderFactory.php | 49 ++++++++++++ LiipImagineBundle.php | 2 + Resources/config/imagine.php | 8 ++ Resources/doc/configuration.rst | 6 +- Resources/doc/data-loader/asset_mapper.rst | 29 +++++++ .../Binary/Locator/AssetMapperLocatorTest.php | 75 +++++++++++++++++++ .../Loader/AssetMapperLoaderFactoryTest.php | 59 +++++++++++++++ Tests/LiipImagineBundleTest.php | 2 + 11 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 Binary/Locator/AssetMapperLocator.php create mode 100644 DependencyInjection/Factory/Loader/AssetMapperLoaderFactory.php create mode 100644 Resources/doc/data-loader/asset_mapper.rst create mode 100644 Tests/Binary/Locator/AssetMapperLocatorTest.php create mode 100644 Tests/DependencyInjection/Factory/Loader/AssetMapperLoaderFactoryTest.php diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 099c13f1a..5045a2bd9 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -26,5 +26,8 @@ jobs: - name: Add vips run: composer require rokka/imagine-vips + - name: Add asset mapper + run: composer require symfony/asset-mapper + - name: Run PHPStan run: vendor/bin/phpstan analyze diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 03161ea9b..12ea0adc9 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -84,6 +84,11 @@ jobs: SYMFONY_DEPRECATIONS_HELPER: max[self]=0 run: vendor/bin/simple-phpunit -v + - name: Add asset mapper + # asset mapper support is optional in LiipImagineBundle. asset mapper was only added in symfony 6 + if: ${{ matrix.symfony >= '6.4' }} + run: composer require --no-update symfony/asset-mapper --dev + - name: Install php-coveralls run: composer global require --no-interaction --no-progress php-coveralls/php-coveralls diff --git a/Binary/Locator/AssetMapperLocator.php b/Binary/Locator/AssetMapperLocator.php new file mode 100644 index 000000000..20d3418e0 --- /dev/null +++ b/Binary/Locator/AssetMapperLocator.php @@ -0,0 +1,61 @@ +assetMapper->allAssets() as $assetCandidate) { + if ($path === $assetCandidate->publicPath) { + return $assetCandidate->sourcePath; + } + } + throw new NotLoadableException(\sprintf('Asset with public path "%s" not found.', $path)); + } +} diff --git a/DependencyInjection/Factory/Loader/AssetMapperLoaderFactory.php b/DependencyInjection/Factory/Loader/AssetMapperLoaderFactory.php new file mode 100644 index 000000000..f6400e87d --- /dev/null +++ b/DependencyInjection/Factory/Loader/AssetMapperLoaderFactory.php @@ -0,0 +1,49 @@ +replaceArgument(0, new Reference('asset_mapper')); + + $definition = $this->getChildLoaderDefinition('filesystem'); + + if ($container->hasDefinition('liip_imagine.mime_types')) { + $mimeTypes = $container->getDefinition('liip_imagine.mime_types'); + $definition->replaceArgument(0, $mimeTypes); + $definition->replaceArgument(1, $mimeTypes); + } + $definition->replaceArgument(2, $locatorDefinition); + + return $this->setTaggedLoaderDefinition($loaderName, $definition, $container); + } + + public function getName() + { + return 'asset_mapper'; + } + + public function addConfiguration(ArrayNodeDefinition $builder) + { + $builder + ->children() + ->end(); + } +} diff --git a/LiipImagineBundle.php b/LiipImagineBundle.php index f3457915a..5ea0e6375 100644 --- a/LiipImagineBundle.php +++ b/LiipImagineBundle.php @@ -23,6 +23,7 @@ use Liip\ImagineBundle\DependencyInjection\Compiler\NonFunctionalFilterExceptionPass; use Liip\ImagineBundle\DependencyInjection\Compiler\PostProcessorsCompilerPass; use Liip\ImagineBundle\DependencyInjection\Compiler\ResolversCompilerPass; +use Liip\ImagineBundle\DependencyInjection\Factory\Loader\AssetMapperLoaderFactory; use Liip\ImagineBundle\DependencyInjection\Factory\Loader\ChainLoaderFactory; use Liip\ImagineBundle\DependencyInjection\Factory\Loader\FileSystemLoaderFactory; use Liip\ImagineBundle\DependencyInjection\Factory\Loader\FlysystemLoaderFactory; @@ -69,6 +70,7 @@ public function build(ContainerBuilder $container): void $extension->addLoaderFactory(new StreamLoaderFactory()); $extension->addLoaderFactory(new FileSystemLoaderFactory()); $extension->addLoaderFactory(new FlysystemLoaderFactory()); + $extension->addLoaderFactory(new AssetMapperLoaderFactory()); $extension->addLoaderFactory(new ChainLoaderFactory()); $container->registerForAutoconfiguration(LoaderLoaderInterface::class)->addTag('liip_imagine.filter.loader'); diff --git a/Resources/config/imagine.php b/Resources/config/imagine.php index 045b526f3..61f2c220e 100644 --- a/Resources/config/imagine.php +++ b/Resources/config/imagine.php @@ -21,6 +21,7 @@ use Liip\ImagineBundle\Binary\Loader\FlysystemLoader; use Liip\ImagineBundle\Binary\Loader\FlysystemV2Loader; use Liip\ImagineBundle\Binary\Loader\StreamLoader; +use Liip\ImagineBundle\Binary\Locator\AssetMapperLocator; use Liip\ImagineBundle\Binary\Locator\FileSystemInsecureLocator; use Liip\ImagineBundle\Binary\Locator\FileSystemLocator; use Liip\ImagineBundle\Binary\SimpleMimeTypeGuesser; @@ -429,6 +430,13 @@ '', // will be injected by FilesystemLoaderFactory ]) ->tag('liip_imagine.binary.locator', ['shared' => false]); + $services->set('liip_imagine.binary.locator.asset_mapper', AssetMapperLocator::class) + ->share(true) + ->public() + ->args([ + '', // will be injected by AssetMapperLoaderFactory + ]) + ->tag('liip_imagine.binary.locator', ['shared' => false]); $services->set('liip_imagine.binary.locator.filesystem_insecure', FileSystemInsecureLocator::class) ->share(false) diff --git a/Resources/doc/configuration.rst b/Resources/doc/configuration.rst index 36ce79e3a..6ffbdc352 100644 --- a/Resources/doc/configuration.rst +++ b/Resources/doc/configuration.rst @@ -77,7 +77,8 @@ There are several configuration options available: * ``cache`` - default cache resolver. Default value: ``web_path`` (which means the standard web_path resolver is used) * ``data_loader`` - name of a custom data loader. Default value: ``filesystem`` - (which means the standard filesystem loader is used). + (which means the standard filesystem loader is used). Built-in loaders include: + ``filesystem``, ``chain``, ``flysystem``, ``stream``, and ``asset_mapper``. * ``twig.mode`` - Twig filter integration. ``none`` disables the twig filters, ``lazy`` enables Twig using the Twig runtime for lazy loading. The default value is ``legacy`` and enables the old Twig integration that is loaded on each request. Version 3 will drop ``legacy`` and default @@ -99,7 +100,8 @@ There are several configuration options available: * ``cache`` - default cache resolver. Default value: ``web_path`` (which means the standard web_path resolver is used) * ``data_loader`` - name of a custom data loader. Default value: ``filesystem`` - (which means the standard filesystem loader is used). + (which means the standard filesystem loader is used). Built-in loaders include: + ``filesystem``, ``chain``, ``flysystem``, ``stream``, and ``asset_mapper``. * ``post_processors`` - sets post-processors to be applied on filtered image (see Post-Processors section in the :doc:`filters chapter ` for details). * ``driver`` - one of the drivers: ``gd``, ``imagick``, ``gmagick``, ``vips``. diff --git a/Resources/doc/data-loader/asset_mapper.rst b/Resources/doc/data-loader/asset_mapper.rst new file mode 100644 index 000000000..0f37facef --- /dev/null +++ b/Resources/doc/data-loader/asset_mapper.rst @@ -0,0 +1,29 @@ + +.. _data-loaders-asset-mapper: + +Asset Mapper Loader (for dev) +============================ + +The ``AssetMapper`` data loader allows for loading images using Symfony's AssetMapper component. + +Configuration +------------- + +To enable the Asset Mapper loader, you need to configure it in your loaders section. +A common use case is to use it in combination with the default filesystem loader using a chain loader, +especially in development environment. + +.. code-block:: yaml + + # config/packages/liip_imagine.yaml + when@dev: + liip_imagine: + loaders: + asset_mapper: + asset_mapper: ~ + chain: + chain: + loaders: [ asset_mapper, default ] + data_loader: chain + +This configuration creates an ``asset_mapper`` loader and a ``chain`` loader that first tries to find the asset via AssetMapper, and then falls back to the ``default`` loader. Finally, it sets the global ``data_loader`` to use this new ``chain`` loader. diff --git a/Tests/Binary/Locator/AssetMapperLocatorTest.php b/Tests/Binary/Locator/AssetMapperLocatorTest.php new file mode 100644 index 000000000..3c755b19a --- /dev/null +++ b/Tests/Binary/Locator/AssetMapperLocatorTest.php @@ -0,0 +1,75 @@ +markTestSkipped('symfony/asset-mapper is required for this test.'); + } + } + + public function testImplementsLocatorInterface(): void + { + $assetMapper = $this->createMock(AssetMapperInterface::class); + $this->assertInstanceOf(LocatorInterface::class, new AssetMapperLocator($assetMapper)); + } + + public function testLocateWithoutCache(): void + { + $path = 'images/logo.png'; + $pathInfo = '/images/logo.png'; + $sourcePath = '/path/to/logo.png'; + $logicalPath = 'logo.png'; + + $asset = new MappedAsset($logicalPath, $sourcePath, $pathInfo, $pathInfo); + + $assetMapper = $this->createMock(AssetMapperInterface::class); + $assetMapper->expects($this->once()) + ->method('allAssets') + ->willReturn([$asset]); + + $locator = new AssetMapperLocator($assetMapper); + $result = $locator->locate($path); + + $this->assertSame($sourcePath, $result); + } + + public function testThrowsIfAssetNotFound(): void + { + $path = 'images/logo.png'; + + $assetMapper = $this->createMock(AssetMapperInterface::class); + $assetMapper->expects($this->once()) + ->method('allAssets') + ->willReturn([]); + + $locator = new AssetMapperLocator($assetMapper); + + $this->expectException(NotLoadableException::class); + $this->expectExceptionMessage('Asset with public path "/images/logo.png" not found.'); + + $locator->locate($path); + } +} diff --git a/Tests/DependencyInjection/Factory/Loader/AssetMapperLoaderFactoryTest.php b/Tests/DependencyInjection/Factory/Loader/AssetMapperLoaderFactoryTest.php new file mode 100644 index 000000000..9ac658da5 --- /dev/null +++ b/Tests/DependencyInjection/Factory/Loader/AssetMapperLoaderFactoryTest.php @@ -0,0 +1,59 @@ + + */ +class AssetMapperLoaderFactoryTest extends FactoryTestCase +{ + protected function setUp(): void + { + if (!interface_exists(AssetMapperInterface::class)) { + $this->markTestSkipped('symfony/asset-mapper is required for this test.'); + } + } + + public function testImplementsLoaderFactoryInterface(): void + { + $this->assertInstanceOf(LoaderFactoryInterface::class, new AssetMapperLoaderFactory()); + } + + public function testReturnsExpectedName(): void + { + $this->assertSame('asset_mapper', (new AssetMapperLoaderFactory())->getName()); + } + + public function testCreateLoaderDefinition(): void + { + $container = new ContainerBuilder(); + + $loader = new AssetMapperLoaderFactory(); + $loader->create($container, 'the_loader_name', [ + ]); + + $this->assertTrue($container->hasDefinition('liip_imagine.binary.loader.the_loader_name')); + + /** @var ChildDefinition $loaderDefinition */ + $loaderDefinition = $container->getDefinition('liip_imagine.binary.loader.the_loader_name'); + + $this->assertInstanceOfChildDefinition($loaderDefinition); + $this->assertSame('liip_imagine.binary.loader.prototype.filesystem', $loaderDefinition->getParent()); + } +} diff --git a/Tests/LiipImagineBundleTest.php b/Tests/LiipImagineBundleTest.php index 232dd40ae..8082beab9 100644 --- a/Tests/LiipImagineBundleTest.php +++ b/Tests/LiipImagineBundleTest.php @@ -20,6 +20,7 @@ use Liip\ImagineBundle\DependencyInjection\Compiler\NonFunctionalFilterExceptionPass; use Liip\ImagineBundle\DependencyInjection\Compiler\PostProcessorsCompilerPass; use Liip\ImagineBundle\DependencyInjection\Compiler\ResolversCompilerPass; +use Liip\ImagineBundle\DependencyInjection\Factory\Loader\AssetMapperLoaderFactory; use Liip\ImagineBundle\DependencyInjection\Factory\Loader\ChainLoaderFactory; use Liip\ImagineBundle\DependencyInjection\Factory\Loader\FileSystemLoaderFactory; use Liip\ImagineBundle\DependencyInjection\Factory\Loader\FlysystemLoaderFactory; @@ -150,6 +151,7 @@ public function testAddLoaders(): void StreamLoaderFactory::class, FileSystemLoaderFactory::class, FlysystemLoaderFactory::class, + AssetMapperLoaderFactory::class, ChainLoaderFactory::class, ], $loaders); } From 66cb2e12960070f9736d661e2eca0d82d3206166 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 5 Jan 2026 15:49:42 +0100 Subject: [PATCH 21/27] prepare release --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fdec6c5a..2df4967ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic ## [2.17.0](https://github.com/liip/LiipImagineBundle/tree/2.17.0) +- Add AssetMapperLocator to work with the asset mapper in development mode ([tito10047](https://github.com/liip/LiipImagineBundle/pull/1645)) - Drop support for PHP 7 ([dbu](https://github.com/liip/LiipImagineBundle/pull/1646)) ## [2.16.0](https://github.com/liip/LiipImagineBundle/tree/2.16.0) From 7abbd9c8fb63bfa45faa7e58f4e083fb25bc1975 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Tue, 6 Jan 2026 09:12:43 +0100 Subject: [PATCH 22/27] mark asset mapper factory service template abstract like the other services --- CHANGELOG.md | 4 ++++ Resources/config/imagine.php | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2df4967ec..9d61fcb14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic # 2.x +## 2.17.1 + +- Fix for AssetMapperLoaderFactory to not fail when not configured ([dbu](https://github.com/liip/LiipImagineBundle/pull/1649)) + ## [2.17.0](https://github.com/liip/LiipImagineBundle/tree/2.17.0) - Add AssetMapperLocator to work with the asset mapper in development mode ([tito10047](https://github.com/liip/LiipImagineBundle/pull/1645)) diff --git a/Resources/config/imagine.php b/Resources/config/imagine.php index 61f2c220e..4af23d4b3 100644 --- a/Resources/config/imagine.php +++ b/Resources/config/imagine.php @@ -431,12 +431,12 @@ ]) ->tag('liip_imagine.binary.locator', ['shared' => false]); $services->set('liip_imagine.binary.locator.asset_mapper', AssetMapperLocator::class) - ->share(true) - ->public() + ->abstract() + ->private() ->args([ '', // will be injected by AssetMapperLoaderFactory ]) - ->tag('liip_imagine.binary.locator', ['shared' => false]); + ->tag('liip_imagine.binary.locator', ['shared' => true]); $services->set('liip_imagine.binary.locator.filesystem_insecure', FileSystemInsecureLocator::class) ->share(false) From 3d2ff993e52c8cce0c28b985a94465c2e471bc59 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Tue, 6 Jan 2026 10:23:12 +0100 Subject: [PATCH 23/27] lint container in ci --- .github/workflows/phpunit.yml | 13 ++++++++----- Tests/Functional/app/bin/console | 22 ++++++++++++++++++++++ composer.json | 6 +++++- 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100755 Tests/Functional/app/bin/console diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 12ea0adc9..207d99e66 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -63,6 +63,11 @@ jobs: if: matrix.symfony == '8.0.*' run: composer remove --no-update enqueue/enqueue-bundle --dev + - name: Add asset mapper + # asset mapper support is optional in LiipImagineBundle. asset mapper was only added in Symfony 6 + if: ${{ matrix.symfony >= '6.4' }} + run: composer require --no-update symfony/asset-mapper --dev + - name: Update project dependencies uses: ramsey/composer-install@v2 with: @@ -70,6 +75,9 @@ jobs: env: SYMFONY_REQUIRE: "${{ matrix.symfony }}" + - name: Lint container + run: ./Tests/Functional/app/bin/console lint:container + - name: Cache PHPUnit uses: actions/cache@v3 with: @@ -84,11 +92,6 @@ jobs: SYMFONY_DEPRECATIONS_HELPER: max[self]=0 run: vendor/bin/simple-phpunit -v - - name: Add asset mapper - # asset mapper support is optional in LiipImagineBundle. asset mapper was only added in symfony 6 - if: ${{ matrix.symfony >= '6.4' }} - run: composer require --no-update symfony/asset-mapper --dev - - name: Install php-coveralls run: composer global require --no-interaction --no-progress php-coveralls/php-coveralls diff --git a/Tests/Functional/app/bin/console b/Tests/Functional/app/bin/console new file mode 100755 index 000000000..de8aa897c --- /dev/null +++ b/Tests/Functional/app/bin/console @@ -0,0 +1,22 @@ +#!/usr/bin/env php + Date: Tue, 6 Jan 2026 10:34:48 +0100 Subject: [PATCH 24/27] prepare release --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d61fcb14..f7b28ae19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,9 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic # 2.x -## 2.17.1 +## [2.17.1](https://github.com/liip/LiipImagineBundle/tree/2.17.1) -- Fix for AssetMapperLoaderFactory to not fail when not configured ([dbu](https://github.com/liip/LiipImagineBundle/pull/1649)) +- Fix for AssetMapperLoaderFactory service definition to not fail when not configured ([dbu](https://github.com/liip/LiipImagineBundle/pull/1649)) ## [2.17.0](https://github.com/liip/LiipImagineBundle/tree/2.17.0) From de669ae7580215a7f16b1c6bf748dbb91eb608c9 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 19 Mar 2026 11:59:51 +0100 Subject: [PATCH 25/27] cleanup deprecations for new major version --- CHANGELOG.md | 1 + doc/cache-resolver/aws_s3.rst | 3 +- src/Controller/ImagineController.php | 5 +- .../Factory/Resolver/AwsS3ResolverFactory.php | 9 +- src/Imagine/Cache/Resolver/AwsS3Resolver.php | 12 +-- .../Binary/Locator/FileSystemLocatorTest.php | 4 - .../MetadataReaderCompilerPassTest.php | 4 - .../Resolver/AwsS3ResolverFactoryTest.php | 92 ------------------- tests/Functional/AbstractWebTestCase.php | 5 - .../Controller/ImagineControllerTest.php | 4 - .../Cache/Resolver/WebPathResolverTest.php | 16 ---- .../AbstractPostProcessorTestCase.php | 8 -- 12 files changed, 11 insertions(+), 152 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f9f9ef1a..b03d5afbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ for a given releases. Unreleased, upcoming changes will be updated here periodic - Removed deprecated code and BC for old Symfony versions. - The response when the `filter` parameter in a resolve request is not an array is now 400 bad request, and no longer 404 not found. - Simplified the `ProxyResolver` to no longer do the undocumented regex replace logic on domain names (reverting [#687](https://github.com/liip/LiipImagineBundle/pull/687)). +- Removed `use_psr_cache`, the cache now always needs to be a PSR cache and Doctrine cache is no longer supported. # 2.x diff --git a/doc/cache-resolver/aws_s3.rst b/doc/cache-resolver/aws_s3.rst index c64ec6c65..a01bd48fa 100644 --- a/doc/cache-resolver/aws_s3.rst +++ b/doc/cache-resolver/aws_s3.rst @@ -226,8 +226,7 @@ current. You just need to configure them with defined options. .. note:: - The ``cache`` option accepts a doctrine cache, but this is now deprecated. - Use the ``use_psr_cache`` boolean option set to ``true`` so that a psr cache can be used instead. + The ``cache`` needs to be a PSR cache instance. If enabled both first one will be :ref:`Cache `, then :ref:`Proxy ` and after all process delegates to AwsS3 resolver. diff --git a/src/Controller/ImagineController.php b/src/Controller/ImagineController.php index 26383721a..8932e03f6 100644 --- a/src/Controller/ImagineController.php +++ b/src/Controller/ImagineController.php @@ -59,8 +59,7 @@ public function __construct( public function filterAction(Request $request, string $path, string $filter): RedirectResponse { $path = PathHelper::urlPathToFilePath($path); - // TODO once we limit `symfony/http-foundation` to 6.4 or newer, use `$request->query->getString()` - $resolver = $request->query->has('resolver') ? (string) $request->query->get('resolver') : null; + $resolver = $request->query->has('resolver') ? $request->query->getString('resolver') : null; return $this->createRedirectResponse(function () use ($path, $filter, $resolver, $request) { return $this->filterService->getUrlOfFilteredImage( @@ -85,7 +84,7 @@ public function filterAction(Request $request, string $path, string $filter): Re */ public function filterRuntimeAction(Request $request, string $hash, string $path, string $filter): RedirectResponse { - $resolver = $request->query->has('resolver') ? (string) $request->query->get('resolver') : null; + $resolver = $request->query->has('resolver') ? $request->query->getString('resolver') : null; $path = PathHelper::urlPathToFilePath($path); $runtimeConfig = $request->query->all('filters'); diff --git a/src/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php b/src/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php index 0495be413..42b9e4c44 100644 --- a/src/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php +++ b/src/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php @@ -65,11 +65,7 @@ public function create(ContainerBuilder $container, string $name, array $config) $container->setDefinition($cachedResolverId, $container->getDefinition($resolverId)); - if (false === $config['use_psr_cache']) { - trigger_deprecation('liip/imagine-bundle', '2.13.4', \sprintf('Setting the "liip_imagine.resolvers.%s.%s.use_psr_cache" config option to "false" is deprecated.', $resolverName, $this->getName())); - } - - $cacheResolverDefinition = $this->getChildResolverDefinition($config['use_psr_cache'] ? 'psr_cache' : 'cache'); + $cacheResolverDefinition = $this->getChildResolverDefinition('psr_cache'); $cacheResolverDefinition->replaceArgument(0, new Reference($config['cache'])); $cacheResolverDefinition->replaceArgument(1, new Reference($cachedResolverId)); @@ -99,9 +95,6 @@ public function addConfiguration(ArrayNodeDefinition $builder): void ->scalarNode('cache') ->defaultFalse() ->end() - ->booleanNode('use_psr_cache') - ->defaultFalse() - ->end() ->scalarNode('acl') ->defaultValue('public-read') ->end() diff --git a/src/Imagine/Cache/Resolver/AwsS3Resolver.php b/src/Imagine/Cache/Resolver/AwsS3Resolver.php index b7c17d916..59f01f528 100644 --- a/src/Imagine/Cache/Resolver/AwsS3Resolver.php +++ b/src/Imagine/Cache/Resolver/AwsS3Resolver.php @@ -38,13 +38,13 @@ class AwsS3Resolver implements ResolverInterface /** * Constructs a cache resolver storing images on Amazon S3. * - * @param S3Client $storage The Amazon S3 storage API. It's required to know authentication information - * @param string $bucket The bucket name to operate on - * @param string|null $acl The ACL to use when storing new objects. Default: owner read/write, public read - * @param array $getOptions A list of options to be passed when retrieving the object url from Amazon S3 - * @param array $putOptions A list of options to be passed when saving the object to Amazon S3 + * @param S3Client $storage The Amazon S3 storage API. It's required to know authentication information + * @param string $bucket The bucket name to operate on + * @param string $acl The ACL to use when storing new objects. Default: owner read/write, public read + * @param array $getOptions A list of options to be passed when retrieving the object url from Amazon S3 + * @param array $putOptions A list of options to be passed when saving the object to Amazon S3 */ - public function __construct(S3Client $storage, string $bucket, string $acl = 'public-read', array $getOptions = [], $putOptions = []) + public function __construct(S3Client $storage, string $bucket, string $acl = 'public-read', array $getOptions = [], array $putOptions = []) { $this->storage = $storage; $this->bucket = $bucket; diff --git a/tests/Binary/Locator/FileSystemLocatorTest.php b/tests/Binary/Locator/FileSystemLocatorTest.php index ba56e7b17..f9fab6a89 100644 --- a/tests/Binary/Locator/FileSystemLocatorTest.php +++ b/tests/Binary/Locator/FileSystemLocatorTest.php @@ -23,10 +23,6 @@ public function testAllowInvalidPaths(): void { $locator = new FileSystemLocator(['/does/not/exist/foo', '/does/not/exist/bar', $temp = sys_get_temp_dir()], true); $roots = (new \ReflectionObject($locator))->getProperty('roots'); - // remove when we drop support for PHP older than 8.1 - if (PHP_VERSION_ID < 80100) { - $roots->setAccessible(true); - } $array = [ '', '', diff --git a/tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php b/tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php index cb8fbb9c3..a7c9fc696 100644 --- a/tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php +++ b/tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php @@ -76,10 +76,6 @@ public function testDoesNotOverrideCustomReaderWhenExifNotAvailable(): void private static function getVisibilityRestrictedStaticProperty(\ReflectionClass $r, string $p): string { $property = $r->getProperty($p); - // remove when we drop support for PHP older than 8.1 - if (PHP_VERSION_ID < 80100) { - $property->setAccessible(true); - } return $property->getValue(); } diff --git a/tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php b/tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php index 5898f6d77..dd603929e 100644 --- a/tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php +++ b/tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php @@ -185,48 +185,6 @@ public function testWrapResolverWithProxyOnCreateWithoutCache(): void $this->assertSame(['foo'], $resolverDefinition->getArgument(1)); } - /** - * @group legacy - */ - public function testWrapResolverWithCacheOnCreateWithoutProxy(): void - { - $this->expectDeprecation('Since liip/imagine-bundle 2.13.4: Setting the "liip_imagine.resolvers.the_resolver_name.aws_s3.use_psr_cache" config option to "false" is deprecated.'); - - $container = new ContainerBuilder(); - - $resolver = new AwsS3ResolverFactory(); - - $resolver->create($container, 'the_resolver_name', [ - 'client_id' => null, - 'client_config' => [], - 'bucket' => 'aBucket', - 'acl' => 'aAcl', - 'get_options' => [], - 'put_options' => [], - 'cache' => 'the_cache_service_id', - 'use_psr_cache' => false, - 'proxies' => [], - ]); - - $this->assertTrue($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name.cached')); - $cachedResolverDefinition = $container->getDefinition('liip_imagine.cache.resolver.the_resolver_name.cached'); - $this->assertInstanceOf(ChildDefinition::class, $cachedResolverDefinition); - $this->assertSame('liip_imagine.cache.resolver.prototype.aws_s3', $cachedResolverDefinition->getParent()); - - $this->assertFalse($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name.proxied')); - - $this->assertTrue($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name')); - $resolverDefinition = $container->getDefinition('liip_imagine.cache.resolver.the_resolver_name'); - $this->assertInstanceOf(ChildDefinition::class, $resolverDefinition); - $this->assertSame('liip_imagine.cache.resolver.prototype.cache', $resolverDefinition->getParent()); - - $this->assertInstanceOf(Reference::class, $resolverDefinition->getArgument(0)); - $this->assertSame('the_cache_service_id', (string) $resolverDefinition->getArgument(0)); - - $this->assertInstanceOf(Reference::class, $resolverDefinition->getArgument(1)); - $this->assertSame('liip_imagine.cache.resolver.the_resolver_name.cached', (string) $resolverDefinition->getArgument(1)); - } - public function testWrapResolverWithPsrCacheOnCreateWithoutProxy(): void { $container = new ContainerBuilder(); @@ -264,56 +222,6 @@ public function testWrapResolverWithPsrCacheOnCreateWithoutProxy(): void $this->assertSame('liip_imagine.cache.resolver.the_resolver_name.cached', (string) $resolverDefinition->getArgument(1)); } - /** - * @group legacy - */ - public function testWrapResolverWithProxyAndCacheOnCreate(): void - { - $this->expectDeprecation('Since liip/imagine-bundle 2.13.4: Setting the "liip_imagine.resolvers.the_resolver_name.aws_s3.use_psr_cache" config option to "false" is deprecated.'); - - $container = new ContainerBuilder(); - - $resolver = new AwsS3ResolverFactory(); - - $resolver->create($container, 'the_resolver_name', [ - 'client_id' => null, - 'client_config' => [], - 'bucket' => 'aBucket', - 'acl' => 'aAcl', - 'get_options' => [], - 'put_options' => [], - 'cache' => 'the_cache_service_id', - 'use_psr_cache' => false, - 'proxies' => ['foo'], - ]); - - $this->assertTrue($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name.proxied')); - $proxiedResolverDefinition = $container->getDefinition('liip_imagine.cache.resolver.the_resolver_name.proxied'); - $this->assertInstanceOf(ChildDefinition::class, $proxiedResolverDefinition); - $this->assertSame('liip_imagine.cache.resolver.prototype.aws_s3', $proxiedResolverDefinition->getParent()); - - $this->assertTrue($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name.cached')); - $cachedResolverDefinition = $container->getDefinition('liip_imagine.cache.resolver.the_resolver_name.cached'); - $this->assertInstanceOf(ChildDefinition::class, $cachedResolverDefinition); - $this->assertSame('liip_imagine.cache.resolver.prototype.proxy', $cachedResolverDefinition->getParent()); - - $this->assertInstanceOf(Reference::class, $cachedResolverDefinition->getArgument(0)); - $this->assertSame('liip_imagine.cache.resolver.the_resolver_name.proxied', (string) $cachedResolverDefinition->getArgument(0)); - - $this->assertSame(['foo'], $cachedResolverDefinition->getArgument(1)); - - $this->assertTrue($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name')); - $resolverDefinition = $container->getDefinition('liip_imagine.cache.resolver.the_resolver_name'); - $this->assertInstanceOf(ChildDefinition::class, $resolverDefinition); - $this->assertSame('liip_imagine.cache.resolver.prototype.cache', $resolverDefinition->getParent()); - - $this->assertInstanceOf(Reference::class, $resolverDefinition->getArgument(0)); - $this->assertSame('the_cache_service_id', (string) $resolverDefinition->getArgument(0)); - - $this->assertInstanceOf(Reference::class, $resolverDefinition->getArgument(1)); - $this->assertSame('liip_imagine.cache.resolver.the_resolver_name.cached', (string) $resolverDefinition->getArgument(1)); - } - public function testSetCachePrefixIfDefined(): void { $container = new ContainerBuilder(); diff --git a/tests/Functional/AbstractWebTestCase.php b/tests/Functional/AbstractWebTestCase.php index ca19a7cb1..e01885126 100644 --- a/tests/Functional/AbstractWebTestCase.php +++ b/tests/Functional/AbstractWebTestCase.php @@ -36,12 +36,7 @@ protected function getParameter(string $name) protected function getPrivateProperty(object $object, string $name) { $r = new \ReflectionObject($object); - $p = $r->getProperty($name); - // remove when we drop support for PHP older than 8.1 - if (PHP_VERSION_ID < 80100) { - $p->setAccessible(true); - } return $p->getValue($object); } diff --git a/tests/Functional/Controller/ImagineControllerTest.php b/tests/Functional/Controller/ImagineControllerTest.php index 990e6a65e..1b707ffd2 100644 --- a/tests/Functional/Controller/ImagineControllerTest.php +++ b/tests/Functional/Controller/ImagineControllerTest.php @@ -39,10 +39,6 @@ protected function setUp(): void if ($this->webp_generate) { $filterService = $this->getService('test.liip_imagine.service.filter'); $webpGenerate = new \ReflectionProperty($filterService, 'webpGenerate'); - // remove when we drop support for PHP older than 8.1 - if (PHP_VERSION_ID < 80100) { - $webpGenerate->setAccessible(true); - } $webpGenerate->setValue($filterService, true); } } diff --git a/tests/Imagine/Cache/Resolver/WebPathResolverTest.php b/tests/Imagine/Cache/Resolver/WebPathResolverTest.php index cf7a6af4d..f6687d24c 100644 --- a/tests/Imagine/Cache/Resolver/WebPathResolverTest.php +++ b/tests/Imagine/Cache/Resolver/WebPathResolverTest.php @@ -461,10 +461,6 @@ public function testShouldRemoveDoubleSlashInUrl(): void $rc = new \ReflectionClass($resolver); $method = $rc->getMethod('getFileUrl'); - // remove when we drop support for PHP older than 8.1 - if (PHP_VERSION_ID < 80100) { - $method->setAccessible(true); - } $result = $method->invokeArgs($resolver, ['/cats.jpg', 'some_filter']); @@ -482,10 +478,6 @@ public function testShouldSanitizeSeparatorBetweenSchemeAndAuthorityInUrl(): voi $rc = new \ReflectionClass($resolver); $method = $rc->getMethod('getFileUrl'); - // remove when we drop support for PHP older than 8.1 - if (PHP_VERSION_ID < 80100) { - $method->setAccessible(true); - } $result = $method->invokeArgs($resolver, ['https://some.meme.com/cute/cats.jpg', 'some_filter']); @@ -499,15 +491,7 @@ public static function assertAttributeSame($expected, string $actualAttributeNam { $reflector = new \ReflectionObject($actualClassOrObject); $attribute = $reflector->getProperty($actualAttributeName); - // remove when we drop support for PHP older than 8.1 - if (PHP_VERSION_ID < 80100) { - $attribute->setAccessible(true); - } $actual = $attribute->getValue($actualClassOrObject); - // remove when we drop support for PHP older than 8.1 - if (PHP_VERSION_ID < 80100) { - $attribute->setAccessible(false); - } self::assertSame($expected, $actual, $message); } diff --git a/tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php b/tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php index 6f015f103..8e1c3234d 100644 --- a/tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php +++ b/tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php @@ -60,10 +60,6 @@ protected function getProtectedReflectionMethodVisible($object, string $method): } $m = $r->getMethod($method); - // remove when we drop support for PHP older than 8.1 - if (PHP_VERSION_ID < 80100) { - $m->setAccessible(true); - } return $m; } @@ -80,10 +76,6 @@ protected function getProtectedReflectionPropertyVisible($object, string $proper } $p = $r->getProperty($property); - // remove when we drop support for PHP older than 8.1 - if (PHP_VERSION_ID < 80100) { - $p->setAccessible(true); - } return $p; } From 31c61acc3cf3472e563f4ca12b27debe87463775 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 19 Mar 2026 12:00:47 +0100 Subject: [PATCH 26/27] cs fixer --- src/Binary/Loader/ChainLoader.php | 2 +- src/Binary/Loader/FileSystemLoader.php | 2 +- src/Binary/Locator/FileSystemLocator.php | 2 +- src/Command/CacheCommandTrait.php | 2 +- src/Component/Console/Style/ImagineStyle.php | 2 +- src/Config/Stack.php | 2 +- src/DependencyInjection/Configuration.php | 10 ++++---- .../Factory/Loader/ChainLoaderFactory.php | 2 +- .../Loader/FileSystemLoaderFactory.php | 6 ++--- .../Factory/Resolver/AwsS3ResolverFactory.php | 2 +- .../LiipImagineExtension.php | 2 +- .../PostProcessor/InvalidOptionException.php | 2 +- src/Imagine/Cache/CacheManager.php | 4 ++-- .../Cache/Resolver/FlysystemResolver.php | 10 ++++---- .../Cache/Resolver/FlysystemV2Resolver.php | 10 ++++---- .../Cache/Resolver/NoCacheWebPathResolver.php | 2 +- .../Cache/Resolver/WebPathResolver.php | 12 +++++----- src/Imagine/Cache/Signer.php | 4 ++-- src/Imagine/Filter/FilterManager.php | 4 ++-- .../Filter/Loader/FlipFilterLoader.php | 2 +- .../Filter/Loader/ResampleFilterLoader.php | 2 +- src/Resources/config/commands.php | 2 +- src/Resources/config/messenger.php | 2 +- src/Templating/LazyFilterRuntime.php | 2 +- tests/Binary/Loader/FileSystemLoaderTest.php | 2 +- .../Locator/FileSystemInsecureLocatorTest.php | 2 +- .../Binary/Locator/FileSystemLocatorTest.php | 2 +- .../LiipImagineExtensionTest.php | 6 ++--- tests/Imagine/Cache/CacheManagerTest.php | 24 +++++++++---------- .../Loader/DownscaleFilterLoaderTest.php | 2 +- .../JpegOptimPostProcessorTest.php | 4 ++-- .../MozJpegPostProcessorTest.php | 4 ++-- .../OptiPngPostProcessorTest.php | 4 ++-- .../PngquantPostProcessorTest.php | 4 ++-- 34 files changed, 73 insertions(+), 73 deletions(-) diff --git a/src/Binary/Loader/ChainLoader.php b/src/Binary/Loader/ChainLoader.php index 0a50def10..1068b462b 100644 --- a/src/Binary/Loader/ChainLoader.php +++ b/src/Binary/Loader/ChainLoader.php @@ -25,7 +25,7 @@ class ChainLoader implements LoaderInterface */ public function __construct(array $loaders) { - $this->loaders = array_filter($loaders, function ($loader) { + $this->loaders = array_filter($loaders, static function ($loader) { return $loader instanceof LoaderInterface; }); } diff --git a/src/Binary/Loader/FileSystemLoader.php b/src/Binary/Loader/FileSystemLoader.php index a8754c66b..6e65800d1 100644 --- a/src/Binary/Loader/FileSystemLoader.php +++ b/src/Binary/Loader/FileSystemLoader.php @@ -38,7 +38,7 @@ public function __construct( public function find($path) { $path = $this->locator->locate($path); - if (false === \is_file($path)) { + if (false === is_file($path)) { throw new NotLoadableException(\sprintf('Source image: "%s" is no file.', $path)); } $mimeType = $this->mimeTypeGuesser->guessMimeType($path); diff --git a/src/Binary/Locator/FileSystemLocator.php b/src/Binary/Locator/FileSystemLocator.php index 08e5d9479..92636c41c 100644 --- a/src/Binary/Locator/FileSystemLocator.php +++ b/src/Binary/Locator/FileSystemLocator.php @@ -101,7 +101,7 @@ private function sanitizeRootPath(string $path, bool $allowUnresolvable): ?strin */ private function sanitizeAbsolutePath(string $path): string { - $roots = array_filter($this->roots, function (string $root) use ($path): bool { + $roots = array_filter($this->roots, static function (string $root) use ($path): bool { return 0 === mb_strpos($path, $root); }); diff --git a/src/Command/CacheCommandTrait.php b/src/Command/CacheCommandTrait.php index 2a5e7e0fe..4c9a9e655 100644 --- a/src/Command/CacheCommandTrait.php +++ b/src/Command/CacheCommandTrait.php @@ -82,7 +82,7 @@ private function outputCommandHeader(): void private function outputCommandResult(array $images, array $filters, string $singularAction): void { if (!$this->outputMachineReadable) { - $wordPluralizer = function (int $count, string $singular) { + $wordPluralizer = static function (int $count, string $singular) { return 1 === $count ? $singular : \sprintf('%ss', $singular); }; diff --git a/src/Component/Console/Style/ImagineStyle.php b/src/Component/Console/Style/ImagineStyle.php index 043d62739..2c07296ff 100644 --- a/src/Component/Console/Style/ImagineStyle.php +++ b/src/Component/Console/Style/ImagineStyle.php @@ -146,6 +146,6 @@ private function compileString(string $format, array $replacements = []): string } catch (\ValueError $error) { } - throw new InvalidArgumentException(\sprintf('Invalid string format "%s" or replacements "%s".', $format, implode(', ', array_map(function ($replacement) { return var_export($replacement, true); }, $replacements)))); + throw new InvalidArgumentException(\sprintf('Invalid string format "%s" or replacements "%s".', $format, implode(', ', array_map(static function ($replacement) { return var_export($replacement, true); }, $replacements)))); } } diff --git a/src/Config/Stack.php b/src/Config/Stack.php index 74b594bdb..6de0d6d49 100644 --- a/src/Config/Stack.php +++ b/src/Config/Stack.php @@ -64,7 +64,7 @@ public function getFilters(): array private function setFilters(array $filters): void { foreach ($filters as $filter) { - if (!($filter instanceof FilterInterface)) { + if (!$filter instanceof FilterInterface) { throw new InvalidArgumentException('Unknown filter provided.'); } } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index bd4160c10..8916a224d 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -65,14 +65,14 @@ public function getConfigTreeBuilder(): TreeBuilder $rootNode ->beforeNormalization() - ->ifTrue(function ($v) { + ->ifTrue(static function ($v) { return empty($v['loaders']) || empty($v['loaders']['default']) || empty($v['resolvers']) || empty($v['resolvers']['default']); }) - ->then(function ($v) { + ->then(static function ($v) { if (empty($v['loaders'])) { $v['loaders'] = []; } @@ -106,7 +106,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->children() ->scalarNode('driver')->defaultValue('gd') ->validate() - ->ifTrue(function ($v) { + ->ifTrue(static function ($v) { return !\in_array($v, ['gd', 'imagick', 'gmagick', 'vips'], true); }) ->thenInvalid('Invalid imagine driver specified: %s') @@ -154,7 +154,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->scalarNode('filter_runtime_action')->defaultValue(\sprintf('%s::filterRuntimeAction', ImagineController::class))->end() ->integerNode('redirect_response_code')->defaultValue(302) ->validate() - ->ifTrue(function ($redirectResponseCode) { + ->ifTrue(static function ($redirectResponseCode) { return !\in_array($redirectResponseCode, ControllerConfig::REDIRECT_RESPONSE_CODES, true); }) ->thenInvalid('Invalid redirect response code "%s" (must be 201, 301, 302, 303, 307, or 308).') @@ -262,7 +262,7 @@ private function addConfigurationSections(array $factories, ArrayNodeDefinition $nodeDefinition ->validate() - ->ifTrue(function ($array) use ($type) { + ->ifTrue(static function ($array) use ($type) { foreach ($array as $name => $element) { if (!$element) { throw new InvalidConfigurationException(ucfirst($type).' "'.$name.'" must have a factory configured'); diff --git a/src/DependencyInjection/Factory/Loader/ChainLoaderFactory.php b/src/DependencyInjection/Factory/Loader/ChainLoaderFactory.php index d0b958ae3..2dd74573a 100644 --- a/src/DependencyInjection/Factory/Loader/ChainLoaderFactory.php +++ b/src/DependencyInjection/Factory/Loader/ChainLoaderFactory.php @@ -50,7 +50,7 @@ public function addConfiguration(ArrayNodeDefinition $builder): void */ private function createLoaderReferences(array $loaders): array { - return array_combine($loaders, array_map(function (string $name): Reference { + return array_combine($loaders, array_map(static function (string $name): Reference { return new Reference(\sprintf('liip_imagine.binary.loader.%s', $name)); }, $loaders)); } diff --git a/src/DependencyInjection/Factory/Loader/FileSystemLoaderFactory.php b/src/DependencyInjection/Factory/Loader/FileSystemLoaderFactory.php index 35e5fa54f..2e099194a 100644 --- a/src/DependencyInjection/Factory/Loader/FileSystemLoaderFactory.php +++ b/src/DependencyInjection/Factory/Loader/FileSystemLoaderFactory.php @@ -49,7 +49,7 @@ public function addConfiguration(ArrayNodeDefinition $builder): void ->arrayNode('data_root') ->beforeNormalization() ->ifString() - ->then(function ($value) { + ->then(static function ($value) { return [$value]; }) ->end() @@ -118,7 +118,7 @@ private function getBundleResourcePaths(ContainerBuilder $container): array $paths = $this->getBundlePathsUsingNamedObj($container->getParameter('kernel.bundles')); } - return array_map(function (string $path): string { + return array_map(static function (string $path): string { return $path.DIRECTORY_SEPARATOR.'Resources'.DIRECTORY_SEPARATOR.'public'; }, $paths); } @@ -130,7 +130,7 @@ private function getBundleResourcePaths(ContainerBuilder $container): array */ private function getBundlePathsUsingMetadata(array $metadata): array { - return array_combine(array_keys($metadata), array_map(function (array $data) { + return array_combine(array_keys($metadata), array_map(static function (array $data) { return $data['path']; }, $metadata)); } diff --git a/src/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php b/src/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php index 42b9e4c44..aca03a470 100644 --- a/src/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php +++ b/src/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php @@ -139,7 +139,7 @@ public function addConfiguration(ArrayNodeDefinition $builder): void ->ifTrue(static function ($v) { return isset($v['client_id']); }) - ->then(function ($config) { + ->then(static function ($config) { $config['client_config'] = []; return $config; diff --git a/src/DependencyInjection/LiipImagineExtension.php b/src/DependencyInjection/LiipImagineExtension.php index 3a925e2a0..25d0358dd 100644 --- a/src/DependencyInjection/LiipImagineExtension.php +++ b/src/DependencyInjection/LiipImagineExtension.php @@ -131,7 +131,7 @@ public function prepend(ContainerBuilder $container): void private function createFilterSets(array $defaultFilterSets, array $filterSets): array { - return array_map(function (array $filterSet) use ($defaultFilterSets) { + return array_map(static function (array $filterSet) use ($defaultFilterSets) { return array_replace_recursive($defaultFilterSets, $filterSet); }, $filterSets); } diff --git a/src/Exception/Imagine/Filter/PostProcessor/InvalidOptionException.php b/src/Exception/Imagine/Filter/PostProcessor/InvalidOptionException.php index 999a3d5d2..cd5955dce 100644 --- a/src/Exception/Imagine/Filter/PostProcessor/InvalidOptionException.php +++ b/src/Exception/Imagine/Filter/PostProcessor/InvalidOptionException.php @@ -29,7 +29,7 @@ private function stringifyOptions(array $options = []): string $options = array_map([$this, 'stringifyOptionValue'], $options); - array_walk($options, function (&$o, $name) { + array_walk($options, static function (&$o, $name) { $o = \sprintf('%s="%s"', $name, $o); }); diff --git a/src/Imagine/Cache/CacheManager.php b/src/Imagine/Cache/CacheManager.php index 12c9a8eef..0a84880e4 100644 --- a/src/Imagine/Cache/CacheManager.php +++ b/src/Imagine/Cache/CacheManager.php @@ -97,7 +97,7 @@ public function getBrowserPath(string $path, string $filter, array $runtimeConfi */ public function getRuntimePath(string $path, array $runtimeConfig): string { - $path = ltrim($path, '/'); + $path = mb_ltrim($path, '/'); return 'rc/'.$this->signer->sign($path, $runtimeConfig).'/'.$path; } @@ -112,7 +112,7 @@ public function getRuntimePath(string $path, array $runtimeConfig): string public function generateUrl(string $path, string $filter, array $runtimeConfig = [], ?string $resolver = null, int $referenceType = UrlGeneratorInterface::ABSOLUTE_URL): string { $params = [ - 'path' => ltrim($path, '/'), + 'path' => mb_ltrim($path, '/'), 'filter' => $filter, ]; diff --git a/src/Imagine/Cache/Resolver/FlysystemResolver.php b/src/Imagine/Cache/Resolver/FlysystemResolver.php index 2e7c83bae..9c08120eb 100644 --- a/src/Imagine/Cache/Resolver/FlysystemResolver.php +++ b/src/Imagine/Cache/Resolver/FlysystemResolver.php @@ -49,8 +49,8 @@ public function __construct( $this->flysystem = $flysystem; $this->requestContext = $requestContext; - $this->webRoot = rtrim($rootUrl, '/'); - $this->cachePrefix = ltrim(str_replace('//', '/', $cachePrefix), '/'); + $this->webRoot = mb_rtrim($rootUrl, '/'); + $this->cachePrefix = mb_ltrim(str_replace('//', '/', $cachePrefix), '/'); $this->cacheRoot = $this->cachePrefix; $this->visibility = $visibility; } @@ -77,8 +77,8 @@ public function resolve(string $path, string $filter): string { return \sprintf( '%s/%s', - rtrim($this->webRoot, '/'), - ltrim($this->getFileUrl($path, $filter), '/') + mb_rtrim($this->webRoot, '/'), + mb_ltrim($this->getFileUrl($path, $filter), '/') ); } @@ -136,6 +136,6 @@ protected function getFileUrl(string $path, string $filter): string // crude way of sanitizing URL scheme ("protocol") part $path = str_replace('://', '---', $path); - return $this->cachePrefix.'/'.$filter.'/'.ltrim($path, '/'); + return $this->cachePrefix.'/'.$filter.'/'.mb_ltrim($path, '/'); } } diff --git a/src/Imagine/Cache/Resolver/FlysystemV2Resolver.php b/src/Imagine/Cache/Resolver/FlysystemV2Resolver.php index ade061073..df76833d5 100644 --- a/src/Imagine/Cache/Resolver/FlysystemV2Resolver.php +++ b/src/Imagine/Cache/Resolver/FlysystemV2Resolver.php @@ -50,8 +50,8 @@ public function __construct( $this->flysystem = $flysystem; $this->requestContext = $requestContext; - $this->webRoot = rtrim($rootUrl, '/'); - $this->cachePrefix = ltrim(str_replace('//', '/', $cachePrefix), '/'); + $this->webRoot = mb_rtrim($rootUrl, '/'); + $this->cachePrefix = mb_ltrim(str_replace('//', '/', $cachePrefix), '/'); $this->cacheRoot = $this->cachePrefix; $this->visibility = $visibility; } @@ -78,8 +78,8 @@ public function resolve(string $path, string $filter): string { return \sprintf( '%s/%s', - rtrim($this->webRoot, '/'), - ltrim($this->getFileUrl($path, $filter), '/') + mb_rtrim($this->webRoot, '/'), + mb_ltrim($this->getFileUrl($path, $filter), '/') ); } @@ -137,6 +137,6 @@ protected function getFileUrl(string $path, string $filter): string // crude way of sanitizing URL scheme ("protocol") part $path = str_replace('://', '---', $path); - return $this->cachePrefix.'/'.$filter.'/'.ltrim($path, '/'); + return $this->cachePrefix.'/'.$filter.'/'.mb_ltrim($path, '/'); } } diff --git a/src/Imagine/Cache/Resolver/NoCacheWebPathResolver.php b/src/Imagine/Cache/Resolver/NoCacheWebPathResolver.php index ee2eb4670..ab7b690fd 100644 --- a/src/Imagine/Cache/Resolver/NoCacheWebPathResolver.php +++ b/src/Imagine/Cache/Resolver/NoCacheWebPathResolver.php @@ -43,7 +43,7 @@ public function resolve(string $path, string $filter): string $this->requestContext->getScheme(), $this->requestContext->getHost(), $port, - ltrim(PathHelper::filePathToUrlPath($path), '/') + mb_ltrim(PathHelper::filePathToUrlPath($path), '/') ); } diff --git a/src/Imagine/Cache/Resolver/WebPathResolver.php b/src/Imagine/Cache/Resolver/WebPathResolver.php index 78eaca9e8..c65bff5e2 100644 --- a/src/Imagine/Cache/Resolver/WebPathResolver.php +++ b/src/Imagine/Cache/Resolver/WebPathResolver.php @@ -37,16 +37,16 @@ public function __construct( $this->filesystem = $filesystem; $this->requestContext = $requestContext; - $this->webRoot = rtrim(str_replace('//', '/', $webRootDir), '/'); - $this->cachePrefix = ltrim(str_replace('//', '/', $cachePrefix), '/'); + $this->webRoot = mb_rtrim(str_replace('//', '/', $webRootDir), '/'); + $this->cachePrefix = mb_ltrim(str_replace('//', '/', $cachePrefix), '/'); $this->cacheRoot = $this->webRoot.'/'.$this->cachePrefix; } public function resolve(string $path, string $filter): string { return \sprintf('%s/%s', - rtrim($this->getBaseUrl(), '/'), - ltrim($this->getFileUrl($path, $filter), '/') + mb_rtrim($this->getBaseUrl(), '/'), + mb_ltrim($this->getFileUrl($path, $filter), '/') ); } @@ -112,7 +112,7 @@ protected function getBaseUrl(): string if ('.php' === mb_substr($this->requestContext->getBaseUrl(), -4)) { $baseUrl = pathinfo($this->requestContext->getBaseurl(), PATHINFO_DIRNAME); } - $baseUrl = rtrim($baseUrl, '/\\'); + $baseUrl = mb_rtrim($baseUrl, '/\\'); return \sprintf('%s://%s%s%s', $this->requestContext->getScheme(), @@ -127,6 +127,6 @@ private function getFullPath(string $path, string $filter): string // crude way of sanitizing URL scheme ("protocol") part $path = str_replace('://', '---', $path); - return $this->cachePrefix.'/'.$filter.'/'.ltrim($path, '/'); + return $this->cachePrefix.'/'.$filter.'/'.mb_ltrim($path, '/'); } } diff --git a/src/Imagine/Cache/Signer.php b/src/Imagine/Cache/Signer.php index 877f80292..c766d1014 100644 --- a/src/Imagine/Cache/Signer.php +++ b/src/Imagine/Cache/Signer.php @@ -23,12 +23,12 @@ public function __construct(string $secret) public function sign(string $path, ?array $runtimeConfig = null): string { if ($runtimeConfig) { - array_walk_recursive($runtimeConfig, function (&$value) { + array_walk_recursive($runtimeConfig, static function (&$value) { $value = (string) $value; }); } - return mb_substr(preg_replace('/[^a-zA-Z0-9-_]/', '', base64_encode(hash_hmac('sha256', ltrim($path, '/').(null === $runtimeConfig ?: serialize($runtimeConfig)), $this->secret, true))), 0, 8); + return mb_substr(preg_replace('/[^a-zA-Z0-9-_]/', '', base64_encode(hash_hmac('sha256', mb_ltrim($path, '/').(null === $runtimeConfig ?: serialize($runtimeConfig)), $this->secret, true))), 0, 8); } public function check(string $hash, string $path, ?array $runtimeConfig = null): bool diff --git a/src/Imagine/Filter/FilterManager.php b/src/Imagine/Filter/FilterManager.php index 148e53738..d68b7d829 100644 --- a/src/Imagine/Filter/FilterManager.php +++ b/src/Imagine/Filter/FilterManager.php @@ -175,7 +175,7 @@ private function sanitizeFilters(array $filters): array }, ARRAY_FILTER_USE_KEY); if (\count($filters) !== \count($sanitized)) { - throw new \InvalidArgumentException(\sprintf('Could not find filter(s): %s', implode(', ', array_map(function (string $name): string { return \sprintf('"%s"', $name); }, array_diff(array_keys($filters), array_keys($sanitized)))))); + throw new \InvalidArgumentException(\sprintf('Could not find filter(s): %s', implode(', ', array_map(static function (string $name): string { return \sprintf('"%s"', $name); }, array_diff(array_keys($filters), array_keys($sanitized)))))); } return $sanitized; @@ -188,7 +188,7 @@ private function sanitizePostProcessors(array $processors): array }, ARRAY_FILTER_USE_KEY); if (\count($processors) !== \count($sanitized)) { - throw new \InvalidArgumentException(\sprintf('Could not find post processor(s): %s', implode(', ', array_map(function (string $name): string { return \sprintf('"%s"', $name); }, array_diff(array_keys($processors), array_keys($sanitized)))))); + throw new \InvalidArgumentException(\sprintf('Could not find post processor(s): %s', implode(', ', array_map(static function (string $name): string { return \sprintf('"%s"', $name); }, array_diff(array_keys($processors), array_keys($sanitized)))))); } return $sanitized; diff --git a/src/Imagine/Filter/Loader/FlipFilterLoader.php b/src/Imagine/Filter/Loader/FlipFilterLoader.php index e74574c69..3de13a605 100644 --- a/src/Imagine/Filter/Loader/FlipFilterLoader.php +++ b/src/Imagine/Filter/Loader/FlipFilterLoader.php @@ -31,7 +31,7 @@ private function sanitizeOptions(array $options): array $resolver = new OptionsResolver(); $resolver->setDefault('axis', 'x'); $resolver->setAllowedValues('axis', ['x', 'horizontal', 'y', 'vertical']); - $resolver->setNormalizer('axis', function (Options $options, $value) { + $resolver->setNormalizer('axis', static function (Options $options, $value) { return 'horizontal' === $value ? 'x' : ('vertical' === $value ? 'y' : $value); }); diff --git a/src/Imagine/Filter/Loader/ResampleFilterLoader.php b/src/Imagine/Filter/Loader/ResampleFilterLoader.php index bbbda9a35..ce15509fc 100644 --- a/src/Imagine/Filter/Loader/ResampleFilterLoader.php +++ b/src/Imagine/Filter/Loader/ResampleFilterLoader.php @@ -104,7 +104,7 @@ private function resolveOptions(array $options): array ImageInterface::RESOLUTION_PIXELSPERCENTIMETER, ]); - $resolver->setNormalizer('filter', function (Options $options, $value) { + $resolver->setNormalizer('filter', static function (Options $options, $value) { foreach (['\Imagine\Image\ImageInterface::FILTER_%s', '\Imagine\Image\ImageInterface::%s', '%s'] as $format) { if (\defined($constant = \sprintf($format, mb_strtoupper($value))) || \defined($constant = \sprintf($format, $value))) { return \constant($constant); diff --git a/src/Resources/config/commands.php b/src/Resources/config/commands.php index 504978a20..3da1e7d0f 100644 --- a/src/Resources/config/commands.php +++ b/src/Resources/config/commands.php @@ -14,7 +14,7 @@ use Liip\ImagineBundle\Command\RemoveCacheCommand; use Liip\ImagineBundle\Command\ResolveCacheCommand; -return function (ContainerConfigurator $container): void { +return static function (ContainerConfigurator $container): void { $container->services() ->set('liip_imagine.command.cache_remove', RemoveCacheCommand::class) ->tag('console.command', ['command' => 'liip:imagine:cache:remove', 'alias' => 'imagine:del']) diff --git a/src/Resources/config/messenger.php b/src/Resources/config/messenger.php index 766000920..fdbc7b730 100644 --- a/src/Resources/config/messenger.php +++ b/src/Resources/config/messenger.php @@ -14,7 +14,7 @@ use Liip\ImagineBundle\Message\Handler\WarmupCacheHandler; use Liip\ImagineBundle\Message\WarmupCache; -return function (ContainerConfigurator $container): void { +return static function (ContainerConfigurator $container): void { $container->services() ->set('liip_imagine.messenger.warmup_cache_processor', WarmupCacheHandler::class) ->tag('messenger.message_handler', ['handles' => WarmupCache::class]) diff --git a/src/Templating/LazyFilterRuntime.php b/src/Templating/LazyFilterRuntime.php index f7b17e659..752288418 100644 --- a/src/Templating/LazyFilterRuntime.php +++ b/src/Templating/LazyFilterRuntime.php @@ -81,7 +81,7 @@ private function cleanPath(string $path): string if ($this->assetVersion) { $start = mb_strrpos($path, $this->assetVersion); if (mb_strlen($path) - mb_strlen($this->assetVersion) === $start) { - return rtrim(mb_substr($path, 0, $start), '?'); + return mb_rtrim(mb_substr($path, 0, $start), '?'); } } diff --git a/tests/Binary/Loader/FileSystemLoaderTest.php b/tests/Binary/Loader/FileSystemLoaderTest.php index b02badd18..5d6c9c227 100644 --- a/tests/Binary/Loader/FileSystemLoaderTest.php +++ b/tests/Binary/Loader/FileSystemLoaderTest.php @@ -91,7 +91,7 @@ public static function provideMultipleRootLoadCases(): array realpath(__DIR__.'/../../../'), ]; - return array_map(function ($parameters) use ($pathsPrepended) { + return array_map(static function ($parameters) use ($pathsPrepended) { return [[$pathsPrepended[mt_rand(0, \count($pathsPrepended) - 1)], $parameters[0]], $parameters[1]]; }, static::provideLoadCases()); } diff --git a/tests/Binary/Locator/FileSystemInsecureLocatorTest.php b/tests/Binary/Locator/FileSystemInsecureLocatorTest.php index e63041702..d57a50ed9 100644 --- a/tests/Binary/Locator/FileSystemInsecureLocatorTest.php +++ b/tests/Binary/Locator/FileSystemInsecureLocatorTest.php @@ -74,7 +74,7 @@ public static function provideMultipleRootLoadCases(): array realpath(__DIR__.'/../../../'), ]; - return array_map(function ($params) use ($prepend) { + return array_map(static function ($params) use ($prepend) { return [[$prepend[mt_rand(0, \count($prepend) - 1)], $params[0]], $params[1]]; }, static::provideLoadCases()); } diff --git a/tests/Binary/Locator/FileSystemLocatorTest.php b/tests/Binary/Locator/FileSystemLocatorTest.php index f9fab6a89..b5301948d 100644 --- a/tests/Binary/Locator/FileSystemLocatorTest.php +++ b/tests/Binary/Locator/FileSystemLocatorTest.php @@ -83,7 +83,7 @@ public static function provideMultipleRootLoadCases(): array realpath(__DIR__.'/../../../'), ]; - return array_map(function ($params) use ($prepend) { + return array_map(static function ($params) use ($prepend) { return [[$prepend[mt_rand(0, \count($prepend) - 1)], $params[0]], $params[1]]; }, static::provideLoadCases()); } diff --git a/tests/DependencyInjection/LiipImagineExtensionTest.php b/tests/DependencyInjection/LiipImagineExtensionTest.php index c85151e59..304444eed 100644 --- a/tests/DependencyInjection/LiipImagineExtensionTest.php +++ b/tests/DependencyInjection/LiipImagineExtensionTest.php @@ -280,11 +280,11 @@ private function assertHasNotDefinition(string $id): void private function assertDICConstructorArguments(Definition $definition, array $arguments): void { - $castArrayElementsToString = function (array $a): array { - return array_map(function ($v) { return (string) $v; }, $a); + $castArrayElementsToString = static function (array $a): array { + return array_map(static function ($v) { return (string) $v; }, $a); }; - $implodeArrayElements = function (array $a): string { + $implodeArrayElements = static function (array $a): string { return \sprintf('[%s]:%d', implode(',', $a), \count($a)); }; diff --git a/tests/Imagine/Cache/CacheManagerTest.php b/tests/Imagine/Cache/CacheManagerTest.php index 42f252fba..9a7332707 100644 --- a/tests/Imagine/Cache/CacheManagerTest.php +++ b/tests/Imagine/Cache/CacheManagerTest.php @@ -441,7 +441,7 @@ public function testRemoveCacheForPathAndFilterOnRemove(): void $config ->expects($this->atLeastOnce()) ->method('get') - ->willReturnCallback(function ($filter) { + ->willReturnCallback(static function ($filter) { return [ 'cache' => $filter, ]; @@ -479,7 +479,7 @@ public function testRemoveCacheForPathAndSomeFiltersOnRemove(): void $config ->expects($this->atLeastOnce()) ->method('get') - ->willReturnCallback(function ($filter) { + ->willReturnCallback(static function ($filter) { return [ 'cache' => $filter, ]; @@ -515,7 +515,7 @@ public function testRemoveCacheForSomePathsAndFilterOnRemove(): void $config ->expects($this->atLeastOnce()) ->method('get') - ->willReturnCallback(function ($filter) { + ->willReturnCallback(static function ($filter) { return [ 'cache' => $filter, ]; @@ -554,7 +554,7 @@ public function testRemoveCacheForSomePathsAndSomeFiltersOnRemove(): void $config ->expects($this->atLeastOnce()) ->method('get') - ->willReturnCallback(function ($filter) { + ->willReturnCallback(static function ($filter) { return [ 'cache' => $filter, ]; @@ -595,7 +595,7 @@ public function testRemoveCacheForAllFiltersOnRemove(): void $config ->expects($this->atLeastOnce()) ->method('get') - ->willReturnCallback(function ($filter) { + ->willReturnCallback(static function ($filter) { return [ 'cache' => $filter, ]; @@ -641,7 +641,7 @@ public function testRemoveCacheForPathAndAllFiltersOnRemove(): void $config ->expects($this->atLeastOnce()) ->method('get') - ->willReturnCallback(function ($filter) { + ->willReturnCallback(static function ($filter) { return [ 'cache' => $filter, ]; @@ -680,7 +680,7 @@ public function testAggregateFiltersByResolverOnRemove(): void $config ->expects($this->atLeastOnce()) ->method('get') - ->willReturnCallback(function ($filter) { + ->willReturnCallback(static function ($filter) { return [ 'cache' => $filter, ]; @@ -740,7 +740,7 @@ public function testShouldAllowToPassChangedDataFromPreResolveEventToResolver(): ImagineEvents::POST_RESOLVE, ] ) - ->willReturnCallback(function (CacheResolveEvent $event, string $eventName) { + ->willReturnCallback(static function (CacheResolveEvent $event, string $eventName) { if (ImagineEvents::PRE_RESOLVE !== $eventName) { return; } @@ -770,7 +770,7 @@ public function testShouldAllowToGetResolverByFilterChangedInPreResolveEvent(): $dispatcher = $this->createEventDispatcherMock(); $dispatcher ->method('dispatch') - ->willReturnCallback(function (CacheResolveEvent $event, string $eventName) { + ->willReturnCallback(static function (CacheResolveEvent $event, string $eventName) { if (ImagineEvents::PRE_RESOLVE !== $eventName) { return; } @@ -810,14 +810,14 @@ public function testShouldAllowToPassChangedDataFromPreResolveEventToPostResolve [ $this->logicalAnd( $this->isInstanceOf(CacheResolveEvent::class), - $this->callback(function (CacheResolveEvent $event) { + $this->callback(static function (CacheResolveEvent $event) { return 'changed_filter' === $event->getFilter() && 'changed_path' === $event->getPath(); }) ), ImagineEvents::POST_RESOLVE, ] ) - ->willReturnCallback(function (CacheResolveEvent $event, string $eventName) { + ->willReturnCallback(static function (CacheResolveEvent $event, string $eventName) { if (ImagineEvents::PRE_RESOLVE !== $eventName) { return; } @@ -851,7 +851,7 @@ public function testShouldReturnUrlChangedInPostResolveEvent(): void ImagineEvents::POST_RESOLVE, ] ) - ->willReturnCallback(function (CacheResolveEvent $event, string $eventName) { + ->willReturnCallback(static function (CacheResolveEvent $event, string $eventName) { if (ImagineEvents::POST_RESOLVE !== $eventName) { return; } diff --git a/tests/Imagine/Filter/Loader/DownscaleFilterLoaderTest.php b/tests/Imagine/Filter/Loader/DownscaleFilterLoaderTest.php index 9fb934be7..73e682177 100644 --- a/tests/Imagine/Filter/Loader/DownscaleFilterLoaderTest.php +++ b/tests/Imagine/Filter/Loader/DownscaleFilterLoaderTest.php @@ -62,7 +62,7 @@ public function provideSizes() ->willReturn($initialSize); $image ->method('resize') - ->willReturnCallback(function (Box $box) use ($image, &$resultSize): ImageInterface { + ->willReturnCallback(static function (Box $box) use ($image, &$resultSize): ImageInterface { $resultSize = $box; return $image; diff --git a/tests/Imagine/Filter/PostProcessor/JpegOptimPostProcessorTest.php b/tests/Imagine/Filter/PostProcessor/JpegOptimPostProcessorTest.php index a6a279e3b..b091e2ea1 100644 --- a/tests/Imagine/Filter/PostProcessor/JpegOptimPostProcessorTest.php +++ b/tests/Imagine/Filter/PostProcessor/JpegOptimPostProcessorTest.php @@ -44,7 +44,7 @@ public static function provideProcessArgumentsData(): array [[null, true, 85], ['progressive' => true], ['--strip-all', '--max=85', '--all-progressive']], ]; - return array_map(function (array $d) { + return array_map(static function (array $d) { array_unshift($d[2], AbstractPostProcessorTestCase::getPostProcessAsFileExecutable()); return $d; @@ -86,7 +86,7 @@ public static function provideProcessData(): array [['progressive' => true], '--strip-all --all-progressive'], ]; - return array_map(function ($d) use ($file) { + return array_map(static function ($d) use ($file) { array_unshift($d, $file); return $d; diff --git a/tests/Imagine/Filter/PostProcessor/MozJpegPostProcessorTest.php b/tests/Imagine/Filter/PostProcessor/MozJpegPostProcessorTest.php index dee153707..17c7d6427 100644 --- a/tests/Imagine/Filter/PostProcessor/MozJpegPostProcessorTest.php +++ b/tests/Imagine/Filter/PostProcessor/MozJpegPostProcessorTest.php @@ -34,7 +34,7 @@ public static function provideProcessArgumentsData(): array [['quant_table' => 4, 'optimise' => true, 'quality' => 100], ['-quant-table', 4, '-optimise', '-quality', 100]], ]; - return array_map(function (array $d) { + return array_map(static function (array $d) { array_unshift($d[1], AbstractPostProcessorTestCase::getPostProcessAsStdInExecutable()); return $d; @@ -61,7 +61,7 @@ public static function provideProcessData(): array [['quant_table' => 4, 'optimise' => true, 'quality' => 100], '-quant-table 4 -optimise -quality 100'], ]; - return array_map(function ($d) use ($file) { + return array_map(static function ($d) use ($file) { array_unshift($d, $file); return $d; diff --git a/tests/Imagine/Filter/PostProcessor/OptiPngPostProcessorTest.php b/tests/Imagine/Filter/PostProcessor/OptiPngPostProcessorTest.php index 5b25bba83..6223073d0 100644 --- a/tests/Imagine/Filter/PostProcessor/OptiPngPostProcessorTest.php +++ b/tests/Imagine/Filter/PostProcessor/OptiPngPostProcessorTest.php @@ -65,7 +65,7 @@ public static function provideSetupProcessBuilderData(): array [['level' => 4, 'snip' => true, 'preserve_attributes' => true, 'interlace_type' => 1, 'no_bit_depth_reductions' => true, 'no_palette_reductions' => true], ['-o4', '-strip', 'all', '-snip', '-preserve', '-i', 1, '-nb', '-np']], ]; - return array_map(function (array $d) { + return array_map(static function (array $d) { array_unshift($d[1], AbstractPostProcessorTestCase::getPostProcessAsFileExecutable()); return $d; @@ -96,7 +96,7 @@ public static function provideProcessData(): array [['dithering' => 0.5], '--quality 80-100 --floyd 0.5'], ]; - return array_map(function ($d) use ($file) { + return array_map(static function ($d) use ($file) { array_unshift($d, $file); return $d; diff --git a/tests/Imagine/Filter/PostProcessor/PngquantPostProcessorTest.php b/tests/Imagine/Filter/PostProcessor/PngquantPostProcessorTest.php index 58fe98d2d..0663ddbdc 100644 --- a/tests/Imagine/Filter/PostProcessor/PngquantPostProcessorTest.php +++ b/tests/Imagine/Filter/PostProcessor/PngquantPostProcessorTest.php @@ -79,7 +79,7 @@ public static function provideProcessArgumentsData(): array [['dithering' => 0.5], ['80-100', '--floyd', 0.5]], ]; - return array_map(function (array $d) { + return array_map(static function (array $d) { array_unshift($d[1], '--quality'); array_unshift($d[1], AbstractPostProcessorTestCase::getPostProcessAsStdInExecutable()); @@ -111,7 +111,7 @@ public static function provideProcessData(): array [['dithering' => 0.5], '--quality 80-100 --floyd 0.5'], ]; - return array_map(function ($d) use ($file) { + return array_map(static function ($d) use ($file) { array_unshift($d, $file); return $d; From e2520f29fce8e7a988ad43a24cf73e35f5014b1c Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 19 Mar 2026 12:03:47 +0100 Subject: [PATCH 27/27] fix merge mistake in composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 215acbbbb..71f0de884 100644 --- a/composer.json +++ b/composer.json @@ -48,10 +48,10 @@ "symfony/browser-kit": "^6.4|^7.3|^8.0", "symfony/cache": "^6.4|^7.3|^8.0", "symfony/console": "^6.4|^7.3|^8.0", - "symfony/dependency-injection": "^6.4|^7.3|^8.0", "symfony/form": "^6.4|^7.3|^8.0", "symfony/messenger": "^6.4|^7.3|^8.0", "symfony/phpunit-bridge": "^7.3", + "symfony/runtime": "^6.4|^7.3|^8.0", "symfony/validator": "^6.4|^7.3|^8.0", "symfony/yaml": "^6.4|^7.3|^8.0" },