Skip to content

Commit 7d8dcba

Browse files
author
Marcin Czarnecki
committed
feat(unions): Add support for simple arrays
1 parent a093b21 commit 7d8dcba

File tree

5 files changed

+34
-37
lines changed

5 files changed

+34
-37
lines changed

src/Handler/UnionHandler.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,15 @@ private function matchSimpleType(mixed $data, array $type, Context $context): mi
115115

116116
private function isPrimitiveType(string $type): bool
117117
{
118-
return in_array($type, ['int', 'integer', 'float', 'double', 'bool', 'boolean', 'string'], true);
118+
return in_array($type, ['int', 'integer', 'float', 'double', 'bool', 'boolean', 'string', 'array'], true);
119119
}
120120

121121
private function testPrimitive(mixed $data, string $type, string $format): bool
122122
{
123123
switch ($type) {
124+
case 'array':
125+
return is_array($data);
126+
124127
case 'integer':
125128
case 'int':
126129
return (string) (int) $data === (string) $data;
@@ -134,7 +137,7 @@ private function testPrimitive(mixed $data, string $type, string $format): bool
134137
return (string) (bool) $data === (string) $data;
135138

136139
case 'string':
137-
return (string) $data === (string) $data;
140+
return is_string($data);
138141
}
139142

140143
return false;

src/Metadata/Driver/TypedPropertiesDriver.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ public function __construct(DriverInterface $delegate, ?ParserInterface $typePar
6060
private function reorderTypes(array $types): array
6161
{
6262
uasort($types, static function ($a, $b) {
63-
$order = ['null' => 0, 'true' => 1, 'false' => 2, 'bool' => 3, 'int' => 4, 'float' => 5, 'string' => 6];
63+
$order = ['null' => 0, 'true' => 1, 'false' => 2, 'bool' => 3, 'int' => 4, 'float' => 5, 'array' => 6, 'string' => 7];
6464

65-
return ($order[$a['name']] ?? 7) <=> ($order[$b['name']] ?? 7);
65+
return ($order[$a['name']] ?? 8) <=> ($order[$b['name']] ?? 8);
6666
});
6767

6868
return $types;
@@ -117,7 +117,7 @@ public function loadMetadataForClass(ReflectionClass $class): ?ClassMetadata
117117
$this->reorderTypes(
118118
array_map(
119119
fn (string $type) => $this->typeParser->parse($type),
120-
array_filter($reflectionType->getTypes(), [$this, 'shouldTypeHint']),
120+
array_filter($reflectionType->getTypes(), [$this, 'shouldTypeHintInsideUnion']),
121121
),
122122
),
123123
],
@@ -179,11 +179,16 @@ private function shouldTypeHintUnion(?ReflectionType $reflectionType)
179179
}
180180

181181
foreach ($reflectionType->getTypes() as $type) {
182-
if ($this->shouldTypeHint($type)) {
182+
if ($this->shouldTypeHintInsideUnion($type)) {
183183
return true;
184184
}
185185
}
186186

187187
return false;
188188
}
189+
190+
private function shouldTypeHintInsideUnion(?ReflectionType $reflectionType)
191+
{
192+
return $this->shouldTypeHint($reflectionType) || 'array' === $reflectionType->getName();
193+
}
189194
}

tests/Fixtures/TypedProperties/UnionTypedProperties.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
class UnionTypedProperties
88
{
9-
private int|bool|float|string $data;
9+
private int|bool|float|string|array $data;
1010

1111
private int|bool|float|string|null $nullableData;
1212

tests/Metadata/Driver/UnionTypedPropertiesDriverTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ public function testInferUnionTypesShouldResultInManyTypes()
3434
'params' =>
3535
[
3636
[
37+
[
38+
'name' => 'array',
39+
'params' => [],
40+
],
3741
[
3842
'name' => 'string',
3943
'params' => [],

tests/Serializer/JsonSerializationTest.php

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ protected static function getContent($key)
151151
$outputs['data_float'] = '{"data":1.236}';
152152
$outputs['data_bool'] = '{"data":false}';
153153
$outputs['data_string'] = '{"data":"foo"}';
154+
$outputs['data_array'] = '{"data":[1,2,3]}';
154155
$outputs['data_author'] = '{"data":{"full_name":"foo"}}';
155156
$outputs['data_comment'] = '{"data":{"author":{"full_name":"foo"},"text":"bar"}}';
156157
$outputs['data_discriminated_author'] = '{"data":{"full_name":"foo","objectType":"author"}}';
@@ -438,46 +439,30 @@ public static function getTypeHintedArraysAndStdClass()
438439
];
439440
}
440441

441-
public function testDeserializingUnionProperties()
442+
public static function getSimpleUnionProperties(): iterable
442443
{
443-
if (PHP_VERSION_ID < 80000) {
444-
$this->markTestSkipped(sprintf('%s requires PHP 8.0', TypedPropertiesDriver::class));
445-
446-
return;
447-
}
448-
449-
$object = new UnionTypedProperties(10000);
450-
self::assertEquals($object, $this->deserialize(static::getContent('data_integer'), UnionTypedProperties::class));
451-
452-
$object = new UnionTypedProperties(1.236);
453-
self::assertEquals($object, $this->deserialize(static::getContent('data_float'), UnionTypedProperties::class));
454-
455-
$object = new UnionTypedProperties(false);
456-
self::assertEquals($object, $this->deserialize(static::getContent('data_bool'), UnionTypedProperties::class));
457-
458-
$object = new UnionTypedProperties('foo');
459-
self::assertEquals($object, $this->deserialize(static::getContent('data_string'), UnionTypedProperties::class));
444+
yield 'int' => [10000, 'data_integer'];
445+
yield [1.236, 'data_float'];
446+
yield [false, 'data_bool'];
447+
yield ['foo', 'data_string'];
448+
yield [[1, 2, 3], 'data_array'];
460449
}
461450

462-
public function testSerializingUnionProperties()
451+
/**
452+
* @dataProvider getSimpleUnionProperties
453+
*/
454+
#[DataProvider('getSimpleUnionProperties')]
455+
public function testUnionProperties(mixed $data, string $expected): void
463456
{
464457
if (PHP_VERSION_ID < 80000) {
465458
$this->markTestSkipped(sprintf('%s requires PHP 8.0', TypedPropertiesDriver::class));
466459

467460
return;
468461
}
469462

470-
$serialized = $this->serialize(new UnionTypedProperties(10000));
471-
self::assertEquals(static::getContent('data_integer'), $serialized);
472-
473-
$serialized = $this->serialize(new UnionTypedProperties(1.236));
474-
self::assertEquals(static::getContent('data_float'), $serialized);
475-
476-
$serialized = $this->serialize(new UnionTypedProperties(false));
477-
self::assertEquals(static::getContent('data_bool'), $serialized);
478-
479-
$serialized = $this->serialize(new UnionTypedProperties('foo'));
480-
self::assertEquals(static::getContent('data_string'), $serialized);
463+
$object = new UnionTypedProperties($data);
464+
self::assertEquals($object, $this->deserialize(static::getContent($expected), UnionTypedProperties::class));
465+
self::assertEquals($this->serialize($object), static::getContent($expected));
481466
}
482467

483468
public function testDeserializingComplexDiscriminatedUnionProperties()

0 commit comments

Comments
 (0)