Skip to content

Commit bc692db

Browse files
committed
use class normalizer
1 parent 163b37b commit bc692db

7 files changed

Lines changed: 73 additions & 16 deletions

File tree

src/Hydrator.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ interface Hydrator
88
{
99
/**
1010
* @param class-string<T> $class
11-
* @param array<string, mixed> $data
1211
* @param array<string, mixed> $context
1312
*
1413
* @return T
@@ -17,12 +16,8 @@ interface Hydrator
1716
*
1817
* @template T of object
1918
*/
20-
public function hydrate(string $class, array $data, array $context = []): object;
19+
public function hydrate(string $class, mixed $data, array $context = []): object;
2120

22-
/**
23-
* @param array<string, mixed> $context
24-
*
25-
* @return array<string, mixed>
26-
*/
27-
public function extract(object $object, array $context = []): array;
21+
/** @param array<string, mixed> $context */
22+
public function extract(object $object, array $context = []): mixed;
2823
}

src/Metadata/AttributeMetadataFactory.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Patchlevel\Hydrator\Normalizer\ArrayNormalizer;
1313
use Patchlevel\Hydrator\Normalizer\ArrayShapeNormalizer;
1414
use Patchlevel\Hydrator\Normalizer\Normalizer;
15+
use Patchlevel\Hydrator\Normalizer\ObjectNormalizer;
1516
use Patchlevel\Hydrator\Normalizer\TypeAwareNormalizer;
1617
use ReflectionAttribute;
1718
use ReflectionClass;
@@ -73,6 +74,7 @@ private function getClassMetadata(ReflectionClass $reflectionClass): ClassMetada
7374
{
7475
$metadata = new ClassMetadata(
7576
$reflectionClass,
77+
$this->getNormalizerOnClass($reflectionClass),
7678
$this->getPropertyMetadataList($reflectionClass),
7779
$this->getLazy($reflectionClass),
7880
);
@@ -189,6 +191,7 @@ private function mergeMetadata(ClassMetadata $parent, ClassMetadata $child): Cla
189191

190192
return new ClassMetadata(
191193
$parent->reflection,
194+
$child->normalizer ?? $parent->normalizer,
192195
array_values($properties),
193196
$child->lazy ?? $parent->lazy,
194197
array_merge($parent->extras, $child->extras),
@@ -212,6 +215,22 @@ private function getNormalizer(ReflectionProperty $reflectionProperty): Normaliz
212215
return $normalizer;
213216
}
214217

218+
private function getNormalizerOnClass(ReflectionClass $reflectionClass): Normalizer|null
219+
{
220+
$type = Type::object($reflectionClass->getName());
221+
$normalizer = $this->inferNormalizerByType($type);
222+
223+
if ($normalizer instanceof ObjectNormalizer) {
224+
return null;
225+
}
226+
227+
if ($normalizer instanceof TypeAwareNormalizer) {
228+
$normalizer->handleType($type);
229+
}
230+
231+
return $normalizer;
232+
}
233+
215234
private function findNormalizerOnProperty(ReflectionProperty $reflectionProperty): Normalizer|null
216235
{
217236
/** @var list<ReflectionAttribute<Normalizer>> $attributeReflectionList */

src/Metadata/ClassMetadata.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
namespace Patchlevel\Hydrator\Metadata;
66

7+
use Patchlevel\Hydrator\Normalizer\Normalizer;
78
use ReflectionClass;
89

910
/**
1011
* @phpstan-type serialized array{
1112
* className: class-string,
13+
* normalizer: Normalizer|null,
1214
* properties: array<string, PropertyMetadata>,
1315
* lazy: bool|null,
1416
* extras: array<string, mixed>,
@@ -30,6 +32,7 @@ final class ClassMetadata
3032
*/
3133
public function __construct(
3234
public readonly ReflectionClass $reflection,
35+
public Normalizer|null $normalizer = null,
3336
array $properties = [],
3437
public bool|null $lazy = null,
3538
public array $extras = [],
@@ -67,6 +70,7 @@ public function __serialize(): array
6770
{
6871
return [
6972
'className' => $this->className,
73+
'normalizer' => $this->normalizer,
7074
'properties' => $this->properties,
7175
'lazy' => $this->lazy,
7276
'extras' => $this->extras,
@@ -77,6 +81,7 @@ public function __serialize(): array
7781
public function __unserialize(array $data): void
7882
{
7983
$this->reflection = new ReflectionClass($data['className']);
84+
$this->normalizer = $data['normalizer'];
8085
$this->properties = $data['properties'];
8186
$this->lazy = $data['lazy'];
8287
$this->extras = $data['extras'];

src/MetadataHydrator.php

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
use Patchlevel\Hydrator\Middleware\Stack;
1313
use Patchlevel\Hydrator\Middleware\TransformMiddleware;
1414
use Patchlevel\Hydrator\Normalizer\HydratorAwareNormalizer;
15+
use Patchlevel\Hydrator\Normalizer\InvalidType;
1516
use ReflectionClass;
1617

1718
use function array_key_exists;
19+
use function is_array;
1820

1921
use const PHP_VERSION_ID;
2022

@@ -33,21 +35,28 @@ public function __construct(
3335

3436
/**
3537
* @param class-string<T> $class
36-
* @param array<string, mixed> $data
3738
* @param array<string, mixed> $context
3839
*
3940
* @return T
4041
*
4142
* @template T of object
4243
*/
43-
public function hydrate(string $class, array $data, array $context = []): object
44+
public function hydrate(string $class, mixed $data, array $context = []): object
4445
{
4546
try {
4647
$metadata = $this->metadata($class);
4748
} catch (ClassNotFound $e) {
4849
throw new ClassNotSupported($class, $e);
4950
}
5051

52+
if ($metadata->normalizer) {
53+
return $metadata->normalizer->denormalize($data, $context);
54+
}
55+
56+
if (!is_array($data)) {
57+
throw new InvalidType();
58+
}
59+
5160
if (PHP_VERSION_ID < 80400) {
5261
$stack = new Stack($this->middlewares);
5362

@@ -71,14 +80,15 @@ function () use ($metadata, $data, $context): object {
7180
);
7281
}
7382

74-
/**
75-
* @param array<string, mixed> $context
76-
*
77-
* @return array<string, mixed>
78-
*/
79-
public function extract(object $object, array $context = []): array
83+
/** @param array<string, mixed> $context */
84+
public function extract(object $object, array $context = []): mixed
8085
{
8186
$metadata = $this->metadata($object::class);
87+
88+
if ($metadata->normalizer) {
89+
return $metadata->normalizer->normalize($object, $context);
90+
}
91+
8292
$stack = new Stack($this->middlewares);
8393

8494
return $stack->next()->extract($metadata, $object, $context, $stack);

tests/Unit/Metadata/AttributeMetadataFactoryTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,4 +359,12 @@ class {
359359

360360
self::assertTrue($metadata->lazy);
361361
}
362+
363+
public function testClassMetadataWithNormalizer(): void
364+
{
365+
$metadataFactory = new AttributeMetadataFactory();
366+
$metadata = $metadataFactory->metadata(ProfileId::class);
367+
368+
self::assertInstanceOf(IdNormalizer::class, $metadata->normalizer);
369+
}
362370
}

tests/Unit/Metadata/ClassMetadataTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public function testPropertiesHashmap(): void
3030

3131
$classMetadata = new ClassMetadata(
3232
$reflection,
33+
null,
3334
[$fooMetadata, $barMetadata],
3435
);
3536

tests/Unit/MetadataHydratorTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,15 @@ public function testExtractWithInlineNormalizer(): void
190190
);
191191
}
192192

193+
public function testExtractWithClassNormalizer(): void
194+
{
195+
$data = $this->hydrator->extract(
196+
ProfileId::fromString('id'),
197+
);
198+
199+
self::assertEquals('id', $data);
200+
}
201+
193202
public function testHydrate(): void
194203
{
195204
$expected = new ProfileCreated(
@@ -471,6 +480,16 @@ public function testHydrateWithInferNormalizerWitIterables(): void
471480
self::assertEquals($expected, $event);
472481
}
473482

483+
public function testHydrateWithClassNormalizer(): void
484+
{
485+
$object = $this->hydrator->hydrate(
486+
ProfileId::class,
487+
'id',
488+
);
489+
490+
self::assertEquals(ProfileId::fromString('id'), $object);
491+
}
492+
474493
#[RequiresPhp('>=8.4')]
475494
public function testLazyHydrate(): void
476495
{

0 commit comments

Comments
 (0)