diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index 2e3b80895..c39befb41 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -10,10 +10,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 442029c2f..cd433ffb3 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -10,10 +10,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 @@ -27,5 +27,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 f5995ac0f..082e33a6d 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -11,52 +11,44 @@ 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: php: ['8.1', '8.2', '8.3'] dependencies: [highest] symfony: ['*'] - stability: ['stable'] include: # Minimum supported dependencies with the oldest supported PHP version - php: '8.1' dependencies: lowest symfony: '*' - stability: 'stable' # Minimum supported dependencies with the latest supported PHP version - - php: '8.3' + - php: '8.5' dependencies: lowest symfony: '*' - stability: 'stable' # Test each supported Symfony version with the lowest supported PHP version - php: '8.1' dependencies: highest symfony: '6.4.*' - stability: 'stable' - php: '8.2' dependencies: highest symfony: '7.0.*' - stability: 'stable' - php: '8.3' dependencies: highest symfony: '7.0.*' - stability: 'stable' - # Test Symfony 7.1 dev - - php: '8.2' + - php: '8.4' dependencies: highest - symfony: '7.1.*' - stability: 'dev' + symfony: '8.0.*' steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Configure coverage driver id: coverage @@ -69,8 +61,7 @@ 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 @@ -84,6 +75,9 @@ jobs: with: dependency-versions: ${{ matrix.dependencies }} + - name: Lint container + run: ./Tests/Functional/app/bin/console lint:container + - name: Cache PHPUnit uses: actions/cache@v3 with: @@ -114,7 +108,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 diff --git a/CHANGELOG.md b/CHANGELOG.md index e128fe1d0..b03d5afbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,35 @@ 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 +## [2.17.1](https://github.com/liip/LiipImagineBundle/tree/2.17.1) + +- 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) + +- 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) + +- 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.15.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)) +- 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) - 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/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 +`, then :ref:`Proxy ` and after all process delegates to AwsS3 resolver. diff --git a/doc/configuration.rst b/doc/configuration.rst index ae5132d51..1c9a87cfb 100644 --- a/doc/configuration.rst +++ b/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 ``lazy``. The twig filter automatically picks up the ``framework.assets.version`` configuration. You can @@ -97,7 +98,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/phpunit.xml.dist b/phpunit.xml.dist index 0f21e702a..b55efb217 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -22,6 +22,7 @@ + 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/Controller/ImagineController.php b/src/Controller/ImagineController.php index 21b3257e7..8932e03f6 100644 --- a/src/Controller/ImagineController.php +++ b/src/Controller/ImagineController.php @@ -59,7 +59,7 @@ public function __construct( public function filterAction(Request $request, string $path, string $filter): RedirectResponse { $path = PathHelper::urlPathToFilePath($path); - $resolver = $request->get('resolver'); + $resolver = $request->query->has('resolver') ? $request->query->getString('resolver') : null; return $this->createRedirectResponse(function () use ($path, $filter, $resolver, $request) { return $this->filterService->getUrlOfFilteredImage( @@ -84,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->get('resolver'); + $resolver = $request->query->has('resolver') ? $request->query->getString('resolver') : null; $path = PathHelper::urlPathToFilePath($path); $runtimeConfig = $request->query->all('filters'); 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 8279034b2..aca03a470 100644 --- a/src/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php +++ b/src/DependencyInjection/Factory/Resolver/AwsS3ResolverFactory.php @@ -13,6 +13,8 @@ use Aws\S3\S3Client; 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; @@ -22,10 +24,15 @@ class AwsS3ResolverFactory extends AbstractResolverFactory public function create(ContainerBuilder $container, string $name, array $config): string { $awsS3ClientId = 'liip_imagine.cache.resolver.'.$name.'.client'; - $awsS3ClientDefinition = new Definition(S3Client::class); - $awsS3ClientDefinition->setFactory([S3Client::class, '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(S3Client::class)) + ->setFactory([S3Client::class, 'factory']) + ->addArgument($config['client_config']) + ); + } $resolverDefinition = $this->getChildResolverDefinition(); $resolverDefinition->replaceArgument(0, new Reference($awsS3ClientId)); @@ -58,7 +65,7 @@ public function create(ContainerBuilder $container, string $name, array $config) $container->setDefinition($cachedResolverId, $container->getDefinition($resolverId)); - $cacheResolverDefinition = $this->getChildResolverDefinition('cache'); + $cacheResolverDefinition = $this->getChildResolverDefinition('psr_cache'); $cacheResolverDefinition->replaceArgument(0, new Reference($config['cache'])); $cacheResolverDefinition->replaceArgument(1, new Reference($cachedResolverId)); @@ -86,15 +93,17 @@ public function addConfiguration(ArrayNodeDefinition $builder): void ->cannotBeEmpty() ->end() ->scalarNode('cache') - ->defaultValue(false) + ->defaultFalse() ->end() ->scalarNode('acl') ->defaultValue('public-read') - ->cannotBeEmpty() ->end() ->scalarNode('cache_prefix') ->defaultValue('') ->end() + ->scalarNode('client_id') + ->defaultNull() + ->end() ->arrayNode('client_config') ->isRequired() ->prototype('variable') @@ -117,6 +126,24 @@ public function addConfiguration(ArrayNodeDefinition $builder): void ->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(static function ($config) { + $config['client_config'] = []; + + return $config; + }) ->end(); } } diff --git a/src/DependencyInjection/LiipImagineExtension.php b/src/DependencyInjection/LiipImagineExtension.php index 0328b1db8..25d0358dd 100644 --- a/src/DependencyInjection/LiipImagineExtension.php +++ b/src/DependencyInjection/LiipImagineExtension.php @@ -20,12 +20,13 @@ 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\Exception\LogicException; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; +use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\Messenger\MessageBusInterface; class LiipImagineExtension extends Extension implements PrependExtensionInterface @@ -68,14 +69,14 @@ public function load(array $configs, ContainerBuilder $container): void $this->loadResolvers($config['resolvers'], $container); $this->loadLoaders($config['loaders'], $container); - $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); - $loader->load('imagine.xml'); + $loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('imagine.php'); if ('none' !== $config['twig']['mode']) { $this->loadTwig($config['twig'], $loader, $container); } - $loader->load('commands.xml'); + $loader->load('commands.php'); if ($this->isConfigEnabled($container, $config['messenger'])) { $this->registerMessengerConfiguration($loader); @@ -89,7 +90,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}"); @@ -130,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); } @@ -152,19 +153,19 @@ 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'); + $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 ('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/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/AwsS3Resolver.php b/src/Imagine/Cache/Resolver/AwsS3Resolver.php index ce8e2ae54..59f01f528 100644 --- a/src/Imagine/Cache/Resolver/AwsS3Resolver.php +++ b/src/Imagine/Cache/Resolver/AwsS3Resolver.php @@ -44,11 +44,11 @@ class AwsS3Resolver implements ResolverInterface * @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; - $this->acl = $acl; + $this->acl = $acl ?? ''; $this->getOptions = $getOptions; $this->putOptions = $putOptions; } @@ -76,20 +76,19 @@ public function resolve(string $path, string $filter): string public function store(BinaryInterface $binary, string $path, string $filter): void { $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->logger?->error('The object could not be created on Amazon S3.', [ 'objectPath' => $objectPath, 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/Data/DataManager.php b/src/Imagine/Data/DataManager.php index 2c4736b2d..d518acdc9 100644 --- a/src/Imagine/Data/DataManager.php +++ b/src/Imagine/Data/DataManager.php @@ -69,7 +69,7 @@ public function getLoader(string $filter): LoaderInterface $loaderName = empty($config['data_loader']) ? $this->defaultLoader : $config['data_loader']; - if (!\array_key_exists($loaderName, $this->loaders)) { + 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/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/LiipImagineBundle.php b/src/LiipImagineBundle.php index 2d3ef5150..0fdc59f25 100644 --- a/src/LiipImagineBundle.php +++ b/src/LiipImagineBundle.php @@ -19,6 +19,7 @@ use Liip\ImagineBundle\DependencyInjection\Compiler\MetadataReaderCompilerPass; 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; @@ -57,6 +58,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/src/Resources/config/commands.php b/src/Resources/config/commands.php new file mode 100644 index 000000000..3da1e7d0f --- /dev/null +++ b/src/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/src/Resources/config/commands.xml b/src/Resources/config/commands.xml deleted file mode 100644 index 4b8fac819..000000000 --- a/src/Resources/config/commands.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Resources/config/imagine.php b/src/Resources/config/imagine.php new file mode 100644 index 000000000..4af23d4b3 --- /dev/null +++ b/src/Resources/config/imagine.php @@ -0,0 +1,583 @@ +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.asset_mapper', AssetMapperLocator::class) + ->abstract() + ->private() + ->args([ + '', // will be injected by AssetMapperLoaderFactory + ]) + ->tag('liip_imagine.binary.locator', ['shared' => true]); + + $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/src/Resources/config/imagine.xml b/src/Resources/config/imagine.xml deleted file mode 100644 index dffd23f9b..000000000 --- a/src/Resources/config/imagine.xml +++ /dev/null @@ -1,440 +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.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% - - - - - diff --git a/src/Resources/config/imagine_twig_mode_lazy.php b/src/Resources/config/imagine_twig_mode_lazy.php new file mode 100644 index 000000000..eb5718853 --- /dev/null +++ b/src/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/src/Resources/config/imagine_twig_mode_lazy.xml b/src/Resources/config/imagine_twig_mode_lazy.xml deleted file mode 100644 index ac9ec6f19..000000000 --- a/src/Resources/config/imagine_twig_mode_lazy.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - null - null - - - - diff --git a/src/Resources/config/imagine_vips.php b/src/Resources/config/imagine_vips.php new file mode 100644 index 000000000..c9b874430 --- /dev/null +++ b/src/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/src/Resources/config/imagine_vips.xml b/src/Resources/config/imagine_vips.xml deleted file mode 100644 index de460af51..000000000 --- a/src/Resources/config/imagine_vips.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/Resources/config/messenger.php b/src/Resources/config/messenger.php new file mode 100644 index 000000000..fdbc7b730 --- /dev/null +++ b/src/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/src/Resources/config/messenger.xml b/src/Resources/config/messenger.xml deleted file mode 100644 index f88874d00..000000000 --- a/src/Resources/config/messenger.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - 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 48e6b7dbf..b5301948d 100644 --- a/tests/Binary/Locator/FileSystemLocatorTest.php +++ b/tests/Binary/Locator/FileSystemLocatorTest.php @@ -23,7 +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'); - $roots->setAccessible(true); $array = [ '', '', @@ -84,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/Controller/ImagineControllerTest.php b/tests/Controller/ImagineControllerTest.php index b78194ec3..487ff0627 100644 --- a/tests/Controller/ImagineControllerTest.php +++ b/tests/Controller/ImagineControllerTest.php @@ -77,9 +77,9 @@ public function testInvalidRedirectResponseCode(int $redirectResponseCode): void { $this->expectException(InvalidArgumentException::class); $this->createControllerInstance( - $path = '/foo', - $filter = 'filter', - $hash = 'hash', + '/foo', + 'filter', + 'hash', $redirectResponseCode, false ); diff --git a/tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php b/tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php index f4256b9ed..a7c9fc696 100644 --- a/tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php +++ b/tests/DependencyInjection/Compiler/MetadataReaderCompilerPassTest.php @@ -76,7 +76,6 @@ public function testDoesNotOverrideCustomReaderWhenExifNotAvailable(): void private static function getVisibilityRestrictedStaticProperty(\ReflectionClass $r, string $p): string { $property = $r->getProperty($p); - $property->setAccessible(true); return $property->getValue(); } diff --git a/tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php b/tests/DependencyInjection/Factory/Resolver/AwsS3ResolverFactoryTest.php index c988a6d07..dd603929e 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); @@ -54,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', @@ -85,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', @@ -108,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', @@ -121,110 +127,93 @@ public function testCreateS3ClientDefinitionWithFactoryOnCreate(): void $this->assertSame([S3Client::class, 'factory'], $clientDefinition->getFactory()); } - public function testWrapResolverWithProxyOnCreateWithoutCache(): void + 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' => ['foo'], + 'proxies' => [], ]); - $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->hasAlias('liip_imagine.cache.resolver.the_resolver_name.client')); - $this->assertFalse($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name.cached')); - - $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.proxy', $resolverDefinition->getParent()); - - $this->assertInstanceOf(Reference::class, $resolverDefinition->getArgument(0)); - $this->assertSame('liip_imagine.cache.resolver.the_resolver_name.proxied', (string) $resolverDefinition->getArgument(0)); - - $this->assertSame(['foo'], $resolverDefinition->getArgument(1)); + $clientAlias = $container->getAlias('liip_imagine.cache.resolver.the_resolver_name.client'); + $this->assertSame('s3.client.default', (string) $clientAlias); } - public function testWrapResolverWithCacheOnCreateWithoutProxy(): void + public function testWrapResolverWithProxyOnCreateWithoutCache(): void { $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', - 'proxies' => [], + 'cache' => false, + 'proxies' => ['foo'], ]); - $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->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->assertFalse($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name.proxied')); + $this->assertFalse($container->hasDefinition('liip_imagine.cache.resolver.the_resolver_name.cached')); $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->assertSame('liip_imagine.cache.resolver.prototype.proxy', $resolverDefinition->getParent()); $this->assertInstanceOf(Reference::class, $resolverDefinition->getArgument(0)); - $this->assertSame('the_cache_service_id', (string) $resolverDefinition->getArgument(0)); + $this->assertSame('liip_imagine.cache.resolver.the_resolver_name.proxied', (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)); + $this->assertSame(['foo'], $resolverDefinition->getArgument(1)); } - public function testWrapResolverWithProxyAndCacheOnCreate(): void + public function testWrapResolverWithPsrCacheOnCreateWithoutProxy(): void { $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', - 'proxies' => ['foo'], + 'use_psr_cache' => true, + 'proxies' => [], ]); - $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('liip_imagine.cache.resolver.prototype.aws_s3', $cachedResolverDefinition->getParent()); - $this->assertSame(['foo'], $cachedResolverDefinition->getArgument(1)); + $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->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)); @@ -240,6 +229,7 @@ public function testSetCachePrefixIfDefined(): void $resolver = new AwsS3ResolverFactory(); $resolver->create($container, 'the_resolver_name', [ + 'client_id' => null, 'client_config' => [], 'bucket' => 'aBucket', 'acl' => 'aAcl', @@ -305,6 +295,26 @@ 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 = $treeBuilder->getRootNode(); + + $resolver = new AwsS3ResolverFactory(); + $resolver->addConfiguration($rootNode); + + $this->processConfigTree($treeBuilder, [ + 'aws_s3' => [ + 'bucket' => 'aBucket', + 'client_id' => 'aClientId', + 'client_config' => [], + ], + ]); + } + public function testProcessCorrectlyOptionsOnAddConfiguration(): void { $expectedClientConfig = [ 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/Functional/AbstractWebTestCase.php b/tests/Functional/AbstractWebTestCase.php index a6ac18de1..e01885126 100644 --- a/tests/Functional/AbstractWebTestCase.php +++ b/tests/Functional/AbstractWebTestCase.php @@ -36,9 +36,7 @@ protected function getParameter(string $name) protected function getPrivateProperty(object $object, string $name) { $r = new \ReflectionObject($object); - $p = $r->getProperty($name); - $p->setAccessible(true); return $p->getValue($object); } diff --git a/tests/Functional/Controller/ImagineControllerTest.php b/tests/Functional/Controller/ImagineControllerTest.php index 0043b7b32..1b707ffd2 100644 --- a/tests/Functional/Controller/ImagineControllerTest.php +++ b/tests/Functional/Controller/ImagineControllerTest.php @@ -39,7 +39,6 @@ protected function setUp(): void if ($this->webp_generate) { $filterService = $this->getService('test.liip_imagine.service.filter'); $webpGenerate = new \ReflectionProperty($filterService, 'webpGenerate'); - $webpGenerate->setAccessible(true); $webpGenerate->setValue($filterService, true); } } 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/Cache/Resolver/WebPathResolverTest.php b/tests/Imagine/Cache/Resolver/WebPathResolverTest.php index 998dfe1f1..f6687d24c 100644 --- a/tests/Imagine/Cache/Resolver/WebPathResolverTest.php +++ b/tests/Imagine/Cache/Resolver/WebPathResolverTest.php @@ -461,7 +461,6 @@ public function testShouldRemoveDoubleSlashInUrl(): void $rc = new \ReflectionClass($resolver); $method = $rc->getMethod('getFileUrl'); - $method->setAccessible(true); $result = $method->invokeArgs($resolver, ['/cats.jpg', 'some_filter']); @@ -479,7 +478,6 @@ public function testShouldSanitizeSeparatorBetweenSchemeAndAuthorityInUrl(): voi $rc = new \ReflectionClass($resolver); $method = $rc->getMethod('getFileUrl'); - $method->setAccessible(true); $result = $method->invokeArgs($resolver, ['https://some.meme.com/cute/cats.jpg', 'some_filter']); @@ -493,9 +491,7 @@ public static function assertAttributeSame($expected, string $actualAttributeNam { $reflector = new \ReflectionObject($actualClassOrObject); $attribute = $reflector->getProperty($actualAttributeName); - $attribute->setAccessible(true); $actual = $attribute->getValue($actualClassOrObject); - $attribute->setAccessible(false); self::assertSame($expected, $actual, $message); } 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/AbstractPostProcessorTestCase.php b/tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php index 16193eedb..8e1c3234d 100644 --- a/tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php +++ b/tests/Imagine/Filter/PostProcessor/AbstractPostProcessorTestCase.php @@ -60,7 +60,6 @@ protected function getProtectedReflectionMethodVisible($object, string $method): } $m = $r->getMethod($method); - $m->setAccessible(true); return $m; } @@ -77,7 +76,6 @@ protected function getProtectedReflectionPropertyVisible($object, string $proper } $p = $r->getProperty($property); - $p->setAccessible(true); return $p; } 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; diff --git a/tests/LiipImagineBundleTest.php b/tests/LiipImagineBundleTest.php index ec8486c90..fa9b09565 100644 --- a/tests/LiipImagineBundleTest.php +++ b/tests/LiipImagineBundleTest.php @@ -18,6 +18,7 @@ use Liip\ImagineBundle\DependencyInjection\Compiler\MetadataReaderCompilerPass; 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; @@ -146,6 +147,7 @@ public function testAddLoaders(): void StreamLoaderFactory::class, FileSystemLoaderFactory::class, FlysystemLoaderFactory::class, + AssetMapperLoaderFactory::class, ChainLoaderFactory::class, ], $loaders); }