From 0de9eca17e4e7bf896f0bbb36f28bf0dc34e3b61 Mon Sep 17 00:00:00 2001 From: Alex Wells Date: Tue, 31 Oct 2023 01:46:33 +0200 Subject: [PATCH] fix: Serialize empty "map" arrays as objects in JSON --- .../Primitive/BuiltIn/ArrayMapper.php | 17 ++++++++++++++++- tests/Integration/JsonSerializationTest.php | 7 ++++--- tests/Stubs/ClassStub.php | 2 ++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/GoodPhp/Serialization/TypeAdapter/Primitive/BuiltIn/ArrayMapper.php b/src/GoodPhp/Serialization/TypeAdapter/Primitive/BuiltIn/ArrayMapper.php index 652751f..44e4773 100644 --- a/src/GoodPhp/Serialization/TypeAdapter/Primitive/BuiltIn/ArrayMapper.php +++ b/src/GoodPhp/Serialization/TypeAdapter/Primitive/BuiltIn/ArrayMapper.php @@ -3,6 +3,7 @@ namespace GoodPhp\Serialization\TypeAdapter\Primitive\BuiltIn; use Exception; +use GoodPhp\Reflection\Type\PrimitiveType; use GoodPhp\Reflection\Type\Type; use GoodPhp\Serialization\Serializer; use GoodPhp\Serialization\TypeAdapter\Exception\CollectionItemMappingException; @@ -21,8 +22,18 @@ final class ArrayMapper * @return array */ #[MapTo(PrimitiveTypeAdapter::class)] - public function to(array $value, Type $type, Serializer $serializer): array + public function to(array $value, Type $type, Serializer $serializer): array|\stdClass { + if ($value === []) { + // Make sure that map arrays are serialized as object. To do so, we'll return an stdClass instead of + // an array so the upper layer can serialize it as an object, not an empty array. + if ($type->arguments[0]->equals(PrimitiveType::string())) { + return new \stdClass(); + } + + return $value; + } + $itemAdapter = $serializer->adapter(PrimitiveTypeAdapter::class, $type->arguments[1]); return MultipleMappingException::map( @@ -45,6 +56,10 @@ public function to(array $value, Type $type, Serializer $serializer): array #[MapFrom(PrimitiveTypeAdapter::class)] public function from(array $value, Type $type, Serializer $serializer): array { + if ($value === []) { + return $value; + } + $itemAdapter = $serializer->adapter(PrimitiveTypeAdapter::class, $type->arguments[1]); return MultipleMappingException::map( diff --git a/tests/Integration/JsonSerializationTest.php b/tests/Integration/JsonSerializationTest.php index 67c9bc5..561d3a6 100644 --- a/tests/Integration/JsonSerializationTest.php +++ b/tests/Integration/JsonSerializationTest.php @@ -144,9 +144,10 @@ public function serializesProvider(): Generator 123, MissingValue::INSTANCE, new NestedStub('flattened'), - new CarbonImmutable('2020-01-01 00:00:00') + new CarbonImmutable('2020-01-01 00:00:00'), + ['Some key' => 'Some value'] ), - '{"primitive":1,"nested":{"Field":"something"},"date":"2020-01-01T00:00:00.000000Z","optional":123,"nullable":123,"Field":"flattened","carbonImmutable":"2020-01-01T00:00:00.000000Z"}', + '{"primitive":1,"nested":{"Field":"something"},"date":"2020-01-01T00:00:00.000000Z","optional":123,"nullable":123,"Field":"flattened","carbonImmutable":"2020-01-01T00:00:00.000000Z","other":{"Some key":"Some value"}}', ]; yield 'ClassStub with empty optional and null nullable' => [ @@ -166,7 +167,7 @@ public function serializesProvider(): Generator new NestedStub('flattened'), new CarbonImmutable('2020-01-01 00:00:00') ), - '{"primitive":1,"nested":{"Field":"something"},"date":"2020-01-01T00:00:00.000000Z","nullable":null,"Field":"flattened","carbonImmutable":"2020-01-01T00:00:00.000000Z"}', + '{"primitive":1,"nested":{"Field":"something"},"date":"2020-01-01T00:00:00.000000Z","nullable":null,"Field":"flattened","carbonImmutable":"2020-01-01T00:00:00.000000Z","other":{}}', ]; } diff --git a/tests/Stubs/ClassStub.php b/tests/Stubs/ClassStub.php index 5bfbcdd..2c2ba32 100644 --- a/tests/Stubs/ClassStub.php +++ b/tests/Stubs/ClassStub.php @@ -26,6 +26,8 @@ public function __construct( #[Flatten] public NestedStub $flattened, public readonly CarbonImmutable $carbonImmutable, + /** @var array */ + public readonly array $other = [], ) { }