diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 7d6f61a..c4604b9 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -22,8 +22,6 @@ jobs: fail-fast: false matrix: php-version: - - 8.1 - - 8.2 - 8.3 - 8.4 dependencies: @@ -31,27 +29,7 @@ jobs: symfony_version: - "" include: - # Test against latest Symfony 5.4 - - symfony_version: "5.4.*" - php-version: "8.1" - dependencies: "highest" - - symfony_version: "5.4.*" - php-version: "8.2" - dependencies: "highest" - - symfony_version: "5.4.*" - php-version: "8.3" - dependencies: "highest" - - symfony_version: "5.4.*" - php-version: "8.4" - dependencies: "highest" - # Test against latest Symfony 6.4 - - symfony_version: "6.4.*" - php-version: "8.1" - dependencies: "highest" - - symfony_version: "6.4.*" - php-version: "8.2" - dependencies: "highest" - symfony_version: "6.4.*" php-version: "8.3" dependencies: "highest" @@ -60,10 +38,6 @@ jobs: dependencies: "highest" # Test against the highest dependencies - - php-version: "8.1" - dependencies: "highest" - - php-version: "8.2" - dependencies: "highest" - php-version: "8.3" dependencies: "highest" - php-version: "8.4" diff --git a/Makefile b/Makefile index 81cae79..d38be2c 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ coding-standard-fix: .PHONY: static-analysis static-analysis: ## Run static analysis checks - ./vendor/bin/phpstan --configuration=config/phpstan.neon + ./vendor/bin/phpstan --configuration=config/phpstan.neon --memory-limit=256M ./vendor/bin/psalm --config config/psalm.xml --no-cache .PHONY: static-analysis-update diff --git a/README.md b/README.md index e623c16..6ed22b5 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Speicher210 CloudinaryBundle -[![Latest Version](https://img.shields.io/github/tag/Speicher210/CloudinaryBundle.svg?style=flat-square)](https://github.com/Speicher210/CloudinaryBundle/releases) +[![Latest Version](https://img.shields.io/github/tag/protung/cloudinary-bundle.svg?style=flat-square)](https://github.com/Speicher210/CloudinaryBundle/releases) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) -![GitHub branch checks state](https://img.shields.io/github/checks-status/Speicher210/CloudinaryBundle/master?style=flat-square) +![GitHub branch checks state](https://img.shields.io/github/checks-status/protung/cloudinary-bundle/1.x?style=flat-square) ## Install @@ -25,25 +25,9 @@ return [ ]; ``` -or - -``` php -// app/AppKernel.php -// ... -public function registerBundles() -{ - return array( - // ... - new Speicher210\CloudinaryBundle\Speicher210CloudinaryBundle(), - // ... - ); -} -// ... -``` - ## Usage -Configure the connection to cloudinary in your `config.yml` : +Configure the connection to cloudinary in your `config.yaml` : ``` yaml speicher210_cloudinary: @@ -54,8 +38,7 @@ speicher210_cloudinary: access_identifier: api_key: my-key api_secret: my-secret - options: - secure: true + secure: true ``` The following services will be available: diff --git a/composer.json b/composer.json index df98b87..6fdf5a3 100644 --- a/composer.json +++ b/composer.json @@ -15,31 +15,31 @@ "role": "Developer" } ], - "homepage": "https://github.com/Speicher210/CloudinaryBundle", + "homepage": "https://github.com/protung/cloudinary-bundle", "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", - "azjezz/psl": "^2.9.1 || ^3.0.0", - "cloudinary/cloudinary_php": "^2.14.0", - "symfony/console": "^5.4 || ^6.4 || ^7.2", - "symfony/finder": "^5.4 || ^6.4 || ^7.2", - "symfony/framework-bundle": "^5.4 || ^6.4 || ^7.2", - "symfony/yaml": "^5.4 || ^6.4 || ^7.2" + "php": "~8.3.0 || ~8.4.0", + "azjezz/psl": "^3.0.0", + "cloudinary/cloudinary_php": "^3.1.1", + "symfony/console": "^6.4 || ^7.2", + "symfony/finder": "^6.4 || ^7.2", + "symfony/framework-bundle": "^6.4 || ^7.2", + "symfony/yaml": "^6.4 || ^7.2" }, "require-dev": { - "doctrine/coding-standard": "^12.0", - "ergebnis/composer-normalize": "^2.45.0", + "doctrine/coding-standard": "^13.0", + "ergebnis/composer-normalize": "^2.47.0", "php-standard-library/phpstan-extension": "^2.0.0", "php-standard-library/psalm-plugin": "^2.3", - "phpstan/phpstan": "^2.1.2", - "phpstan/phpstan-deprecation-rules": "^2.0.1", - "phpstan/phpstan-phpunit": "^2.0.4", - "phpstan/phpstan-strict-rules": "^2.0.3", - "phpstan/phpstan-symfony": "^2.0.2", - "phpunit/phpunit": "^11.5.7", - "psalm/plugin-phpunit": "^0.19.2", + "phpstan/phpstan": "^2.1.17", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.6", + "phpstan/phpstan-strict-rules": "^2.0.4", + "phpstan/phpstan-symfony": "^2.0.6", + "phpunit/phpunit": "^12.2.6", + "psalm/plugin-phpunit": "^0.19.5", "roave/security-advisories": "dev-latest", - "twig/twig": "^2.0 || ^3.19", - "vimeo/psalm": "^6.0.0" + "twig/twig": "^3.21", + "vimeo/psalm": "^6.12.1" }, "suggest": { "twig/twig": "Allow to use the cloudinary_url function/filter" diff --git a/config/phpstan-baseline.neon b/config/phpstan-baseline.neon index 2f7caf0..b0cd96c 100644 --- a/config/phpstan-baseline.neon +++ b/config/phpstan-baseline.neon @@ -1,51 +1,55 @@ parameters: ignoreErrors: - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + message: '#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable count: 1 path: ../src/Command/DeleteCommand.php - - message: "#^Parameter \\#1 \\$prefix of method Cloudinary\\\\Api\\\\Admin\\\\AdminApi\\:\\:deleteAssetsByPrefix\\(\\) expects string, mixed given\\.$#" + message: '#^Parameter \#1 \$prefix of method Cloudinary\\Api\\Admin\\AdminApi\:\:deleteAssetsByPrefix\(\) expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../src/Command/DeleteCommand.php - - message: "#^Parameter \\#1 \\$publicIds of method Cloudinary\\\\Api\\\\Admin\\\\AdminApi\\:\\:deleteAssets\\(\\) expects array\\|string, mixed given\\.$#" + message: '#^Parameter \#1 \$publicIds of method Cloudinary\\Api\\Admin\\AdminApi\:\:deleteAssets\(\) expects array\|string, mixed given\.$#' + identifier: argument.type count: 1 path: ../src/Command/DeleteCommand.php - - message: "#^Parameter \\#2 \\.\\.\\.\\$args of function Psl\\\\Str\\\\format expects float\\|int\\|string, mixed given\\.$#" + message: '#^Parameter \#2 \.\.\.\$args of function Psl\\Str\\format expects float\|int\|string, mixed given\.$#' + identifier: argument.type count: 2 path: ../src/Command/DeleteCommand.php - - message: "#^Parameter \\#1 \\$publicId of method Cloudinary\\\\Api\\\\Admin\\\\AdminApi\\:\\:asset\\(\\) expects string, mixed given\\.$#" + message: '#^Parameter \#1 \$publicId of method Cloudinary\\Api\\Admin\\AdminApi\:\:asset\(\) expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../src/Command/InfoCommand.php - - message: "#^Parameter \\#2 \\$derivedResources of method Speicher210\\\\CloudinaryBundle\\\\Command\\\\InfoCommand\\:\\:renderDerivedResources\\(\\) expects array\\, mixed given\\.$#" + message: '#^Parameter \#2 \$derivedResources of method Speicher210\\CloudinaryBundle\\Command\\InfoCommand\:\:renderDerivedResources\(\) expects array\, mixed given\.$#' + identifier: argument.type count: 1 path: ../src/Command/InfoCommand.php - - message: "#^In method \"Speicher210\\\\CloudinaryBundle\\\\Command\\\\UploadCommand\\:\\:execute\", caught \"Throwable\" must be rethrown\\. Either catch a more specific exception or add a \"throw\" clause in the \"catch\" block to propagate the exception\\. More info\\: http\\://bit\\.ly/failloud$#" + message: '#^Parameter \#1 \$dirs of method Symfony\\Component\\Finder\\Finder\:\:in\(\) expects array\\|string, mixed given\.$#' + identifier: argument.type count: 1 path: ../src/Command/UploadCommand.php - - message: "#^Parameter \\#1 \\$dirs of method Symfony\\\\Component\\\\Finder\\\\Finder\\:\\:in\\(\\) expects array\\\\|string, mixed given\\.$#" + message: '#^Parameter \#1 \$node of function Psl\\Filesystem\\get_filename expects non\-empty\-string, string given\.$#' + identifier: argument.type count: 1 path: ../src/Command/UploadCommand.php - - message: "#^Parameter \\#1 \\$node of function Psl\\\\Filesystem\\\\get_filename expects non\\-empty\\-string, string given\\.$#" - count: 1 - path: ../src/Command/UploadCommand.php - - - - message: "#^Parameter \\#1 \\$patterns of method Symfony\\\\Component\\\\Finder\\\\Finder\\:\\:name\\(\\) expects array\\\\|string, mixed given\\.$#" + message: '#^Parameter \#1 \$patterns of method Symfony\\Component\\Finder\\Finder\:\:name\(\) expects array\\|string, mixed given\.$#' + identifier: argument.type count: 1 path: ../src/Command/UploadCommand.php diff --git a/config/psalm.baseline.xml b/config/psalm.baseline.xml index 6034560..a0930ad 100644 --- a/config/psalm.baseline.xml +++ b/config/psalm.baseline.xml @@ -1,5 +1,20 @@ - + + + + + + + + + + + + + + + + diff --git a/src/Cloudinary/Cloudinary.php b/src/Cloudinary/Cloudinary.php index a4f5e60..41a8861 100644 --- a/src/Cloudinary/Cloudinary.php +++ b/src/Cloudinary/Cloudinary.php @@ -4,13 +4,17 @@ namespace Speicher210\CloudinaryBundle\Cloudinary; +use Override; + class Cloudinary extends \Cloudinary\Cloudinary { + #[Override] public function adminApi(): Admin { return new Admin($this->configuration); } + #[Override] public function uploadApi(): Uploader { return new Uploader($this->configuration); diff --git a/src/Command/DeleteCommand.php b/src/Command/DeleteCommand.php index a08370d..c2175a5 100644 --- a/src/Command/DeleteCommand.php +++ b/src/Command/DeleteCommand.php @@ -5,6 +5,7 @@ namespace Speicher210\CloudinaryBundle\Command; use Cloudinary\Api\ApiResponse; +use Override; use Psl\Str; use Speicher210\CloudinaryBundle\Cloudinary\Admin; use Symfony\Component\Console\Command\Command; @@ -24,6 +25,7 @@ public function __construct(Admin $cloudinary) parent::__construct(); } + #[Override] protected function configure(): void { $this @@ -43,6 +45,7 @@ protected function configure(): void ); } + #[Override] protected function execute(InputInterface $input, OutputInterface $output): int { $symfonyStyle = new SymfonyStyle($input, $output); diff --git a/src/Command/InfoCommand.php b/src/Command/InfoCommand.php index dce5d0d..8eca037 100644 --- a/src/Command/InfoCommand.php +++ b/src/Command/InfoCommand.php @@ -5,6 +5,7 @@ namespace Speicher210\CloudinaryBundle\Command; use Cloudinary\Api\ApiResponse; +use Override; use Speicher210\CloudinaryBundle\Cloudinary\Admin; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\TableCell; @@ -29,6 +30,7 @@ public function __construct(Admin $cloudinary) parent::__construct(); } + #[Override] protected function configure(): void { $this @@ -37,6 +39,7 @@ protected function configure(): void ->addArgument('public_id', InputArgument::REQUIRED, 'The public ID of the resource.'); } + #[Override] protected function execute(InputInterface $input, OutputInterface $output): int { $symfonyStyle = new SymfonyStyle($input, $output); diff --git a/src/Command/UploadCommand.php b/src/Command/UploadCommand.php index 2f61fa5..74fe946 100644 --- a/src/Command/UploadCommand.php +++ b/src/Command/UploadCommand.php @@ -5,6 +5,7 @@ namespace Speicher210\CloudinaryBundle\Command; use Cloudinary\Api\ApiResponse; +use Override; use Psl\Filesystem; use Psl\Type; use Speicher210\CloudinaryBundle\Cloudinary\Uploader; @@ -29,6 +30,7 @@ public function __construct(Uploader $uploader) parent::__construct(); } + #[Override] protected function configure(): void { $this @@ -51,6 +53,7 @@ protected function configure(): void ); } + #[Override] protected function execute(InputInterface $input, OutputInterface $output): int { $symfonyStyle = new SymfonyStyle($input, $output); diff --git a/src/DependencyInjection/Compiler/RemoveTwigExtensionPass.php b/src/DependencyInjection/Compiler/RemoveTwigExtensionPass.php index 0ed9d52..26142d6 100644 --- a/src/DependencyInjection/Compiler/RemoveTwigExtensionPass.php +++ b/src/DependencyInjection/Compiler/RemoveTwigExtensionPass.php @@ -4,6 +4,7 @@ namespace Speicher210\CloudinaryBundle\DependencyInjection\Compiler; +use Override; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -12,6 +13,7 @@ */ final class RemoveTwigExtensionPass implements CompilerPassInterface { + #[Override] public function process(ContainerBuilder $container): void { if ($container->hasDefinition('twig')) { diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 6a26121..2bb8a8b 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -4,11 +4,13 @@ namespace Speicher210\CloudinaryBundle\DependencyInjection; +use Override; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; final class Configuration implements ConfigurationInterface { + #[Override] public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('speicher210_cloudinary'); diff --git a/src/DependencyInjection/Speicher210CloudinaryExtension.php b/src/DependencyInjection/Speicher210CloudinaryExtension.php index 9d4b2eb..3b414c8 100644 --- a/src/DependencyInjection/Speicher210CloudinaryExtension.php +++ b/src/DependencyInjection/Speicher210CloudinaryExtension.php @@ -4,6 +4,7 @@ namespace Speicher210\CloudinaryBundle\DependencyInjection; +use Override; use Speicher210\CloudinaryBundle\Factory\CloudinaryFactory; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -15,6 +16,7 @@ final class Speicher210CloudinaryExtension extends ConfigurableExtension /** * @param array $mergedConfig */ + #[Override] protected function loadInternal(array $mergedConfig, ContainerBuilder $container): void { $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); diff --git a/src/Factory/InvalidCloudinaryUrlException.php b/src/Factory/InvalidCloudinaryUrlException.php index d3c1a20..504caac 100644 --- a/src/Factory/InvalidCloudinaryUrlException.php +++ b/src/Factory/InvalidCloudinaryUrlException.php @@ -6,7 +6,7 @@ use InvalidArgumentException; -class InvalidCloudinaryUrlException extends InvalidArgumentException +final class InvalidCloudinaryUrlException extends InvalidArgumentException { public function __construct() { diff --git a/src/Speicher210CloudinaryBundle.php b/src/Speicher210CloudinaryBundle.php index 6dfd373..1375bb3 100644 --- a/src/Speicher210CloudinaryBundle.php +++ b/src/Speicher210CloudinaryBundle.php @@ -4,12 +4,14 @@ namespace Speicher210\CloudinaryBundle; +use Override; use Speicher210\CloudinaryBundle\DependencyInjection\Compiler\RemoveTwigExtensionPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; final class Speicher210CloudinaryBundle extends Bundle { + #[Override] public function build(ContainerBuilder $container): void { $container->addCompilerPass(new RemoveTwigExtensionPass()); diff --git a/src/Twig/Extension/CloudinaryExtension.php b/src/Twig/Extension/CloudinaryExtension.php index 02c840d..ff4e349 100644 --- a/src/Twig/Extension/CloudinaryExtension.php +++ b/src/Twig/Extension/CloudinaryExtension.php @@ -9,6 +9,7 @@ use Cloudinary\Tag\PictureTag; use Cloudinary\Tag\VideoTag; use Cloudinary\Transformation\ImageTransformation; +use Override; use Speicher210\CloudinaryBundle\Cloudinary\Cloudinary; use Twig\Extension\AbstractExtension; use Twig\TwigFilter; @@ -34,6 +35,7 @@ public function __construct(Cloudinary $cloudinary, array $defaultConfiguration /** * {@inheritDoc} */ + #[Override] public function getFunctions(): array { return [ @@ -47,6 +49,7 @@ public function getFunctions(): array /** * {@inheritDoc} */ + #[Override] public function getFilters(): array { return [ diff --git a/tests/DependencyInjection/AbstractSpeicher210CloudinaryExtensionTestCase.php b/tests/DependencyInjection/AbstractSpeicher210CloudinaryExtensionTestCase.php index ce4bc3d..ca66956 100644 --- a/tests/DependencyInjection/AbstractSpeicher210CloudinaryExtensionTestCase.php +++ b/tests/DependencyInjection/AbstractSpeicher210CloudinaryExtensionTestCase.php @@ -5,6 +5,7 @@ namespace Speicher210\CloudinaryBundle\Tests\DependencyInjection; use Cloudinary\Configuration\Configuration; +use Override; use PHPUnit\Framework\TestCase; use Speicher210\CloudinaryBundle\Cloudinary\Admin; use Speicher210\CloudinaryBundle\Cloudinary\Cloudinary; @@ -17,6 +18,7 @@ abstract class AbstractSpeicher210CloudinaryExtensionTestCase extends TestCase { private ContainerBuilder $container; + #[Override] protected function setUp(): void { $this->container = new ContainerBuilder(); diff --git a/tests/DependencyInjection/Compiler/RemoveTwigExtensionPassTest.php b/tests/DependencyInjection/Compiler/RemoveTwigExtensionPassTest.php index a9ea2b4..d441486 100644 --- a/tests/DependencyInjection/Compiler/RemoveTwigExtensionPassTest.php +++ b/tests/DependencyInjection/Compiler/RemoveTwigExtensionPassTest.php @@ -4,17 +4,19 @@ namespace Speicher210\CloudinaryBundle\Tests\DependencyInjection\Compiler; +use Override; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Speicher210\CloudinaryBundle\DependencyInjection\Compiler\RemoveTwigExtensionPass; use Symfony\Component\DependencyInjection\ContainerBuilder; -class RemoveTwigExtensionPassTest extends TestCase +final class RemoveTwigExtensionPassTest extends TestCase { private ContainerBuilder&MockObject $container; private RemoveTwigExtensionPass $compilerPass; + #[Override] protected function setUp(): void { $this->container = $this->createMock(ContainerBuilder::class); @@ -25,13 +27,13 @@ protected function setUp(): void public function testProcessWithTwig(): void { $this->container - ->expects(self::once()) + ->expects($this->once()) ->method('hasDefinition') ->with('twig') ->willReturn(true); $this->container - ->expects(self::never()) + ->expects($this->never()) ->method('removeDefinition') ->with('twig.extension.cloudinary'); @@ -41,13 +43,13 @@ public function testProcessWithTwig(): void public function testProcessWithoutTwig(): void { $this->container - ->expects(self::once()) + ->expects($this->once()) ->method('hasDefinition') ->with('twig') ->willReturn(false); $this->container - ->expects(self::once()) + ->expects($this->once()) ->method('removeDefinition') ->with('twig.extension.cloudinary'); diff --git a/tests/DependencyInjection/YamlSpeicher210CloudinaryExtensionTest.php b/tests/DependencyInjection/YamlSpeicher210CloudinaryExtensionTest.php index 1f71290..1b8d86b 100644 --- a/tests/DependencyInjection/YamlSpeicher210CloudinaryExtensionTest.php +++ b/tests/DependencyInjection/YamlSpeicher210CloudinaryExtensionTest.php @@ -4,12 +4,14 @@ namespace Speicher210\CloudinaryBundle\Tests\DependencyInjection; +use Override; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; final class YamlSpeicher210CloudinaryExtensionTest extends AbstractSpeicher210CloudinaryExtensionTestCase { + #[Override] protected function loadConfiguration(ContainerBuilder $container, string $configuration): void { $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Fixtures/Config/Yaml')); diff --git a/tests/Twig/Extension/CloudinaryExtensionTest.php b/tests/Twig/Extension/CloudinaryExtensionTest.php index 06309ad..21ddaeb 100644 --- a/tests/Twig/Extension/CloudinaryExtensionTest.php +++ b/tests/Twig/Extension/CloudinaryExtensionTest.php @@ -4,19 +4,20 @@ namespace Speicher210\CloudinaryBundle\Tests\Twig\Extension; +use Override; +use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Speicher210\CloudinaryBundle\Cloudinary\Cloudinary; use Speicher210\CloudinaryBundle\Twig\Extension\CloudinaryExtension; use Twig\Environment; use Twig\Loader\FilesystemLoader; -/** - * @covers \Speicher210\CloudinaryBundle\Twig\Extension\CloudinaryExtension - */ +#[CoversClass(CloudinaryExtension::class)] final class CloudinaryExtensionTest extends TestCase { private Environment $twig; + #[Override] protected function setUp(): void { $cloudinary = new Cloudinary(['cloud_name' => 'test', 'analytics' => false]);