diff --git a/CHANGELOG.md b/CHANGELOG.md index 739eaa4..f7b5f75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Latest ------ ### Changes +* [#45](https://github.com/cleverage/archive-process-bundle/issues/45) The bundle throws exceptions implementing `ProcessExceptionInterface` of the process bundle instead of raw SPL exceptions (as [cleverage/process-bundle#317](https://github.com/cleverage/process-bundle/issues/317)): new `Exception\UnexpectedValueException` and `Exception\RuntimeException`, extending the SPL exceptions thrown before (same messages, the existing `catch` keep working). Add tests. * [#43](https://github.com/cleverage/archive-process-bundle/issues/43) Composer: require PHP `^8.2` instead of `>=8.2` (PHP 9 is no longer accepted before being tested), remove the authorization of the `symfony/flex` plugin, which is not required (the CI installs it globally), as [cleverage/process-bundle#319](https://github.com/cleverage/process-bundle/issues/319). * [#38](https://github.com/cleverage/archive-process-bundle/issues/38) Define the public API (Symfony BC promise, as [cleverage/process-bundle#279](https://github.com/cleverage/process-bundle/issues/279)): `ZipTask`, `UnzipTask` and `CleverAgeArchiveProcessBundle` are marked `@final since 2.3`, they will be `final` in 3.0: extending them triggers a deprecation with the Symfony `DebugClassLoader`. `CleverAgeArchiveProcessExtension` is marked `@internal`. * [#37](https://github.com/cleverage/archive-process-bundle/issues/37) `CleverAgeArchiveProcessExtension::findServices()` loads the service definition files with a glob pattern instead of a `Finder` (same files, as [cleverage/process-bundle#271](https://github.com/cleverage/process-bundle/issues/271)), `symfony/finder` is no longer required. Add tests. diff --git a/src/Exception/RuntimeException.php b/src/Exception/RuntimeException.php new file mode 100644 index 0000000..3075669 --- /dev/null +++ b/src/Exception/RuntimeException.php @@ -0,0 +1,23 @@ +setInput([]); } if (!\is_array($state->getInput())) { - throw new \UnexpectedValueException(\sprintf('UnzipTask expects an array or null input, %s given', get_debug_type($state->getInput()))); + throw new UnexpectedValueException(\sprintf('UnzipTask expects an array or null input, %s given', get_debug_type($state->getInput()))); } /** * @var array{filename: string, destination: string} $options @@ -39,11 +41,11 @@ public function execute(ProcessState $state): void $filename = $options['filename']; if (!file_exists($filename)) { - throw new \UnexpectedValueException("File does not exists: '{$filename}'"); + throw new UnexpectedValueException("File does not exists: '{$filename}'"); } if (!is_readable($filename)) { - throw new \UnexpectedValueException("File is not readable: '{$filename}'"); + throw new UnexpectedValueException("File is not readable: '{$filename}'"); } $dest = $options['destination']; @@ -51,7 +53,7 @@ public function execute(ProcessState $state): void $zipArchive = new \ZipArchive(); $res = $zipArchive->open($filename); if (true !== $res) { - throw new \RuntimeException("Unable to open file {$filename} with code {$res}"); + throw new RuntimeException("Unable to open file {$filename} with code {$res}"); } // The PHP warning is replaced by the exception below @@ -60,7 +62,7 @@ public function execute(ProcessState $state): void $error = error_get_last()['message'] ?? $zipArchive->getStatusString(); $zipArchive->close(); if (!$extracted) { - throw new \RuntimeException("Unable to extract file {$filename} to {$dest}: {$error}"); + throw new RuntimeException("Unable to extract file {$filename} to {$dest}: {$error}"); } $state->setOutput($dest); diff --git a/src/Task/ZipTask.php b/src/Task/ZipTask.php index 59a2dbe..a9f7412 100644 --- a/src/Task/ZipTask.php +++ b/src/Task/ZipTask.php @@ -13,6 +13,8 @@ namespace CleverAge\ArchiveProcessBundle\Task; +use CleverAge\ArchiveProcessBundle\Exception\RuntimeException; +use CleverAge\ArchiveProcessBundle\Exception\UnexpectedValueException; use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -30,7 +32,7 @@ public function execute(ProcessState $state): void $state->setInput([]); } if (!\is_array($state->getInput())) { - throw new \UnexpectedValueException(\sprintf('ZipTask expects an array or null input, %s given', get_debug_type($state->getInput()))); + throw new UnexpectedValueException(\sprintf('ZipTask expects an array or null input, %s given', get_debug_type($state->getInput()))); } /** * @var array{filename: string, files: array|string, files_base_path: string} $options @@ -40,7 +42,7 @@ public function execute(ProcessState $state): void $zip = new \ZipArchive(); $ret = $zip->open($options['filename'], \ZipArchive::CREATE | \ZipArchive::OVERWRITE); if (true !== $ret) { - throw new \RuntimeException("Fail to open file {$options['filename']} with code {$ret}"); + throw new RuntimeException("Fail to open file {$options['filename']} with code {$ret}"); } $files = $options['files']; @@ -62,19 +64,19 @@ public function execute(ProcessState $state): void $currentFilepath = $basePath.\DIRECTORY_SEPARATOR.$currentFilename; } if (!file_exists($currentFilepath)) { - throw new \UnexpectedValueException("File does not exists: '{$currentFilepath}'"); + throw new UnexpectedValueException("File does not exists: '{$currentFilepath}'"); } if (!is_readable($currentFilepath)) { - throw new \UnexpectedValueException("File is not readable: '{$currentFilepath}'"); + throw new UnexpectedValueException("File is not readable: '{$currentFilepath}'"); } if (false === $zip->addFile($currentFilepath, $currentFilename)) { - throw new \RuntimeException("Unable to add file {$currentFilepath} to zip"); + throw new RuntimeException("Unable to add file {$currentFilepath} to zip"); } } // The archive is written on close: the PHP warning is replaced by the exception below if (!@$zip->close()) { - throw new \RuntimeException("Unable to write zip file {$options['filename']}: {$zip->getStatusString()}"); + throw new RuntimeException("Unable to write zip file {$options['filename']}: {$zip->getStatusString()}"); } $state->setOutput($options['filename']); diff --git a/tests/Exception/SplExceptionsTest.php b/tests/Exception/SplExceptionsTest.php new file mode 100644 index 0000000..f9f8a2e --- /dev/null +++ b/tests/Exception/SplExceptionsTest.php @@ -0,0 +1,53 @@ +, class-string<\Throwable>}> + */ + public static function provideExceptions(): iterable + { + yield 'UnexpectedValueException' => [UnexpectedValueException::class, \UnexpectedValueException::class]; + yield 'RuntimeException' => [RuntimeException::class, \RuntimeException::class]; + } + + /** + * @param class-string<\Throwable> $class + * @param class-string<\Throwable> $splClass + */ + #[DataProvider('provideExceptions')] + public function testExtendsTheSplExceptionAndImplementsTheInterface(string $class, string $splClass): void + { + $exception = new $class('message', 12); + + self::assertInstanceOf($splClass, $exception); + self::assertInstanceOf(ProcessExceptionInterface::class, $exception); + self::assertSame(['message', 12], [$exception->getMessage(), $exception->getCode()]); + } +}