diff --git a/.idea/php.xml b/.idea/php.xml index c983c89..e97844c 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -98,6 +98,7 @@ + diff --git a/.idea/problem-details-symfony-bundle.iml b/.idea/problem-details-symfony-bundle.iml index 43a3eb2..a072eba 100644 --- a/.idea/problem-details-symfony-bundle.iml +++ b/.idea/problem-details-symfony-bundle.iml @@ -79,6 +79,7 @@ + diff --git a/composer.json b/composer.json index 7c62d7b..92f9e33 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ "phpmd/phpmd": "^2.5", "phpstan/phpstan": "^2.0", "phpunit/phpunit": "^11.5.0", - "squizlabs/php_codesniffer": "^3.7.2" + "squizlabs/php_codesniffer": "^3.7.2", + "symfony/yaml": "^7.2" }, "license": "MIT", "autoload": { diff --git a/composer.lock b/composer.lock index 0c69640..c30d181 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "332900e0eb2d63e20627d71802900c7a", + "content-hash": "a5bb9a914eb4413be9ad2b40ddd478cb", "packages": [ { "name": "psr/event-dispatcher", @@ -5236,6 +5236,78 @@ ], "time": "2024-10-18T07:58:17+00:00" }, + { + "name": "symfony/yaml", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "099581e99f557e9f16b43c5916c26380b54abb22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/099581e99f557e9f16b43c5916c26380b54abb22", + "reference": "099581e99f557e9f16b43c5916c26380b54abb22", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-23T06:56:12+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.3", @@ -5347,12 +5419,12 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": "^8.2" }, - "platform-dev": [], + "platform-dev": {}, "plugin-api-version": "2.6.0" } diff --git a/config/services.yaml b/config/services.yaml index 4448d51..14b47a6 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -12,21 +12,21 @@ services: arguments: $validationErrorsBuilder: '@Phauthentic\Symfony\ProblemDetails\Validation\ValidationErrorsBuilder' $problemDetailsResponseFactory: '@Phauthentic\Symfony\ProblemDetails\FromExceptionEventFactoryInterface' - tags: - - { name: 'phauthentic.problem_details.exception_converter' } + tags: ['phauthentic.problem_details.exception_converter'] Phauthentic\Symfony\ProblemDetails\ExceptionConversion\HttpExceptionConverter: arguments: $problemDetailsFactory: '@Phauthentic\Symfony\ProblemDetails\ProblemDetailsFactoryInterface' - tags: - - { name: 'phauthentic.problem_details.exception_converter' } + tags: ['phauthentic.problem_details.exception_converter'] Phauthentic\Symfony\ProblemDetails\ExceptionConversion\GenericExceptionConverter: - tags: - - { name: 'phauthentic.problem_details.exception_converter' } + arguments: + $problemDetailsFactory: '@Phauthentic\Symfony\ProblemDetails\ProblemDetailsFactoryInterface' + tags: ['phauthentic.problem_details.exception_converter'] Phauthentic\Symfony\ProblemDetails\ThrowableToProblemDetailsKernelListener: + public: true arguments: $exceptionConverters: !tagged_iterator phauthentic.problem_details.exception_converter tags: - - { name: 'kernel.event_listener', event: 'kernel.exception', priority: 0 } \ No newline at end of file + - { name: 'kernel.event_listener', event: 'kernel.exception', priority: 0 } diff --git a/readme.md b/readme.md index baa4437..70ed65f 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,9 @@ This bundle provides support for [RFC 9457](https://www.rfc-editor.org/rfc/rfc94 composer require phauthentic/problem-details-symfony-bundle ``` -## Docs +## Documentation + +Simply inject the `ProblemDetailsFactoryInterface` into your handlers and use it to create `ProblemDetails` responses. ```php class ExampleController @@ -37,6 +39,31 @@ class ExampleController } ``` +### Service Configuration + +To add more converters to the kernel listener, you can tag additional services with `phauthentic.problem_details.exception_converter`. They must implement the [ExceptionConverterInterface](src/ExceptionConversion/ExceptionConverterInterface.php). + +```yaml + Phauthentic\Symfony\ProblemDetails\ExceptionConversion\ValidationFailedExceptionConverter: + arguments: + $validationErrorsBuilder: '@Phauthentic\Symfony\ProblemDetails\Validation\ValidationErrorsBuilder' + $problemDetailsResponseFactory: '@Phauthentic\Symfony\ProblemDetails\FromExceptionEventFactoryInterface' + tags: ['phauthentic.problem_details.exception_converter'] +``` + +To completely override the list of already configured listeners override + +```yaml + Phauthentic\Symfony\ProblemDetails\ThrowableToProblemDetailsKernelListener: + public: true + arguments: + $exceptionConverters: !tagged_iterator phauthentic.problem_details.exception_converter + tags: + - { name: 'kernel.event_listener', event: 'kernel.exception', priority: 0 } +``` + +in your `services.yaml`. + ## Problem Details Example ```text diff --git a/src/ExceptionConversion/GenericExceptionConverter.php b/src/ExceptionConversion/GenericExceptionConverter.php index 6c4bb8d..d259a3e 100644 --- a/src/ExceptionConversion/GenericExceptionConverter.php +++ b/src/ExceptionConversion/GenericExceptionConverter.php @@ -15,13 +15,6 @@ * Notice that you might need to adjust the priority of the listener in your services.yaml file to make sure it is * executed in the right order if you have other listeners. * - * - * Phauthentic\Symfony\ProblemDetails\ThrowableToProblemDetailsKernelListener: - * arguments: ['%kernel.environment%', { }] - * tags: - * - { name: kernel.event_listener, event: kernel.exception, priority: -20 } - * - * * @link https://www.rfc-editor.org/rfc/rfc9457.html */ class GenericExceptionConverter implements ExceptionConverterInterface diff --git a/tests/Unit/ExceptionConversion/GenericThrowableConverterTest.php b/tests/Unit/ExceptionConversion/GenericExceptionConverterTest.php similarity index 97% rename from tests/Unit/ExceptionConversion/GenericThrowableConverterTest.php rename to tests/Unit/ExceptionConversion/GenericExceptionConverterTest.php index ea19946..6802f65 100644 --- a/tests/Unit/ExceptionConversion/GenericThrowableConverterTest.php +++ b/tests/Unit/ExceptionConversion/GenericExceptionConverterTest.php @@ -18,7 +18,7 @@ /** * */ -class GenericThrowableConverterTest extends TestCase +class GenericExceptionConverterTest extends TestCase { public function setUp(): void { diff --git a/tests/Unit/ServiceLoadingTest.php b/tests/Unit/ServiceLoadingTest.php new file mode 100644 index 0000000..187d00a --- /dev/null +++ b/tests/Unit/ServiceLoadingTest.php @@ -0,0 +1,47 @@ +load('services.yaml'); + $container->compile(); + + // Assert + $listener = $container->get(ThrowableToProblemDetailsKernelListener::class); + $this->assertInstanceOf(ThrowableToProblemDetailsKernelListener::class, $listener); + + $reflectionClass = new ReflectionClass($listener); + $converters = $reflectionClass->getProperty('exceptionConverters')->getValue($listener); + $result = []; + foreach ($converters as $converter) { + $result[] = get_class($converter); + } + $this->assertCount(3, $result); + $this->assertEquals([ + ValidationFailedExceptionConverter::class, + HttpExceptionConverter::class, + GenericExceptionConverter::class, + ], $result); + } +}