Skip to content

Commit 484fdd4

Browse files
authored
Merge pull request #85 from patchlevel/refactor-infer-find-normalizer
allow infer nested arrays
2 parents 8d70a36 + f6aee65 commit 484fdd4

File tree

4 files changed

+70
-53
lines changed

4 files changed

+70
-53
lines changed

phpstan-baseline.neon

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,21 @@ parameters:
3131
path: src/Metadata/AttributeMetadataFactory.php
3232

3333
-
34-
message: '#^Method Patchlevel\\Hydrator\\Metadata\\AttributeMetadataFactory\:\:inferNormalizer\(\) has parameter \$type with generic class Symfony\\Component\\TypeInfo\\Type\\ObjectType but does not specify its types\: T$#'
34+
message: '#^Method Patchlevel\\Hydrator\\Metadata\\AttributeMetadataFactory\:\:guessNormalizerByObjectType\(\) has parameter \$type with generic class Symfony\\Component\\TypeInfo\\Type\\ObjectType but does not specify its types\: T$#'
3535
identifier: missingType.generics
3636
count: 1
3737
path: src/Metadata/AttributeMetadataFactory.php
3838

3939
-
40-
message: '#^Parameter \#1 \$enum of class Patchlevel\\Hydrator\\Normalizer\\EnumNormalizer constructor expects class\-string\<BackedEnum\>\|null, string given\.$#'
40+
message: '#^Parameter \#1 \$class of method Patchlevel\\Hydrator\\Metadata\\AttributeMetadataFactory\:\:findNormalizerOnClass\(\) expects class\-string, string given\.$#'
4141
identifier: argument.type
42-
count: 1
42+
count: 2
4343
path: src/Metadata/AttributeMetadataFactory.php
4444

4545
-
46-
message: '#^Parameter \#1 \$objectOrClass of class ReflectionClass constructor expects class\-string\<T of object\>\|T of object, string given\.$#'
46+
message: '#^Parameter \#1 \$enum of class Patchlevel\\Hydrator\\Normalizer\\EnumNormalizer constructor expects class\-string\<BackedEnum\>\|null, string given\.$#'
4747
identifier: argument.type
48-
count: 2
48+
count: 1
4949
path: src/Metadata/AttributeMetadataFactory.php
5050

5151
-

src/Metadata/AttributeMetadataFactory.php

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -225,38 +225,6 @@ private function getFieldName(ReflectionProperty $reflectionProperty): string
225225
return $attributeReflectionList[0]->newInstance()->name();
226226
}
227227

228-
private function getNormalizer(ReflectionProperty $reflectionProperty): Normalizer|null
229-
{
230-
$type = $this->typeResolver->resolve($reflectionProperty);
231-
232-
$normalizer = $this->findNormalizer($reflectionProperty, $type);
233-
234-
if ($normalizer instanceof TypeAwareNormalizer) {
235-
$normalizer->handleType($type);
236-
}
237-
238-
if ($normalizer instanceof ReflectionTypeAwareNormalizer) {
239-
$reflectionPropertyType = $reflectionProperty->getType();
240-
$normalizer->handleReflectionType($reflectionPropertyType);
241-
}
242-
243-
return $normalizer;
244-
}
245-
246-
private function inferNormalizer(ObjectType $type): Normalizer|null
247-
{
248-
if ($type instanceof BackedEnumType) {
249-
return new EnumNormalizer($type->getClassName());
250-
}
251-
252-
return match ($type->getClassName()) {
253-
DateTimeImmutable::class => new DateTimeImmutableNormalizer(),
254-
DateTime::class => new DateTimeNormalizer(),
255-
DateTimeZone::class => new DateTimeZoneNormalizer(),
256-
default => null,
257-
};
258-
}
259-
260228
private function hasIgnore(ReflectionProperty $reflectionProperty): bool
261229
{
262230
return $reflectionProperty->getAttributes(Ignore::class) !== [];
@@ -367,7 +335,28 @@ private function validate(ClassMetadata $metadata): void
367335
}
368336
}
369337

370-
private function findNormalizer(ReflectionProperty $reflectionProperty, Type $type): Normalizer|null
338+
private function getNormalizer(ReflectionProperty $reflectionProperty): Normalizer|null
339+
{
340+
$normalizer = $this->findNormalizerOnProperty($reflectionProperty);
341+
$type = null;
342+
343+
if (!$normalizer) {
344+
$type = $this->typeResolver->resolve($reflectionProperty);
345+
$normalizer = $this->inferNormalizerByType($type);
346+
}
347+
348+
if ($normalizer instanceof TypeAwareNormalizer) {
349+
$normalizer->handleType($type ?? $this->typeResolver->resolve($reflectionProperty));
350+
}
351+
352+
if ($normalizer instanceof ReflectionTypeAwareNormalizer) {
353+
$normalizer->handleReflectionType($reflectionProperty->getType());
354+
}
355+
356+
return $normalizer;
357+
}
358+
359+
private function findNormalizerOnProperty(ReflectionProperty $reflectionProperty): Normalizer|null
371360
{
372361
$attributeReflectionList = $reflectionProperty->getAttributes(
373362
Normalizer::class,
@@ -378,18 +367,27 @@ private function findNormalizer(ReflectionProperty $reflectionProperty, Type $ty
378367
return $attributeReflectionList[0]->newInstance();
379368
}
380369

370+
return null;
371+
}
372+
373+
private function inferNormalizerByType(Type $type): Normalizer|null
374+
{
381375
if ($type instanceof NullableType) {
382376
$type = $type->getWrappedType();
383377
}
384378

379+
if ($type instanceof BackedEnumType) {
380+
return new EnumNormalizer($type->getClassName());
381+
}
382+
385383
if ($type instanceof ObjectType) {
386-
$normalizer = $this->findNormalizerOnClass(new ReflectionClass($type->getClassName()));
384+
$normalizer = $this->findNormalizerOnClass($type->getClassName());
387385

388386
if ($normalizer) {
389387
return $normalizer;
390388
}
391389

392-
return $this->inferNormalizer($type);
390+
return $this->guessNormalizerByObjectType($type);
393391
}
394392

395393
if ($type instanceof CollectionType) {
@@ -399,29 +397,31 @@ private function findNormalizer(ReflectionProperty $reflectionProperty, Type $ty
399397
$valueType = $type->getWrappedType();
400398
}
401399

402-
if (!$valueType instanceof ObjectType) {
403-
return null;
404-
}
400+
$normalizer = null;
405401

406-
$normalizer = $this->findNormalizerOnClass(new ReflectionClass($valueType->getClassName()));
402+
if ($valueType instanceof ObjectType) {
403+
$normalizer = $this->findNormalizerOnClass($valueType->getClassName());
404+
}
407405

408406
if ($normalizer === null) {
409-
$normalizer = $this->inferNormalizer($valueType);
407+
$normalizer = $this->inferNormalizerByType($valueType);
408+
}
410409

411-
if ($normalizer === null) {
412-
return null;
413-
}
410+
if ($normalizer) {
411+
return new ArrayNormalizer($normalizer);
414412
}
415413

416-
return new ArrayNormalizer($normalizer);
414+
return null;
417415
}
418416

419417
return null;
420418
}
421419

422-
/** @param ReflectionClass<object> $reflectionClass */
423-
private function findNormalizerOnClass(ReflectionClass $reflectionClass): Normalizer|null
420+
/** @param class-string $class */
421+
private function findNormalizerOnClass(string $class): Normalizer|null
424422
{
423+
$reflectionClass = new ReflectionClass($class);
424+
425425
$attributes = $reflectionClass->getAttributes(
426426
Normalizer::class,
427427
ReflectionAttribute::IS_INSTANCEOF,
@@ -434,15 +434,15 @@ private function findNormalizerOnClass(ReflectionClass $reflectionClass): Normal
434434
$parent = $reflectionClass->getParentClass();
435435

436436
if ($parent) {
437-
$normalizer = $this->findNormalizerOnClass($parent);
437+
$normalizer = $this->findNormalizerOnClass($parent->getName());
438438

439439
if ($normalizer !== null) {
440440
return $normalizer;
441441
}
442442
}
443443

444444
foreach ($reflectionClass->getInterfaces() as $interface) {
445-
$normalizer = $this->findNormalizerOnClass($interface);
445+
$normalizer = $this->findNormalizerOnClass($interface->getName());
446446

447447
if ($normalizer !== null) {
448448
return $normalizer;
@@ -451,4 +451,14 @@ private function findNormalizerOnClass(ReflectionClass $reflectionClass): Normal
451451

452452
return null;
453453
}
454+
455+
private function guessNormalizerByObjectType(ObjectType $type): Normalizer|null
456+
{
457+
return match ($type->getClassName()) {
458+
DateTimeImmutable::class => new DateTimeImmutableNormalizer(),
459+
DateTime::class => new DateTimeNormalizer(),
460+
DateTimeZone::class => new DateTimeZoneNormalizer(),
461+
default => null,
462+
};
463+
}
454464
}

tests/Unit/Fixture/InferNormalizerWithIterablesDto.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ final class InferNormalizerWithIterablesDto
1111
* @param list<Status> $listArray
1212
* @param iterable<Status> $iterableArray
1313
* @param array<string, Status> $hashMap
14+
* @param array<string, iterable<Status>> $nested
1415
* @param array{foo: string, bar: int, baz: list<string>}|null $jsonArray
1516
*/
1617
public function __construct(
1718
public array $defaultArray = [],
1819
public array $listArray = [],
1920
public iterable $iterableArray = [],
2021
public array $hashMap = [],
22+
public iterable $nested = [],
2123
public array|null $jsonArray = null,
2224
) {
2325
}

tests/Unit/MetadataHydratorTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,10 @@ public function testHydrateWithInferNormalizerWitIterables(): void
466466
'foo' => Status::Draft,
467467
'bar' => Status::Draft,
468468
],
469+
[
470+
'foo' => [Status::Draft],
471+
'bar' => [Status::Draft],
472+
],
469473
[
470474
'foo' => 'php',
471475
'bar' => 15,
@@ -480,6 +484,7 @@ public function testHydrateWithInferNormalizerWitIterables(): void
480484
'listArray' => ['draft'],
481485
'iterableArray' => ['draft'],
482486
'hashMap' => ['foo' => 'draft', 'bar' => 'draft'],
487+
'nested' => ['foo' => ['draft'], 'bar' => ['draft']],
483488
'jsonArray' => ['foo' => 'php', 'bar' => 15, 'baz' => ['test']],
484489
],
485490
);

0 commit comments

Comments
 (0)