Skip to content

Commit

Permalink
feat(json): allow normalizing stdClass to {}
Browse files Browse the repository at this point in the history
- allow `JSON_FORCE_OBJECT` flag
  • Loading branch information
simPod committed Jul 23, 2024
1 parent ba22b52 commit 9a795a6
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 5 deletions.
7 changes: 7 additions & 0 deletions src/Normalizer/Formatter/JsonFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use function is_scalar;
use function json_encode;

use const JSON_FORCE_OBJECT;
use const JSON_THROW_ON_ERROR;

/** @internal */
Expand Down Expand Up @@ -45,6 +46,12 @@ public function format(mixed $value): void
} elseif ($value instanceof EmptyObject) {
$this->write('{}');
} elseif (is_iterable($value)) {
if ($value === [] && $this->jsonEncodingOptions & JSON_FORCE_OBJECT) {
$this->write('{}');

return;

}
// Note: when a generator is formatted, it is considered as a list
// if its first key is 0. This is done early because the first JSON
// character for an array differs from the one for an object, and we
Expand Down
4 changes: 3 additions & 1 deletion src/Normalizer/JsonNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use function is_resource;
use function stream_get_contents;

use const JSON_FORCE_OBJECT;
use const JSON_HEX_AMP;
use const JSON_HEX_APOS;
use const JSON_HEX_QUOT;
Expand All @@ -34,7 +35,8 @@
*/
final class JsonNormalizer implements Normalizer
{
private const ACCEPTABLE_JSON_OPTIONS = JSON_HEX_QUOT
private const ACCEPTABLE_JSON_OPTIONS = JSON_FORCE_OBJECT
| JSON_HEX_QUOT
| JSON_HEX_TAG
| JSON_HEX_AMP
| JSON_HEX_APOS
Expand Down
21 changes: 17 additions & 4 deletions tests/Integration/Normalizer/NormalizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

use function array_merge;

use const JSON_FORCE_OBJECT;
use const JSON_HEX_TAG;
use const JSON_THROW_ON_ERROR;

Expand Down Expand Up @@ -194,6 +195,21 @@ public static function normalize_basic_values_yields_expected_output_data_provid
'expected json' => '{"foo":"foo","bar":"bar"}',
];

yield 'empty stdClass' => [
'input' => (fn () => new stdClass())(),
'expected array' => [],
'expected json' => '[]',
];

yield 'empty stdClass kept as object in json' => [
'input' => (fn () => new stdClass())(),
'expected array' => [],
'expected json' => '{}',
[],
[],
JSON_FORCE_OBJECT
];

yield 'ArrayObject' => [
'input' => new ArrayObject(['foo' => 'foo', 'bar' => 'bar']),
'expected array' => [
Expand Down Expand Up @@ -1148,16 +1164,13 @@ public function test_json_transformer_will_always_throw_on_error(): void

public function test_json_transformer_only_accepts_acceptable_json_options(): void
{
$normalizer = $this->mapperBuilder()->normalizer(Format::json())->withOptions(JSON_FORCE_OBJECT);
self::assertSame(JSON_THROW_ON_ERROR, (fn () => $this->jsonEncodingOptions)->call($normalizer));

$normalizer = $this->mapperBuilder()->normalizer(Format::json())->withOptions(JSON_PARTIAL_OUTPUT_ON_ERROR);
self::assertSame(JSON_THROW_ON_ERROR, (fn () => $this->jsonEncodingOptions)->call($normalizer));

$normalizer = $this->mapperBuilder()->normalizer(Format::json())->withOptions(JSON_PRETTY_PRINT);
self::assertSame(JSON_THROW_ON_ERROR, (fn () => $this->jsonEncodingOptions)->call($normalizer));

$normalizer = $this->mapperBuilder()->normalizer(Format::json())->withOptions(JSON_FORCE_OBJECT | JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_PRETTY_PRINT);
$normalizer = $this->mapperBuilder()->normalizer(Format::json())->withOptions(JSON_PARTIAL_OUTPUT_ON_ERROR | JSON_PRETTY_PRINT);
self::assertSame(JSON_THROW_ON_ERROR, (fn () => $this->jsonEncodingOptions)->call($normalizer));
}
}
Expand Down

0 comments on commit 9a795a6

Please sign in to comment.