From 2a25fb4e6e90798120eb8f4f5513cf3e57b46102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Kr=C3=A4mer?= <4996022+floriankraemer@users.noreply.github.com> Date: Mon, 6 Jan 2025 23:18:16 +0100 Subject: [PATCH] Refactoring (#4) --- config/services.yaml | 15 ++++- docs/Create-your-own-Converter.md | 61 +++++++++++++++++++ readme.md | 1 + .../ValidationFailedExceptionConverter.php | 8 +-- 4 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 docs/Create-your-own-Converter.md diff --git a/config/services.yaml b/config/services.yaml index 3a7761c..0ea1eba 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -8,9 +8,20 @@ services: Phauthentic\Symfony\ProblemDetails\FromExceptionEventFactoryInterface: class: 'Phauthentic\Symfony\ProblemDetails\ProblemDetailsFactory' - Phauthentic\Symfony\ProblemDetails\Validation\ValidationErrorsToProblemDetailsKernelEventSubscriber: + Phauthentic\Symfony\ProblemDetails\ExceptionConversion\ValidationFailedExceptionConverter: arguments: $validationErrorsBuilder: '@Phauthentic\Symfony\ProblemDetails\Validation\ValidationErrorsBuilder' $problemDetailsResponseFactory: '@Phauthentic\Symfony\ProblemDetails\FromExceptionEventFactoryInterface' + + Phauthentic\Symfony\ProblemDetails\ExceptionConversion\HttpExceptionConverter: + arguments: + $problemDetailsFactory: '@Phauthentic\Symfony\ProblemDetails\ProblemDetailsFactoryInterface' + + Phauthentic\Symfony\ProblemDetails\ExceptionConversion\ThrowableToProblemDetailsKernelListener: + arguments: + $exceptionConverters: + - '@Phauthentic\Symfony\ProblemDetails\ExceptionConversion\ValidationFailedExceptionConverter' + - '@Phauthentic\Symfony\ProblemDetails\ExceptionConversion\HttpExceptionConverter' + - '@Phauthentic\Symfony\ProblemDetails\ExceptionConversion\ThrowableToProblemDetailsKernelListener' tags: - - { name: 'kernel.event_subscriber' } \ No newline at end of file + - { name: 'kernel.event_listener', event: 'kernel.exception', priority: 0 } diff --git a/docs/Create-your-own-Converter.md b/docs/Create-your-own-Converter.md new file mode 100644 index 0000000..a78c5cd --- /dev/null +++ b/docs/Create-your-own-Converter.md @@ -0,0 +1,61 @@ +## How to Implement and Use Your Own Exception Converters + +Implementing and using custom exception converters can make exception handling in your application more structured and versatile. With the `ProblemDetailsSymfonyBundle`, it is possible to extend and customize the way exceptions are converted to `ProblemDetails` responses. Here is how you can create and use your own exception converters: + +### Steps to Implement a Custom Exception Converter +1. **Understand the Exception Conversion** + - Exception converters are responsible for transforming an exception into a structured `ProblemDetails` response adhering to RFC 9457. + - The `ProblemDetailsFactory` can be used to create such responses within the converter. +2. **Create Your Custom Exception Converter** + - Create a class that handles the logic for converting specific exception types or scenarios into `ProblemDetails`. + +```php + namespace App\ExceptionConverter; + + use Psr\Log\LoggerInterface; + use Phauthentic\ProblemDetails\ExceptionConverterInterface; + use Phauthentic\ProblemDetails\ProblemDetailsFactoryInterface; + use Symfony\Component\HttpFoundation\Response; + + class CustomExceptionConverter implements ExceptionConverterInterface + { + public function __construct( + private ProblemDetailsFactoryInterface $problemDetailsFactory, + private LoggerInterface $logger + ) { + } + + /** + * Converts the given exception to a ProblemDetails instance. + */ + public function convert(\Throwable $exception): Response + { + // Example exception check + if ($exception instanceof \DomainException) { + $this->logger->error('Domain Exception occurred: '.$exception->getMessage()); + + return $this->problemDetailsFactory->createResponse( + type: 'https://example.net/domain-error', + detail: $exception->getMessage(), + status: 400, + title: 'Domain Error' + ); + } + + // Default: throw the exception further if it cannot be converted + throw $exception; + } + } +``` + +3. **Register the Exception Converter in Your Application** + - Register your custom exception converter as a service in Symfony, and ensure it integrates into the exception handling workflow. + +```yaml + # config/services.yaml + services: + App\ExceptionConverter\CustomExceptionConverter: + arguments: + $problemDetailsFactory: '@Phauthentic\ProblemDetails\ProblemDetailsFactoryInterface' + $logger: '@logger' +``` diff --git a/readme.md b/readme.md index b089801..baa4437 100644 --- a/readme.md +++ b/readme.md @@ -59,6 +59,7 @@ Content-Language: en ] } ``` + ## Alternatives If you favor a different style of implementation check out the following bundles: diff --git a/src/ExceptionConversion/ValidationFailedExceptionConverter.php b/src/ExceptionConversion/ValidationFailedExceptionConverter.php index 715de76..69bf489 100644 --- a/src/ExceptionConversion/ValidationFailedExceptionConverter.php +++ b/src/ExceptionConversion/ValidationFailedExceptionConverter.php @@ -9,7 +9,6 @@ use RuntimeException; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ExceptionEvent; -use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; use Symfony\Component\Validator\Exception\ValidationFailedException; use Throwable; @@ -52,8 +51,9 @@ public function convertExceptionToErrorDetails(Throwable $throwable, ExceptionEv { $throwable = $this->extractValidationFailedException($throwable); - $errors = $this->validationErrorsBuilder->buildErrors($throwable); - - return $this->problemDetailsResponseFactory->createResponseFromKernelExceptionEvent($event, $errors); + return $this->problemDetailsResponseFactory->createResponseFromKernelExceptionEvent( + $event, + $this->validationErrorsBuilder->buildErrors($throwable) + ); } }