diff --git a/src/Hydrator/HydratorUtil.php b/src/Hydrator/HydratorUtil.php index 4046bda..d0e5071 100644 --- a/src/Hydrator/HydratorUtil.php +++ b/src/Hydrator/HydratorUtil.php @@ -335,6 +335,43 @@ public static function extractEnums(array $data, array $arrayProperties, array $ return $data; } + /** + * @param array $data + * @param array>> $unions + */ + public static function extractUnions(array $data, array $arrayProperties, array $unions): array + { + foreach ($unions as $property => $union) { + $value = $data[$property]; + if (in_array($property, $arrayProperties, true)) { + assert(is_array($value)); + $unionValues = []; + /** @var object $unionValue */ + foreach ($value as $unionValue) { + $unionValues[] = self::extractUnion($unionValue, $union); + } + $data[$property] = $unionValues; + } else { + assert(is_object($value)); + $data[$property] = self::extractUnion($value, $union); + } + } + + return $data; + } + + /** + * @param array> $union + */ + public static function extractUnion(object $object, array $union): bool|array|float|int|string|null + { + if (! isset($union[$object::class])) { + return null; + } + $extractor = $union[$object::class]; + return $extractor::extract($object); + } + /** * @param array> $extractors */ diff --git a/test/Hydrator/Asset/ExtractableHydrator.php b/test/Hydrator/Asset/ExtractableHydrator.php new file mode 100644 index 0000000..5a06b01 --- /dev/null +++ b/test/Hydrator/Asset/ExtractableHydrator.php @@ -0,0 +1,32 @@ + $object->getOne(), + 'two' => $object->getTwo(), + 'three' => $object->isThree(), + ]; + } +} diff --git a/test/Hydrator/Asset/SecondExtractable.php b/test/Hydrator/Asset/SecondExtractable.php new file mode 100644 index 0000000..7d31666 --- /dev/null +++ b/test/Hydrator/Asset/SecondExtractable.php @@ -0,0 +1,17 @@ +value; + } +} diff --git a/test/Hydrator/Asset/SecondExtractableHydrator.php b/test/Hydrator/Asset/SecondExtractableHydrator.php new file mode 100644 index 0000000..5d8e49e --- /dev/null +++ b/test/Hydrator/Asset/SecondExtractableHydrator.php @@ -0,0 +1,27 @@ + $object->getValue(), + ]; + } +} diff --git a/test/Hydrator/HydratorUtilTest.php b/test/Hydrator/HydratorUtilTest.php index a89ad7b..8e11da8 100644 --- a/test/Hydrator/HydratorUtilTest.php +++ b/test/Hydrator/HydratorUtilTest.php @@ -11,8 +11,11 @@ use Kynx\Mezzio\OpenApi\Hydrator\Exception\MissingDiscriminatorException; use Kynx\Mezzio\OpenApi\Hydrator\HydratorUtil; use KynxTest\Mezzio\OpenApi\Hydrator\Asset\Extractable; +use KynxTest\Mezzio\OpenApi\Hydrator\Asset\ExtractableHydrator; use KynxTest\Mezzio\OpenApi\Hydrator\Asset\GoodHydrator; use KynxTest\Mezzio\OpenApi\Hydrator\Asset\MockEnum; +use KynxTest\Mezzio\OpenApi\Hydrator\Asset\SecondExtractable; +use KynxTest\Mezzio\OpenApi\Hydrator\Asset\SecondExtractableHydrator; use KynxTest\Mezzio\OpenApi\Hydrator\Asset\TypeErrorHydrator; use PHPUnit\Framework\TestCase; use stdClass; @@ -494,6 +497,71 @@ public function testExtractEnumsExtrasSingleEnum(): void self::assertSame($expected, $actual); } + public function testExtractUnionsExtractsArrayOfUnions(): void + { + $expected = [ + 'items' => [ + ['one' => 'a', 'two' => 2, 'three' => true], + ], + ]; + $data = [ + 'items' => [ + new Extractable('a', 2, true), + ], + ]; + $unions = [ + 'items' => [ + Extractable::class => ExtractableHydrator::class, + ], + ]; + + $actual = HydratorUtil::extractUnions($data, ['items'], $unions); + self::assertSame($expected, $actual); + } + + public function testExtractUnionsExtractsSingleUnion(): void + { + $expected = [ + 'item' => ['one' => 'a', 'two' => 2, 'three' => true], + ]; + $data = [ + 'item' => new Extractable('a', 2, true), + ]; + $unions = [ + 'item' => [ + Extractable::class => ExtractableHydrator::class, + ], + ]; + + $actual = HydratorUtil::extractUnions($data, ['foo'], $unions); + self::assertSame($expected, $actual); + } + + /** + * @dataProvider extractUnionProvider + */ + public function testExtractUnionExtractsCorrectClass(object $extractable, array $expected): void + { + $union = [ + Extractable::class => ExtractableHydrator::class, + SecondExtractable::class => SecondExtractableHydrator::class, + ]; + + $actual = HydratorUtil::extractUnion($extractable, $union); + self::assertSame($expected, $actual); + } + + /** + * @return array + */ + public static function extractUnionProvider(): array + { + return [ + 'first' => [new Extractable('a', 2, true), ['one' => 'a', 'two' => 2, 'three' => true]], + 'second' => [new SecondExtractable('foo'), ['value' => 'foo']], + ]; + } + public function testExtractEnumsExtractsArrayOfEnums(): void { $expected = [