From f10bfec0f8a03839d390da36818b9730d5c202b8 Mon Sep 17 00:00:00 2001 From: Awilum Date: Fri, 15 Apr 2022 15:46:21 +0300 Subject: [PATCH] feat(serializers): add json5 serializer --- composer.json | 3 +- src/flextype/core/Serializers/Json5.php | 116 ++++++++++++++++++ src/flextype/core/Serializers/Serializers.php | 8 ++ src/flextype/settings.yaml | 9 ++ .../flextype/core/Serializers/Json5Test.php | 25 ++++ 5 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/flextype/core/Serializers/Json5.php create mode 100644 tests/src/flextype/core/Serializers/Json5Test.php diff --git a/composer.json b/composer.json index 60b31b05..e1dbad29 100755 --- a/composer.json +++ b/composer.json @@ -60,7 +60,8 @@ "filp/whoops": "^2.14.5", "symfony/console": "^5.4.3", "symfony/var-exporter": "^5.4.3", - "thermage/thermage": "^0.19.0" + "thermage/thermage": "^0.19.0", + "colinodell/json5": "^2.2" }, "suggest": { "ext-zend-opcache": "Recommended for better performance", diff --git a/src/flextype/core/Serializers/Json5.php b/src/flextype/core/Serializers/Json5.php new file mode 100644 index 00000000..0b864079 --- /dev/null +++ b/src/flextype/core/Serializers/Json5.php @@ -0,0 +1,116 @@ +get('flextype.settings.serializers.json5.encode.options'); + $depth = registry()->get('flextype.settings.serializers.json5.encode.depth'); + + $options = ($options & self::ESCAPE_UNICODE ? 0 : JSON_UNESCAPED_UNICODE) + | JSON_UNESCAPED_SLASHES + | ($options & self::PRETTY ? JSON_PRETTY_PRINT : 0) + | (defined('JSON_PRESERVE_ZERO_FRACTION') ? JSON_PRESERVE_ZERO_FRACTION : 0); + + $json = json_encode($input, $options, $depth); + + if ($error = json_last_error()) { + throw new RuntimeException(json_last_error_msg(), $error); + } + + return $json; + } + + /** + * Takes a JSON5 encoded string and converts it into a PHP variable. + * + * @param string $input A string containing JSON5. + * + * @return mixed The JSON5 converted to a PHP value. + * + * @throws RuntimeException If the JSON5 is not valid. + */ + public function decode(string $input) + { + $cache = registry()->get('flextype.settings.serializers.json5.decode.cache'); + $assoc = registry()->get('flextype.settings.serializers.json5.decode.assoc'); + $depth = registry()->get('flextype.settings.serializers.json5.decode.depth'); + $flags = registry()->get('flextype.settings.serializers.json5.decode.flags'); + + $decode = static function (string $input, bool $assoc, int $depth, int $flags) { + return json5_decode($input, $assoc, $depth, $flags);; + }; + + if ($cache === true && registry()->get('flextype.settings.cache.enabled') === true) { + $key = $this->getCacheID($input); + + if ($dataFromCache = cache()->get($key)) { + return $dataFromCache; + } + + $data = $decode($input, $assoc, $depth, $flags); + cache()->set($key, $data); + + return $data; + } + + return $decode($input, $assoc, $depth, $flags); + } + + /** + * Get Cache ID for JSON5. + * + * @param string $input Input. + * + * @return string Cache ID. + * + * @access public + */ + public function getCacheID(string $input): string + { + return strings('json5' . $input)->hash()->toString(); + } +} diff --git a/src/flextype/core/Serializers/Serializers.php b/src/flextype/core/Serializers/Serializers.php index f2e9193a..4b0fdfa0 100644 --- a/src/flextype/core/Serializers/Serializers.php +++ b/src/flextype/core/Serializers/Serializers.php @@ -30,6 +30,14 @@ class Serializers return new Json(); } + /** + * Create a Json instance. + */ + public function json5(): Json5 + { + return new Json5(); + } + /** * Create a Yaml instance. */ diff --git a/src/flextype/settings.yaml b/src/flextype/settings.yaml index f6e8bcf3..48f32862 100644 --- a/src/flextype/settings.yaml +++ b/src/flextype/settings.yaml @@ -433,6 +433,15 @@ serializers: encode: options: 0 depth: 512 + json5: + decode: + cache: true + assoc: true + depth: 512 + flags: 0 + encode: + options: 0 + depth: 512 yaml: decode: cache: true diff --git a/tests/src/flextype/core/Serializers/Json5Test.php b/tests/src/flextype/core/Serializers/Json5Test.php new file mode 100644 index 00000000..82e3791a --- /dev/null +++ b/tests/src/flextype/core/Serializers/Json5Test.php @@ -0,0 +1,25 @@ +assertEquals('{"title":"Foo","content":"Bar"}', + serializers()->json5() + ->encode(['title' => 'Foo', + 'content' => 'Bar'])); +}); + +test('decode', function () { + $this->assertEquals(['title' => 'Foo', + 'content' => 'Bar'], + serializers()->json5() + ->decode('{"title":"Foo","content":"Bar"}')); +}); + +test('get cache ID', function () { + $string = '{"title":"Foo","content":"Bar"}'; + $cache_id = serializers()->json5() + ->getCacheID($string); + $this->assertEquals(32, strlen($cache_id)); + $this->assertNotEquals($string, $cache_id); +});