Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(json): allow normalizing stdClass to {} #548

Merged
merged 6 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 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 @@ -54,8 +55,11 @@ public function format(mixed $value): void
// afterward, this leads to a JSON array being written, while it
// should have been an object. This is a trade-off we accept,
// considering most generators starting at 0 are actually lists.
$isList = ($value instanceof Generator && $value->key() === 0)
|| (is_array($value) && array_is_list($value));
$isList = ! ($this->jsonEncodingOptions & JSON_FORCE_OBJECT)
&& (
($value instanceof Generator && $value->key() === 0)
|| (is_array($value) && array_is_list($value))
);

$isFirst = true;

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 'list' => [
'input' => ['foo', 'bar'],
'expected array' => ['foo', 'bar'],
'expected json' => '["foo","bar"]',
];

yield 'list kept as object in json' => [
'input' => ['foo', 'bar'],
'expected array' => ['foo', 'bar'],
'expected json' => '{"0":"foo","1":"bar"}',
[],
[],
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
Loading