From 6c50b5170047eb1515f5dd524fac1d44ca525f15 Mon Sep 17 00:00:00 2001 From: Tac Tacelosky Date: Tue, 2 Jan 2024 11:06:54 -0600 Subject: [PATCH] remove unsupported dependencies * drop php templating * document to use DI instead of injecting the container * drop 8.0 from testing, add 8.3 * remove AmazonS3, use awsS3 instead * remove Symfony < 5 installation instructions --- .github/workflows/phpunit.yml | 36 +- .phpstan/iterable_types_baseline.neon | 10 - README.md | 80 ++--- composer.json | 48 ++- doc/cache-resolver/amazons3.rst | 144 -------- doc/cache-resolver/aws_s3.rst | 2 +- doc/cache-resolver/psr_cache.rst | 6 +- doc/installation.rst | 42 +-- phpunit.xml.dist | 67 ++-- .../Cache/Resolver/AmazonS3Resolver.php | 167 --------- .../Cache/Resolver/AmazonS3ResolverTest.php | 340 ------------------ 11 files changed, 93 insertions(+), 849 deletions(-) delete mode 100644 doc/cache-resolver/amazons3.rst delete mode 100644 src/Imagine/Cache/Resolver/AmazonS3Resolver.php delete mode 100644 tests/Imagine/Cache/Resolver/AmazonS3ResolverTest.php diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 64324ab2d..f5995ac0f 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -15,45 +15,45 @@ jobs: strategy: fail-fast: false matrix: - php: ['8.0', '8.1', '8.2'] + php: ['8.1', '8.2', '8.3'] dependencies: [highest] symfony: ['*'] stability: ['stable'] include: # Minimum supported dependencies with the oldest supported PHP version - - php: '8.0' + - php: '8.1' dependencies: lowest symfony: '*' stability: 'stable' # Minimum supported dependencies with the latest supported PHP version - - php: '8.2' + - php: '8.3' dependencies: lowest symfony: '*' stability: 'stable' # Test each supported Symfony version with the lowest supported PHP version - - php: '8.0' - dependencies: highest - symfony: '5.4.*' - stability: 'stable' - - php: '8.1' dependencies: highest symfony: '6.4.*' stability: 'stable' - # Test Symfony 6.4 dev version - php: '8.2' dependencies: highest - symfony: '6.4.*' - stability: 'dev' + symfony: '7.0.*' + stability: 'stable' - # Test Symfony 7.0 dev version - - php: '8.2' + - php: '8.3' dependencies: highest symfony: '7.0.*' + stability: 'stable' + + # Test Symfony 7.1 dev + - php: '8.2' + dependencies: highest + symfony: '7.1.*' stability: 'dev' + steps: - name: Checkout uses: actions/checkout@v4 @@ -76,19 +76,9 @@ jobs: 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 }} - # 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 - - name: Update project dependencies uses: ramsey/composer-install@v2 with: diff --git a/.phpstan/iterable_types_baseline.neon b/.phpstan/iterable_types_baseline.neon index 4a3be7cd8..379eeec80 100644 --- a/.phpstan/iterable_types_baseline.neon +++ b/.phpstan/iterable_types_baseline.neon @@ -280,16 +280,6 @@ parameters: count: 1 path: ../src/Imagine/Cache/CacheManager.php - - - message: "#^Method Liip\\\\ImagineBundle\\\\Imagine\\\\Cache\\\\Resolver\\\\AmazonS3Resolver\\:\\:__construct\\(\\) has parameter \\$objUrlOptions with no value type specified in iterable type array\\.$#" - count: 1 - path: ../src/Imagine/Cache/Resolver/AmazonS3Resolver.php - - - - message: "#^Property Liip\\\\ImagineBundle\\\\Imagine\\\\Cache\\\\Resolver\\\\AmazonS3Resolver\\:\\:\\$objUrlOptions type has no value type specified in iterable type array\\.$#" - count: 1 - path: ../src/Imagine/Cache/Resolver/AmazonS3Resolver.php - - message: "#^Method Liip\\\\ImagineBundle\\\\Imagine\\\\Cache\\\\Resolver\\\\AwsS3Resolver\\:\\:__construct\\(\\) has parameter \\$getOptions with no value type specified in iterable type array\\.$#" count: 1 diff --git a/README.md b/README.md index b6b52ab1e..d70cee5a8 100644 --- a/README.md +++ b/README.md @@ -115,8 +115,8 @@ our [data loaders](http://symfony.com/doc/current/bundles/LiipImagineBundle/data and [cache resolvers](http://symfony.com/doc/current/bundles/LiipImagineBundle/cache-resolvers.html) operate correctly. Use the following boilerplate in your configuration file. -```yml -# app/config/config.yml +```yaml +# config/packages/liip_imagine.yaml liip_imagine : @@ -149,7 +149,7 @@ name `my_thumb`) with two *filters* configured: the `thumbnail` and `background` *filters*. ```yml -# app/config/config.yml +# config/packages/liip_imagine.yaml liip_imagine : resolvers : @@ -193,18 +193,10 @@ There are a number of additional [filters](http://symfony.com/doc/current/bundle but for now you can use your newly defined ``my_thumb`` *filter set* immediately within a template. -*For Twig-based template, use:* - ```twig ``` -*Or, for PHP-based template, use:* - -```php - -``` - Behind the scenes, the bundle applies the filter(s) to the image on-the-fly when the first page request is served. The transformed image is then cached for subsequent requests. The final cached image path would be similar to @@ -217,7 +209,7 @@ rendered via the template helper. This is often caused by having images are rendered, it is strongly suggested to disable this option: ```yml -# app/config/config_dev.yml +# config/packages/web_profiler.yaml web_profiler : intercept_redirects : false @@ -226,37 +218,18 @@ web_profiler : ### Runtime Options -Sometime, you may have a filter defined that fulfills 99% of your usage -scenarios. Instead of defining a new filter for the erroneous 1% of cases, -you may instead choose to alter the behavior of a filter at runtime by +Sometime, you may may need to modify your filter at runtime. You can do so by passing the template helper an options array. -*For Twig-based template, use:* - ```twig {% set runtimeConfig = {"thumbnail": {"size": [50, 50] }} %} ``` -*Or, for PHP-based template, use:* - -```php - array( - "size" => array(50, 50) - ) -); -?> - - -``` - - ### Path Resolution -Sometime you need to resolve the image path returned by this bundle for a +Sometimes you need to resolve the image path returned by this bundle for a filtered image. This can easily be achieved using Symfony's console binary or programmatically from within a controller or other piece of code. @@ -268,7 +241,7 @@ You can resolve an image URL using the console command relative image paths (which must be separated by a space). ```bash -$ php bin/console liip:imagine:cache:resolve relative/path/to/image1.jpg relative/path/to/image2.jpg +php bin/console liip:imagine:cache:resolve relative/path/to/image1.jpg relative/path/to/image2.jpg ``` Additionally, you can use the ``--filter`` option to specify which filter @@ -276,7 +249,7 @@ you want to resolve for (if the ``--filter`` option is omitted, all available filters will be resolved). ```bash -$ php bin/console liip:imagine:cache:resolve relative/path/to/image1.jpg --filter=my_thumb +php bin/console liip:imagine:cache:resolve relative/path/to/image1.jpg --filter=my_thumb ``` @@ -288,24 +261,17 @@ have the service assigned to a variable called `$imagineCacheManager`, you would run: ```php -$imagineCacheManager->getBrowserPath('/relative/path/to/image.jpg', 'my_thumb'); -``` -Often, you need to perform this operation in a controller. Assuming your -controller inherits from the base Symfony controller, you can take advantage -of the inherited ``get`` method to request the ``liip_imagine.cache.manager`` -service, from which you can call ``getBrowserPath`` on a relative image -path to get its resolved location. +use Liip\ImagineBundle\Imagine\Cache\CacheManager; -```php -/** @var CacheManager */ -$imagineCacheManager = $this->get('liip_imagine.cache.manager'); +public function __construct(private CacheManager $imageCacheManager) { +} -/** @var string */ -$resolvedPath = $imagineCacheManager->getBrowserPath('/relative/path/to/image.jpg', 'my_thumb'); +public function doSomething() { + $this->imagineCacheManager->getBrowserPath('/relative/path/to/image.jpg', 'my_thumb'); +} ``` - ## Filters This bundle provides a set of built-in filters and you may easily @@ -317,21 +283,17 @@ from our documentation. ## Use as a Service If you need to use your defined "filter sets" from within your controller, you -can fetch this bundle's FilterService from the service container to do the heavy -lifting for you. +can inject the bundle's FilterService to do the heavy lifting for you. ```php container - ->get('liip_imagine.service.filter'); - // 1) Simple filter, OR $resourcePath = $imagine->getUrlOfFilteredImage('uploads/foo.jpg', 'my_thumb'); @@ -361,7 +323,7 @@ assets from. For many installations this will be sufficient, but sometime you may need to load images from other locations. To do this, you must set the `data_root` parameter in your configuration (often located at `app/config/config.yml`). -```yml +```yaml liip_imagine: loaders: default: @@ -372,7 +334,7 @@ liip_imagine: As of version `1.7.2` you can register multiple data root paths, and the file locator will search each for the requested file. -```yml +```yaml liip_imagine: loaders: default: diff --git a/composer.json b/composer.json index 2b6c5c590..2d7df025c 100644 --- a/composer.json +++ b/composer.json @@ -22,37 +22,35 @@ } }, "require": { - "php": "^8.0", + "php": "^8.1", "ext-mbstring": "*", "imagine/imagine": "^1.3.2", - "symfony/filesystem": "^5.3|^6.0|^7.0", - "symfony/finder": "^5.3|^6.0|^7.0", - "symfony/framework-bundle": "^5.3|^6.0|^7.0", - "symfony/mime": "^5.3|^6.0|^7.0", - "symfony/options-resolver": "^5.3|^6.0|^7.0", - "symfony/process": "^5.3|^6.0|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/options-resolver": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", "twig/twig": "^2.9|^3.0" }, "require-dev": { "ext-gd": "*", - "amazonwebservices/aws-sdk-for-php": "^1.0", - "aws/aws-sdk-php": "^2.4|^3.0", - "doctrine/persistence": "^1.3|^2.0", - "league/flysystem": "^1.0|^2.0|^3.0", + "aws/aws-sdk-php": "^3.0", + "doctrine/persistence": "^2.0", + "league/flysystem": "^3.0", "phpstan/phpstan": "^1.10", "phpstan/phpstan-symfony": "^1.0", - "psr/cache": "^1.0|^2.0|^3.0", - "psr/log": "^1.0", - "symfony/browser-kit": "^5.3|^6.0|^7.0", - "symfony/cache": "^5.3|^6.0|^7.0", - "symfony/console": "^5.3|^6.0|^7.0", - "symfony/dependency-injection": "^5.3|^6.0|^7.0", - "symfony/form": "^5.3|^6.0|^7.0", - "symfony/messenger": "^5.3|^6.0|^7.0", - "symfony/phpunit-bridge": "^5.3|^6.0|^7.0", - "symfony/templating": "^5.3|^6.0|^7.0", - "symfony/validator": "^5.3|^6.0|^7.0", - "symfony/yaml": "^5.3|^6.0|^7.0" + "psr/cache": "^3.0", + "psr/log": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/cache": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/phpunit-bridge": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" }, "suggest": { "ext-exif": "required to read EXIF metadata from images", @@ -61,14 +59,12 @@ "ext-imagick": "required to use imagick driver", "ext-mongodb": "required for mongodb components", "alcaeus/mongo-php-adapter": "required for mongodb components", - "amazonwebservices/aws-sdk-for-php": "required to use AWS version 1 cache resolver", "aws/aws-sdk-php": "required to use AWS version 2/3 cache resolver", "doctrine/mongodb-odm": "required to use mongodb-backed doctrine components", "league/flysystem": "required to use FlySystem data loader or cache resolver", "monolog/monolog": "A psr/log compatible logger is required to enable logging", "rokka/imagine-vips": "required to use 'vips' driver", - "symfony/messenger": "If you like to process images in background", - "symfony/templating": "required to use deprecated Templating component instead of Twig" + "symfony/messenger": "If you like to process images in background" }, "config": { "sort-packages": true diff --git a/doc/cache-resolver/amazons3.rst b/doc/cache-resolver/amazons3.rst deleted file mode 100644 index 3975b7e8f..000000000 --- a/doc/cache-resolver/amazons3.rst +++ /dev/null @@ -1,144 +0,0 @@ - -.. _cache-resolver-amazon-s3: - -Amazon S3 Resolver -================== - -The ``AmazonS3Resolver`` resolver enables cache resolution using the -``\AmazonS3`` storage API. - -Dependencies ------------- - -This cache resolver requires the `aws-sdk-php`_ library, which can be installed -by executing the following command in your project directory: - -.. code-block:: bash - - $ composer require aws/aws-sdk-php - -Configuration -------------- - -To begin, you must assign your Amazon key, secret, and bucket to their respective parameters. - -.. code-block:: yaml - - # app/config/config.yml or app/config/parameters.yml - - parameters: - amazon_s3.key: "your-aws-key" - amazon_s3.secret: "your-aws-secret" - amazon_s3.bucket: "your-bucket.example.com" - -.. note:: - - To not confuse the cache resolver, use the ``bucket.domain.tld`` notation. - Specifying the bucket in a path (``domain.tld/bucket``) does not work. - -Prerequisites -------------- - -Next, you must define the required services. - -.. code-block:: yaml - - # app/config/services.yml - - services: - - acme.imagine.cache.resolver.amazon_s3: - class: Liip\ImagineBundle\Imagine\Cache\Resolver\AmazonS3Resolver - arguments: - - "@acme.amazon_s3" - - "%amazon_s3.bucket%" - tags: - - { name: "liip_imagine.cache.resolver", resolver: "amazon_s3" } - - acme.amazon_s3: - class: AmazonS3 - arguments: - - - key: "%amazon_s3.key%" - secret: "%amazon_s3.secret%" - -Usage ------ - -After configuring ``AmazonS3Resolver``, you can set it as the default cache resolver -for ``LiipImagineBundle`` using the following configuration. - -.. code-block:: yaml - - # app/config/config.yml - - liip_imagine: - cache: amazon_s3 - - -Usage on a Specific Filter -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Alternatively, you can set ``AmazonS3Resolver`` as the cache resolver for a specific -filter set using the following configuration. - -.. code-block:: yaml - - # app/config/config.yml - - liip_imagine: - filter_sets: - cache: ~ - my_thumb: - cache: amazon_s3 - filters: - # the filter list - -.. tip:: - - If you want to use other buckets for other images, simply alter the parameter - names and create additional services. - - -Object URL Options ------------------- - -In order to make use of the object URL options, you can simply add a call to the -service, to alter those options you need. - -.. code-block:: yaml - - # app/config/services.yml - - services: - acme.imagine.cache.resolver.amazon_s3: - class: Liip\ImagineBundle\Imagine\Cache\Resolver\AmazonS3Resolver - arguments: - - "@acme.amazon_s3" - - "%amazon_s3.bucket%" - calls: - # This calls $service->setObjectUrlOption('https', true); - - [ setObjectUrlOption, [ 'https', true ] ] - tags: - - { name: "liip_imagine.cache.resolver", resolver: "amazon_s3" } - -You can also use the constructor of the resolver to directly inject multiple -options. - -.. code-block:: yaml - - # app/config/services.yml - - services: - acme.imagine.cache.resolver.amazon_s3: - class: Liip\ImagineBundle\Imagine\Cache\Resolver\AmazonS3Resolver - arguments: - - "@acme.amazon_s3" - - "%amazon_s3.bucket%" - - "public-read" # AmazonS3::ACL_PUBLIC (default) - - { https: true, torrent: true } - tags: - - { name: "liip_imagine.cache.resolver", resolver: "amazon_s3" } - - -.. _`aws-sdk-php`: https://github.com/amazonwebservices/aws-sdk-for-php diff --git a/doc/cache-resolver/aws_s3.rst b/doc/cache-resolver/aws_s3.rst index b9f99f57a..5b32ae309 100644 --- a/doc/cache-resolver/aws_s3.rst +++ b/doc/cache-resolver/aws_s3.rst @@ -167,7 +167,7 @@ for ``LiipImagineBundle`` using the following configuration: Usage on a Specific Filter ~~~~~~~~~~~~~~~~~~~~~~~~~~ -Alternatively, you can set ``AmazonS3Resolver`` as the cache resolver for a specific +Alternatively, you can set ``AwsS3Resolver`` as the cache resolver for a specific filter set using the following configuration. .. code-block:: yaml diff --git a/doc/cache-resolver/psr_cache.rst b/doc/cache-resolver/psr_cache.rst index ab04a5e9e..1c4b4c699 100644 --- a/doc/cache-resolver/psr_cache.rst +++ b/doc/cache-resolver/psr_cache.rst @@ -16,9 +16,9 @@ Dependencies This cache resolver requires a PSR-6 implementation, e.g. `symfony/cache`, which can be installed by executing the following command in your project directory: -.. code-block:: bash - - $ composer require symfony/cache +```bash +composer require symfony/cache +``` Configuration ------------- diff --git a/doc/installation.rst b/doc/installation.rst index 86765d98f..d42894ef4 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -10,10 +10,10 @@ Open a command console, enter your project directory, and execute the following command to download the latest stable version of this bundle and add it as a dependency to your project: -.. code-block:: bash +```bash +composer require liip/imagine-bundle +``` - composer require liip/imagine-bundle - If you accept the Symfony Flex recipe during installation, the bundle is registered, routing set up and the configuration skeleton file is created. You can now adapt the configuration to your needs. @@ -21,46 +21,16 @@ Otherwise, you need to configure the bundle with the next steps. Step 2: Enable the Bundle ------------------------- - -Then, enable the bundle by adding ``new Liip\ImagineBundle\LiipImagineBundle()`` -to the bundles array of the ``registerBundles`` method in your project's -``app/AppKernel.php`` file: - -.. code-block:: php - - ['all' => true] ]; diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b30f16d72..0f21e702a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,42 +1,29 @@ - - - - - - ./tests - - - - - - ./src - - ./src/Resources - - - - - - - - - - - - - - - - - - + + + + ./src + + + ./src/Resources + + + + + + + + ./tests + + + + + + + + + + + + diff --git a/src/Imagine/Cache/Resolver/AmazonS3Resolver.php b/src/Imagine/Cache/Resolver/AmazonS3Resolver.php deleted file mode 100644 index 5d1bee0f0..000000000 --- a/src/Imagine/Cache/Resolver/AmazonS3Resolver.php +++ /dev/null @@ -1,167 +0,0 @@ -storage = $storage; - $this->bucket = $bucket; - $this->acl = $acl; - $this->objUrlOptions = $objUrlOptions; - } - - public function setLogger(LoggerInterface $logger): void - { - $this->logger = $logger; - } - - public function isStored(string $path, string $filter): bool - { - return $this->objectExists($this->getObjectPath($path, $filter)); - } - - public function resolve(string $path, string $filter): string - { - return $this->getObjectUrl($this->getObjectPath($path, $filter)); - } - - public function store(BinaryInterface $binary, string $path, string $filter): void - { - $objectPath = $this->getObjectPath($path, $filter); - - $storageResponse = $this->storage->create_object($this->bucket, $objectPath, [ - 'body' => $binary->getContent(), - 'contentType' => $binary->getMimeType(), - 'length' => mb_strlen($binary->getContent()), - 'acl' => $this->acl, - ]); - - if (!$storageResponse->isOK()) { - $this->logger?->error('The object could not be created on Amazon S3.', [ - 'objectPath' => $objectPath, - 'filter' => $filter, - 's3_response' => $storageResponse, - ]); - - throw new NotStorableException('The object could not be created on Amazon S3.'); - } - } - - public function remove(array $paths, array $filters): void - { - if (empty($paths) && empty($filters)) { - return; - } - - if (empty($paths)) { - if (!$this->storage->delete_all_objects($this->bucket, sprintf('/%s/i', implode('|', $filters)))) { - $this->logger?->error('The objects could not be deleted from Amazon S3.', [ - 'filters' => implode(', ', $filters), - 'bucket' => $this->bucket, - ]); - } - - return; - } - - foreach ($filters as $filter) { - foreach ($paths as $path) { - $objectPath = $this->getObjectPath($path, $filter); - if (!$this->objectExists($objectPath)) { - continue; - } - - if (!$this->storage->delete_object($this->bucket, $objectPath)->isOK()) { - $this->logger?->error('The objects could not be deleted from Amazon S3.', [ - 'filter' => $filter, - 'bucket' => $this->bucket, - 'path' => $path, - ]); - } - } - } - } - - /** - * Sets a single option to be passed when retrieving an objects URL. - * - * If the option is already set, it will be overwritten. - * - * @param string $key The name of the option - * @param mixed $value The value to be set - * - * @return AmazonS3Resolver $this - * - * @see \AmazonS3::get_object_url() for available options - */ - public function setObjectUrlOption(string $key, $value): self - { - $this->objUrlOptions[$key] = $value; - - return $this; - } - - /** - * Returns the object path within the bucket. - * - * @param string $path The base path of the resource - * @param string $filter The name of the imagine filter in effect - * - * @return string The path of the object on S3 - */ - protected function getObjectPath(string $path, string $filter): string - { - return str_replace('//', '/', $filter.'/'.$path); - } - - /** - * Returns the URL for an object saved on Amazon S3. - */ - protected function getObjectUrl(string $path): string - { - return $this->storage->get_object_url($this->bucket, $path, 0, $this->objUrlOptions); - } - - /** - * Checks whether an object exists. - * - * @throws \S3_Exception - */ - protected function objectExists(string $objectPath): bool - { - return $this->storage->if_object_exists($this->bucket, $objectPath); - } -} diff --git a/tests/Imagine/Cache/Resolver/AmazonS3ResolverTest.php b/tests/Imagine/Cache/Resolver/AmazonS3ResolverTest.php deleted file mode 100644 index 66a6eea72..000000000 --- a/tests/Imagine/Cache/Resolver/AmazonS3ResolverTest.php +++ /dev/null @@ -1,340 +0,0 @@ -assertTrue($rc->implementsInterface(ResolverInterface::class)); - } - - public function testNoDoubleSlashesInObjectUrlOnResolve(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('get_object_url') - ->with('images.example.com', 'thumb/some-folder/path.jpg') - ->willReturn('http://images.example.com/some-folder/path.jpg'); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->resolve('/some-folder/path.jpg', 'thumb'); - } - - public function testObjUrlOptionsPassedToAmazonOnResolve(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('get_object_url') - ->with('images.example.com', 'thumb/some-folder/path.jpg', 0, ['torrent' => true]) - ->willReturn('http://images.example.com/some-folder/path.jpg'); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->setObjectUrlOption('torrent', true); - $resolver->resolve('/some-folder/path.jpg', 'thumb'); - } - - public function testThrowsAndLogIfCanNotCreateObjectOnAmazon(): void - { - $this->expectException(\Liip\ImagineBundle\Exception\Imagine\Cache\Resolver\NotStorableException::class); - $this->expectExceptionMessage('The object could not be created on Amazon S3'); - - $binary = new Binary('aContent', 'image/jpeg', 'jpeg'); - - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('create_object') - ->willReturn($this->createCFResponseMock(false)); - - $logger = $this->createLoggerInterfaceMock(); - $logger - ->expects($this->once()) - ->method('error'); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->setLogger($logger); - $resolver->store($binary, 'foobar.jpg', 'thumb'); - } - - public function testCreatedObjectOnAmazon(): void - { - $binary = new Binary('aContent', 'image/jpeg', 'jpeg'); - - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('create_object') - ->willReturn($this->createCFResponseMock(true)); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->store($binary, 'foobar.jpg', 'thumb'); - } - - public function testIsStoredChecksObjectExistence(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('if_object_exists') - ->willReturn(false); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - - $this->assertFalse($resolver->isStored('/some-folder/path.jpg', 'thumb')); - } - - public function testReturnResolvedImageUrlOnResolve(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('get_object_url') - ->with('images.example.com', 'thumb/some-folder/path.jpg', 0, []) - ->willReturn('http://images.example.com/some-folder/path.jpg'); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - - $this->assertSame( - 'http://images.example.com/some-folder/path.jpg', - $resolver->resolve('/some-folder/path.jpg', 'thumb') - ); - } - - public function testDoNothingIfFiltersAndPathsEmptyOnRemove(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->never()) - ->method('if_object_exists'); - $s3 - ->expects($this->never()) - ->method('delete_object'); - $s3 - ->expects($this->never()) - ->method('delete_all_objects'); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->remove([], []); - } - - public function testRemoveCacheForPathAndFilterOnRemove(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('if_object_exists') - ->with('images.example.com', 'thumb/some-folder/path.jpg') - ->willReturn(true); - $s3 - ->expects($this->once()) - ->method('delete_object') - ->with('images.example.com', 'thumb/some-folder/path.jpg') - ->willReturn($this->createCFResponseMock(true)); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->remove(['some-folder/path.jpg'], ['thumb']); - } - - public function testRemoveCacheForSomePathsAndFilterOnRemove(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->method('if_object_exists') - ->withConsecutive( - ['images.example.com', 'filter/pathOne.jpg'], - ['images.example.com', 'filter/pathTwo.jpg'] - ) - ->willReturn(true); - $s3 - ->method('delete_object') - ->withConsecutive( - ['images.example.com', 'filter/pathOne.jpg'], - ['images.example.com', 'filter/pathTwo.jpg'] - ) - ->willReturnOnConsecutiveCalls( - $this->createCFResponseMock(true), - $this->createCFResponseMock(true) - ); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->remove(['pathOne.jpg', 'pathTwo.jpg'], ['filter']); - } - - public function testRemoveCacheForSomePathsAndSomeFiltersOnRemove(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->method('if_object_exists') - ->withConsecutive( - ['images.example.com', 'filterOne/pathOne.jpg'], - ['images.example.com', 'filterOne/pathTwo.jpg'], - ['images.example.com', 'filterTwo/pathOne.jpg'], - ['images.example.com', 'filterTwo/pathTwo.jpg'] - ) - ->willReturn(true); - $s3 - ->method('delete_object') - ->withConsecutive( - ['images.example.com', 'filterOne/pathOne.jpg'], - ['images.example.com', 'filterOne/pathTwo.jpg'], - ['images.example.com', 'filterTwo/pathOne.jpg'], - ['images.example.com', 'filterTwo/pathTwo.jpg'] - ) - ->willReturnOnConsecutiveCalls( - $this->createCFResponseMock(true), - $this->createCFResponseMock(true), - $this->createCFResponseMock(true), - $this->createCFResponseMock(true) - ); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->remove( - ['pathOne.jpg', 'pathTwo.jpg'], - ['filterOne', 'filterTwo'] - ); - } - - public function testDoNothingWhenObjectNotExistForPathAndFilterOnRemove(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('if_object_exists') - ->with('images.example.com', 'filter/path.jpg') - ->willReturn(false); - $s3 - ->expects($this->never()) - ->method('delete_object'); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->remove(['path.jpg'], ['filter']); - } - - public function testLogIfNotDeletedForPathAndFilterOnRemove(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('if_object_exists') - ->with('images.example.com', 'filter/path.jpg') - ->willReturn(true); - $s3 - ->expects($this->once()) - ->method('delete_object') - ->willReturn($this->createCFResponseMock(false)); - - $logger = $this->createLoggerInterfaceMock(); - $logger - ->expects($this->once()) - ->method('error'); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->setLogger($logger); - $resolver->remove(['path.jpg'], ['filter']); - } - - public function testRemoveCacheForFilterOnRemove(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('delete_all_objects') - ->with('images.example.com', '/filter/i') - ->willReturn(true); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->remove([], ['filter']); - } - - public function testRemoveCacheForSomeFiltersOnRemove(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('delete_all_objects') - ->with('images.example.com', '/filterOne|filterTwo/i') - ->willReturn(true); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->remove([], ['filterOne', 'filterTwo']); - } - - public function testLogIfBatchNotDeletedForFilterOnRemove(): void - { - $s3 = $this->createAmazonS3Mock(); - $s3 - ->expects($this->once()) - ->method('delete_all_objects') - ->with('images.example.com', '/filter/i') - ->willReturn(false); - - $logger = $this->createLoggerInterfaceMock(); - $logger - ->expects($this->once()) - ->method('error'); - - $resolver = new AmazonS3Resolver($s3, 'images.example.com'); - $resolver->setLogger($logger); - $resolver->remove([], ['filter']); - } - - /** - * @return MockObject&\CFResponse - */ - protected function createCFResponseMock(bool $ok) - { - $s3Response = $this->createObjectMock(\CFResponse::class, ['isOK'], false); - $s3Response - ->expects($this->once()) - ->method('isOK') - ->willReturn($ok); - - return $s3Response; - } - - /** - * @return MockObject&\AmazonS3 - */ - protected function createAmazonS3Mock() - { - if (!class_exists(\AmazonS3::class)) { - $this->markTestSkipped('Requires the amazonwebservices/aws-sdk-for-php package.'); - } - - return $this - ->getMockBuilder(\AmazonS3::class) - ->disableOriginalConstructor() - ->setMethods([ - 'if_object_exists', - 'create_object', - 'get_object_url', - 'delete_object', - 'delete_all_objects', - 'authenticate', - ]) - ->getMock(); - } -}