From c61a43d654b544d35bc999a1279a557a874d6406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Sun, 30 Jul 2023 22:33:19 +0200 Subject: [PATCH] [Serializer] Add support for seld/jsonlint in order to enhance error messages --- composer.json | 1 + src/Symfony/Component/Serializer/CHANGELOG.md | 1 + .../Serializer/Encoder/JsonDecode.php | 27 ++++++++++++++++--- .../Tests/Encoder/JsonDecodeTest.php | 11 +++++--- .../Component/Serializer/composer.json | 1 + 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 18ca8b8195f6e..09909a3b703e1 100644 --- a/composer.json +++ b/composer.json @@ -150,6 +150,7 @@ "predis/predis": "^1.1|^2.0", "psr/http-client": "^1.0", "psr/simple-cache": "^1.0|^2.0|^3.0", + "seld/jsonlint": "^1.10", "symfony/mercure-bundle": "^0.3", "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", "symfony/runtime": "self.version", diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index 0fb810b06bcb9..17221fe61c039 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -7,6 +7,7 @@ CHANGELOG * Deprecate Doctrine annotations support in favor of native attributes * Deprecate passing an annotation reader to the constructor of `AnnotationLoader` * Allow the `Groups` attribute/annotation on classes + * JsonDecode: Add `json_decode_detailed_errors` option 6.3 --- diff --git a/src/Symfony/Component/Serializer/Encoder/JsonDecode.php b/src/Symfony/Component/Serializer/Encoder/JsonDecode.php index a9ca028451826..6875ff81c05dd 100644 --- a/src/Symfony/Component/Serializer/Encoder/JsonDecode.php +++ b/src/Symfony/Component/Serializer/Encoder/JsonDecode.php @@ -11,7 +11,9 @@ namespace Symfony\Component\Serializer\Encoder; +use Seld\JsonLint\JsonParser; use Symfony\Component\Serializer\Exception\NotEncodableValueException; +use Symfony\Component\Serializer\Exception\UnsupportedException; /** * Decodes JSON data. @@ -30,6 +32,11 @@ class JsonDecode implements DecoderInterface */ public const ASSOCIATIVE = 'json_decode_associative'; + /** + * True to enable seld/jsonlint as a source for more specific error messages when json_decode fails. + */ + public const DETAILED_ERROR_MESSAGES = 'json_decode_detailed_errors'; + public const OPTIONS = 'json_decode_options'; /** @@ -39,6 +46,7 @@ class JsonDecode implements DecoderInterface private array $defaultContext = [ self::ASSOCIATIVE => false, + self::DETAILED_ERROR_MESSAGES => false, self::OPTIONS => 0, self::RECURSION_DEPTH => 512, ]; @@ -69,6 +77,10 @@ public function __construct(array $defaultContext = []) * json_decode_options: integer * Specifies additional options as per documentation for json_decode * + * json_decode_detailed_errors: bool + * If true, enables seld/jsonlint as a source for more specific error messages when json_decode fails. + * If false or not specified, this method will use default error messages from PHP's json_decode + * * @throws NotEncodableValueException * * @see https://php.net/json_decode @@ -89,11 +101,20 @@ public function decode(string $data, string $format, array $context = []): mixed return $decodedData; } - if (\JSON_ERROR_NONE !== json_last_error()) { - throw new NotEncodableValueException(json_last_error_msg()); + if (\JSON_ERROR_NONE === json_last_error()) { + return $decodedData; + } + $errorMessage = json_last_error_msg(); + + if (!($context[self::DETAILED_ERROR_MESSAGES] ?? $this->defaultContext[self::DETAILED_ERROR_MESSAGES])) { + throw new NotEncodableValueException($errorMessage); + } + + if (!class_exists(JsonParser::class)) { + throw new UnsupportedException(sprintf('Enabling "%s" serializer option requires seld/jsonlint. Try running "composer require seld/jsonlint".', self::DETAILED_ERROR_MESSAGES)); } - return $decodedData; + throw new NotEncodableValueException((new JsonParser())->lint($data)?->getMessage() ?: $errorMessage); } public function supportsDecoding(string $format): bool diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php index ffef479e21f25..66cd10114cc90 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php @@ -58,17 +58,20 @@ public static function decodeProvider() /** * @dataProvider decodeProviderException */ - public function testDecodeWithException($value) + public function testDecodeWithException(string $value, string $expectedExceptionMessage, array $context) { $this->expectException(UnexpectedValueException::class); - $this->decode->decode($value, JsonEncoder::FORMAT); + $this->expectExceptionMessage($expectedExceptionMessage); + $this->decode->decode($value, JsonEncoder::FORMAT, $context); } public static function decodeProviderException() { return [ - ["{'foo': 'bar'}"], - ['kaboom!'], + ["{'foo': 'bar'}", 'Syntax error', []], + ["{'foo': 'bar'}", 'single quotes instead of double quotes', ['json_decode_detailed_errors' => true]], + ['kaboom!', 'Syntax error', ['json_decode_detailed_errors' => false]], + ['kaboom!', "Expected one of: 'STRING', 'NUMBER', 'NULL',", ['json_decode_detailed_errors' => true]], ]; } } diff --git a/src/Symfony/Component/Serializer/composer.json b/src/Symfony/Component/Serializer/composer.json index e0c646d292b2a..91b69a79ba287 100644 --- a/src/Symfony/Component/Serializer/composer.json +++ b/src/Symfony/Component/Serializer/composer.json @@ -22,6 +22,7 @@ }, "require-dev": { "doctrine/annotations": "^1.12|^2", + "seld/jsonlint": "^1.10", "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", "symfony/cache": "^5.4|^6.0|^7.0", "symfony/config": "^5.4|^6.0|^7.0", pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy