From 62f7bb48072177cc81f95338138378b9ce8b42b9 Mon Sep 17 00:00:00 2001 From: Greg Tyler Date: Mon, 11 Nov 2024 15:27:31 +0000 Subject: [PATCH 1/3] Support value types in serialization Allows serialization of value types (i.e. `true` and `false`, as opposed to `bool`), including in union types (e.g. `string|false`). Otherwise, tries to create class with FQCN "true" and, for union types, filters out value types as non-primitive. Fixes #1568 --- .../SerializationGraphNavigator.php | 2 ++ src/Metadata/Driver/TypedPropertiesDriver.php | 2 ++ .../TypedProperties/UnionTypedProperties.php | 2 ++ .../Driver/UnionTypedPropertiesDriverTest.php | 25 +++++++++++++++++++ 4 files changed, 31 insertions(+) diff --git a/src/GraphNavigator/SerializationGraphNavigator.php b/src/GraphNavigator/SerializationGraphNavigator.php index 52d1543da..431eba7d0 100644 --- a/src/GraphNavigator/SerializationGraphNavigator.php +++ b/src/GraphNavigator/SerializationGraphNavigator.php @@ -156,6 +156,8 @@ public function accept($data, ?array $type = null) case 'bool': case 'boolean': + case 'true': + case 'false': return $this->visitor->visitBoolean((bool) $data, $type); case 'double': diff --git a/src/Metadata/Driver/TypedPropertiesDriver.php b/src/Metadata/Driver/TypedPropertiesDriver.php index 15c4f9d67..2e7af8a66 100644 --- a/src/Metadata/Driver/TypedPropertiesDriver.php +++ b/src/Metadata/Driver/TypedPropertiesDriver.php @@ -75,6 +75,8 @@ private function getDefaultWhiteList(): array 'float', 'bool', 'boolean', + 'true', + 'false', 'string', 'double', 'iterable', diff --git a/tests/Fixtures/TypedProperties/UnionTypedProperties.php b/tests/Fixtures/TypedProperties/UnionTypedProperties.php index d7f40dde2..f88de896b 100644 --- a/tests/Fixtures/TypedProperties/UnionTypedProperties.php +++ b/tests/Fixtures/TypedProperties/UnionTypedProperties.php @@ -10,6 +10,8 @@ class UnionTypedProperties private int|bool|float|string|null $nullableData; + private string|false $valueTypedUnion; + public function __construct($data) { $this->data = $data; diff --git a/tests/Metadata/Driver/UnionTypedPropertiesDriverTest.php b/tests/Metadata/Driver/UnionTypedPropertiesDriverTest.php index 5fbfd0935..1da90bfd4 100644 --- a/tests/Metadata/Driver/UnionTypedPropertiesDriverTest.php +++ b/tests/Metadata/Driver/UnionTypedPropertiesDriverTest.php @@ -57,6 +57,31 @@ public function testInferUnionTypesShouldResultInManyTypes() ); } + public function testInferUnionTypesShouldIncludeValueTypes() + { + $m = $this->resolve(UnionTypedProperties::class); + + self::assertEquals( + [ + 'name' => 'union', + 'params' => + [ + [ + [ + 'name' => 'string', + 'params' => [], + ], + [ + 'name' => 'false', + 'params' => [], + ], + ], + ], + ], + $m->propertyMetadata['valueTypedUnion']->type, + ); + } + private function resolve(string $classToResolve): ClassMetadata { $namingStrategy = new IdenticalPropertyNamingStrategy(); From dddb91a673c3e1263880d32a54df034350617f59 Mon Sep 17 00:00:00 2001 From: Greg Tyler Date: Mon, 18 Nov 2024 09:46:27 +0000 Subject: [PATCH 2/3] Add end to end tests for False types From `ea7f7be4cb6ca2d1ed5e156b57f1413be8936e82`, but I can't cherry-pick because it's cross-remote --- .../DeserializationGraphNavigator.php | 2 ++ tests/Fixtures/DataFalse.php | 13 +++++++++ tests/Fixtures/DataTrue.php | 10 +++++++ tests/Serializer/JsonSerializationTest.php | 27 +++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 tests/Fixtures/DataFalse.php create mode 100644 tests/Fixtures/DataTrue.php diff --git a/src/GraphNavigator/DeserializationGraphNavigator.php b/src/GraphNavigator/DeserializationGraphNavigator.php index a29e43c12..edf1e6a68 100644 --- a/src/GraphNavigator/DeserializationGraphNavigator.php +++ b/src/GraphNavigator/DeserializationGraphNavigator.php @@ -128,6 +128,8 @@ public function accept($data, ?array $type = null) case 'bool': case 'boolean': + case 'false': + case 'true': return $this->visitor->visitBoolean($data, $type); case 'double': diff --git a/tests/Fixtures/DataFalse.php b/tests/Fixtures/DataFalse.php new file mode 100644 index 000000000..ce3d2632f --- /dev/null +++ b/tests/Fixtures/DataFalse.php @@ -0,0 +1,13 @@ +markTestSkipped('False type requires PHP 8.2'); + return; + } + + self::assertEquals( + static::getContent('data_false'), + $this->serialize(new DataFalse(false)), + ); + + self::assertEquals( + new DataFalse(false), + $this->deserialize(static::getContent('data_false'), DataFalse::class), + ); + + //What should we expect here? + self::assertEquals( + null, + $this->deserialize(static::getContent('data_true'), DataFalse::class), + ); + } + public function testDeserializingComplexDiscriminatedUnionProperties() { if (PHP_VERSION_ID < 80000) { From 9538cce87652cfe355af8f95febc3869319faea5 Mon Sep 17 00:00:00 2001 From: Greg Tyler Date: Mon, 18 Nov 2024 10:57:06 +0000 Subject: [PATCH 3/3] Fix PHPUnit/PHPCS errors --- tests/Fixtures/DataFalse.php | 5 +++- tests/Fixtures/DataTrue.php | 6 ++++ tests/Serializer/JsonSerializationTest.php | 32 ++++++++++++++++++---- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/tests/Fixtures/DataFalse.php b/tests/Fixtures/DataFalse.php index ce3d2632f..5c7301cf8 100644 --- a/tests/Fixtures/DataFalse.php +++ b/tests/Fixtures/DataFalse.php @@ -6,8 +6,11 @@ class DataFalse { + public false $data; + public function __construct( - public false $data + false $data ) { + $this->data = $data; } } diff --git a/tests/Fixtures/DataTrue.php b/tests/Fixtures/DataTrue.php index 0bfe05b68..9e3f2b09f 100644 --- a/tests/Fixtures/DataTrue.php +++ b/tests/Fixtures/DataTrue.php @@ -7,4 +7,10 @@ class DataTrue { public true $data; + + public function __construct( + true $data + ) { + $this->data = $data; + } } diff --git a/tests/Serializer/JsonSerializationTest.php b/tests/Serializer/JsonSerializationTest.php index 7f59ca0d7..b41c771df 100644 --- a/tests/Serializer/JsonSerializationTest.php +++ b/tests/Serializer/JsonSerializationTest.php @@ -16,6 +16,7 @@ use JMS\Serializer\Tests\Fixtures\Author; use JMS\Serializer\Tests\Fixtures\AuthorList; use JMS\Serializer\Tests\Fixtures\DataFalse; +use JMS\Serializer\Tests\Fixtures\DataTrue; use JMS\Serializer\Tests\Fixtures\DiscriminatedAuthor; use JMS\Serializer\Tests\Fixtures\DiscriminatedComment; use JMS\Serializer\Tests\Fixtures\FirstClassMapCollection; @@ -28,6 +29,7 @@ use JMS\Serializer\Visitor\Factory\JsonSerializationVisitorFactory; use JMS\Serializer\Visitor\SerializationVisitorInterface; use PHPUnit\Framework\Attributes\DataProvider; +use TypeError; class JsonSerializationTest extends BaseSerializationTestCase { @@ -483,10 +485,33 @@ public function testSerializingUnionProperties() self::assertEquals(static::getContent('data_string'), $serialized); } + public function testTrueDataType() + { + if (PHP_VERSION_ID < 80200) { + $this->markTestSkipped('True type requires PHP 8.2'); + + return; + } + + self::assertEquals( + static::getContent('data_true'), + $this->serialize(new DataTrue(true)), + ); + + self::assertEquals( + new DataTrue(true), + $this->deserialize(static::getContent('data_true'), DataTrue::class), + ); + + $this->expectException(TypeError::class); + $this->deserialize(static::getContent('data_false'), DataTrue::class); + } + public function testFalseDataType() { if (PHP_VERSION_ID < 80200) { $this->markTestSkipped('False type requires PHP 8.2'); + return; } @@ -500,11 +525,8 @@ public function testFalseDataType() $this->deserialize(static::getContent('data_false'), DataFalse::class), ); - //What should we expect here? - self::assertEquals( - null, - $this->deserialize(static::getContent('data_true'), DataFalse::class), - ); + $this->expectException(TypeError::class); + $this->deserialize(static::getContent('data_true'), DataFalse::class); } public function testDeserializingComplexDiscriminatedUnionProperties()