diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d2e1eb..8618381 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Latest ------ ### Changes +* [#62](https://github.com/cleverage/soap-process-bundle/issues/62) 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`, `Exception\InvalidArgumentException` and `Exception\RuntimeException`, extending the SPL exceptions thrown before (same messages, the existing `catch` keep working). Add tests. * [#60](https://github.com/cleverage/soap-process-bundle/issues/60) 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). * [#55](https://github.com/cleverage/soap-process-bundle/issues/55) Define the public API (Symfony BC promise, as [cleverage/process-bundle#279](https://github.com/cleverage/process-bundle/issues/279)): `RequestTask`, `RequestTransformer`, `ClientRegistry` and `CleverAgeSoapProcessBundle` are marked `@final since 3.3`, they will be `final` in 4.0: extending them triggers a deprecation with the Symfony `DebugClassLoader`. `Client` (extended by the applications) and `MissingClientException` stay open. `CleverAgeSoapProcessExtension` and `RegisterClientsPass` are marked `@internal`. * [#54](https://github.com/cleverage/soap-process-bundle/issues/54) `CleverAgeSoapProcessExtension::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/Client/Client.php b/src/Client/Client.php index 48f0ea8..a284b08 100644 --- a/src/Client/Client.php +++ b/src/Client/Client.php @@ -13,6 +13,8 @@ namespace CleverAge\SoapProcessBundle\Client; +use CleverAge\SoapProcessBundle\Exception\InvalidArgumentException; +use CleverAge\SoapProcessBundle\Exception\UnexpectedValueException; use Psr\Log\LoggerInterface; /** @@ -61,7 +63,7 @@ public function getLogger(): LoggerInterface public function getCode(): string { if ('' === $this->code || '0' === $this->code) { - throw new \UnexpectedValueException('Client code is not defined'); + throw new UnexpectedValueException('Client code is not defined'); } return $this->code; @@ -187,7 +189,7 @@ public function call(string $method, array $input = []): mixed protected function doSoapCall(string $method, array $input = []): mixed { if (!$this->getSoapClient() instanceof \SoapClient) { - throw new \InvalidArgumentException('Soap client is not initialized'); + throw new InvalidArgumentException('Soap client is not initialized'); } try { $result = $this->getSoapClient()->__soapCall($method, $input, $this->getSoapOptions(), $this->getSoapHeaders()); diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..aedde38 --- /dev/null +++ b/src/Exception/InvalidArgumentException.php @@ -0,0 +1,23 @@ +clients[$code] = $client; $this->serviceIds[$code] = $serviceId; @@ -106,10 +107,10 @@ public function getClient(string $code): ClientInterface $client = $this->locator->get($code); if (!$client instanceof ClientInterface) { - throw new \UnexpectedValueException(\sprintf('The service of the SOAP client "%s" must implement "%s".', $code, ClientInterface::class)); + throw new UnexpectedValueException(\sprintf('The service of the SOAP client "%s" must implement "%s".', $code, ClientInterface::class)); } if ($code !== $client->getCode()) { - throw new \UnexpectedValueException(\sprintf('The SOAP client "%s" is registered with the code "%s" but its getCode() method returns "%s": both must be the same.', $client::class, $code, $client->getCode())); + throw new UnexpectedValueException(\sprintf('The SOAP client "%s" is registered with the code "%s" but its getCode() method returns "%s": both must be the same.', $client::class, $code, $client->getCode())); } return $this->clients[$code] = $client; diff --git a/src/Task/RequestTask.php b/src/Task/RequestTask.php index ac8ca6c..c438c11 100644 --- a/src/Task/RequestTask.php +++ b/src/Task/RequestTask.php @@ -16,6 +16,8 @@ use CleverAge\ProcessBundle\Model\AbstractConfigurableTask; use CleverAge\ProcessBundle\Model\ProcessState; use CleverAge\SoapProcessBundle\Client\SoapCallOptionsTrait; +use CleverAge\SoapProcessBundle\Exception\RuntimeException; +use CleverAge\SoapProcessBundle\Exception\UnexpectedValueException; use CleverAge\SoapProcessBundle\Registry\ClientRegistry; use Psr\Log\LoggerInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -47,7 +49,7 @@ public function execute(ProcessState $state): void $input = $state->getInput() ?: []; if (!\is_array($input)) { - throw new \UnexpectedValueException(\sprintf('RequestTask expects an array or empty input, %s given', get_debug_type($input))); + throw new UnexpectedValueException(\sprintf('RequestTask expects an array or empty input, %s given', get_debug_type($input))); } try { @@ -66,7 +68,7 @@ public function execute(ProcessState $state): void // The process manager applies the error strategy: the process fails with "stop", the error outputs // receive the task input with "skip" - throw new \RuntimeException(\sprintf("Soap call '%s' on client '%s' failed", $options['method'], $options['client']), 0, $e); + throw new RuntimeException(\sprintf("Soap call '%s' on client '%s' failed", $options['method'], $options['client']), 0, $e); } $state->setOutput($result); diff --git a/src/Transformer/RequestTransformer.php b/src/Transformer/RequestTransformer.php index 5680b52..201a900 100644 --- a/src/Transformer/RequestTransformer.php +++ b/src/Transformer/RequestTransformer.php @@ -15,6 +15,8 @@ use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; use CleverAge\SoapProcessBundle\Client\SoapCallOptionsTrait; +use CleverAge\SoapProcessBundle\Exception\RuntimeException; +use CleverAge\SoapProcessBundle\Exception\UnexpectedValueException; use CleverAge\SoapProcessBundle\Registry\ClientRegistry; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -42,7 +44,7 @@ public function __construct(protected ClientRegistry $registry) public function transform(mixed $value, array $options = []): mixed { if (!\is_array($value)) { - throw new \UnexpectedValueException('Expecting an array of value'); + throw new UnexpectedValueException('Expecting an array of value'); } $resolver = new OptionsResolver(); @@ -55,7 +57,7 @@ public function transform(mixed $value, array $options = []): mixed try { return $this->callWithSoapOptions($client, $options['method'], $value, $options['soap_call_options'], $options['soap_call_headers']); } catch (\SoapFault $e) { - throw new \RuntimeException(\sprintf("Soap call '%s' on client '%s' failed", $options['method'], $options['client']), 0, $e); + throw new RuntimeException(\sprintf("Soap call '%s' on client '%s' failed", $options['method'], $options['client']), 0, $e); } } diff --git a/tests/Exception/SplExceptionsTest.php b/tests/Exception/SplExceptionsTest.php new file mode 100644 index 0000000..48b3e78 --- /dev/null +++ b/tests/Exception/SplExceptionsTest.php @@ -0,0 +1,56 @@ +, class-string<\Throwable>}> + */ + public static function provideExceptions(): iterable + { + yield 'UnexpectedValueException' => [UnexpectedValueException::class, \UnexpectedValueException::class]; + yield 'InvalidArgumentException' => [InvalidArgumentException::class, \InvalidArgumentException::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()]); + } +}