From 781f3d08d06f7bed48ca101789087cc6edfa0db3 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Mon, 26 Jun 2023 00:43:13 +0200 Subject: [PATCH 1/8] Fix array of enum --- src/Annotation/DisableDependencyInjection.php | 10 +++++++++ src/Hydrator.php | 11 ++++++---- .../Fixtures/ObjectWithEnumInConstructor.php | 21 +++++++++++++++++++ tests/HydratorTest.php | 18 ++++++++++++++++ 4 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 src/Annotation/DisableDependencyInjection.php create mode 100644 tests/Fixtures/ObjectWithEnumInConstructor.php diff --git a/src/Annotation/DisableDependencyInjection.php b/src/Annotation/DisableDependencyInjection.php new file mode 100644 index 0000000..a2ecf8b --- /dev/null +++ b/src/Annotation/DisableDependencyInjection.php @@ -0,0 +1,10 @@ +container !== null) { + $resolveViaContainer = $this->getAttributeInstance($reflectionClass, DisableDependencyInjection::class); + if ($resolveViaContainer === null && $this->container !== null) { return $this->container->get($object); } @@ -562,8 +562,11 @@ private function hydrateObjectsInArray(array $array, ArrayType $arrayType, int $ } return array_map(function ($object) use ($arrayType) { - $newInstance = $this->container?->get($arrayType->class) ?? $arrayType->getInstance(); + if (is_subclass_of($arrayType->class, BackedEnum::class)) { + return $arrayType->class::tryFrom($object); + } + $newInstance = $this->initializeObject($arrayType->class, []); return $this->hydrate($newInstance, $object); }, $array); } diff --git a/tests/Fixtures/ObjectWithEnumInConstructor.php b/tests/Fixtures/ObjectWithEnumInConstructor.php new file mode 100644 index 0000000..3ca9769 --- /dev/null +++ b/tests/Fixtures/ObjectWithEnumInConstructor.php @@ -0,0 +1,21 @@ +stringableEnum = $value; + $this->numerableEnums = $numerableEnums; + } +} diff --git a/tests/HydratorTest.php b/tests/HydratorTest.php index e4b8465..3914828 100644 --- a/tests/HydratorTest.php +++ b/tests/HydratorTest.php @@ -894,4 +894,22 @@ public function testHydrateWithContainerWithNestedInstances(): void $this->assertInstanceOf(Sun::class, $o->trees[1]->getSun()); $this->assertSame('andromeda', $o->trees[1]->getSun()->getFrom()); } + + public function testDisableDependencyInjection(): void + { + if (\PHP_VERSION_ID < 80100) { + $this->markTestSkipped('php >= 8.1 is required.'); + } + + $container = new Container(); + $container->delegate(new ReflectionContainer()); + + $object = (new Hydrator($container))->hydrate(Fixtures\ObjectWithEnumInConstructor::class, [ + 'stringableEnum' => 'c1200a7e-136e-4a11-9bc3-cc937046e90f', + 'numerableEnums' => [1] + ]); + + $this->assertSame(Fixtures\StringableEnum::foo, $object->stringableEnum); + $this->assertSame(Fixtures\NumerableEnum::foo, $object->numerableEnums[0]); + } } From 0b514508ff47da383466b55778c7e264673647d5 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Sun, 25 Jun 2023 22:44:36 +0000 Subject: [PATCH 2/8] Apply fixes from StyleCI [ci skip] [skip ci] --- src/Hydrator.php | 3 +++ tests/HydratorTest.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Hydrator.php b/src/Hydrator.php index 1a87ea3..c0ace69 100644 --- a/src/Hydrator.php +++ b/src/Hydrator.php @@ -21,6 +21,7 @@ use SergiX44\Hydrator\Annotation\DisableDependencyInjection; use SergiX44\Hydrator\Annotation\UnionResolver; use SergiX44\Hydrator\Exception\InvalidObjectException; + use function array_key_exists; use function class_exists; use function ctype_digit; @@ -36,6 +37,7 @@ use function is_subclass_of; use function sprintf; use function strtotime; + use const FILTER_NULL_ON_FAILURE; use const FILTER_VALIDATE_BOOLEAN; use const FILTER_VALIDATE_FLOAT; @@ -567,6 +569,7 @@ private function hydrateObjectsInArray(array $array, ArrayType $arrayType, int $ } $newInstance = $this->initializeObject($arrayType->class, []); + return $this->hydrate($newInstance, $object); }, $array); } diff --git a/tests/HydratorTest.php b/tests/HydratorTest.php index 3914828..0402fd6 100644 --- a/tests/HydratorTest.php +++ b/tests/HydratorTest.php @@ -906,7 +906,7 @@ public function testDisableDependencyInjection(): void $object = (new Hydrator($container))->hydrate(Fixtures\ObjectWithEnumInConstructor::class, [ 'stringableEnum' => 'c1200a7e-136e-4a11-9bc3-cc937046e90f', - 'numerableEnums' => [1] + 'numerableEnums' => [1], ]); $this->assertSame(Fixtures\StringableEnum::foo, $object->stringableEnum); From 1e63968f29e35dedbfdc310db8a7e3ac75c30ee1 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Tue, 27 Jun 2023 20:21:45 +0200 Subject: [PATCH 3/8] Bump PHP version to ^8.1 --- composer.json | 2 +- tests/HydratorTest.php | 44 ------------------------------------------ 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/composer.json b/composer.json index 403a38c..19e12cb 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ } ], "require": { - "php": "^8.0", + "php": "^8.1", "psr/container": "^1.1 || ^2.0" }, "require-dev": { diff --git a/tests/HydratorTest.php b/tests/HydratorTest.php index 0402fd6..10c14ab 100644 --- a/tests/HydratorTest.php +++ b/tests/HydratorTest.php @@ -493,10 +493,6 @@ public function testHydrateDateIntervalPropertyWithInvalidFormat(): void */ public function testHydrateStringableEnumProperty($value, $expected): void { - if (\PHP_VERSION_ID < 80100) { - $this->markTestSkipped('php >= 8.1 is required.'); - } - $object = (new Hydrator())->hydrate(Fixtures\ObjectWithStringableEnum::class, ['value' => $value]); $this->assertSame($expected, $object->value); @@ -504,10 +500,6 @@ public function testHydrateStringableEnumProperty($value, $expected): void public function stringableEnumValueProvider(): array { - if (\PHP_VERSION_ID < 80100) { - return []; - } - return [ ['c1200a7e-136e-4a11-9bc3-cc937046e90f', Fixtures\StringableEnum::foo], ['a2b29b37-1c5a-4b36-9981-097ddd25c740', Fixtures\StringableEnum::bar], @@ -517,10 +509,6 @@ public function stringableEnumValueProvider(): array public function testHydrateStringableEnumPropertyWithInvalidValue(): void { - if (\PHP_VERSION_ID < 80100) { - $this->markTestSkipped('php >= 8.1 is required.'); - } - $this->expectException(Exception\InvalidValueException::class); $this->expectExceptionMessage('The ObjectWithStringableEnum.value property '. 'expects the following type: string.'); @@ -530,10 +518,6 @@ public function testHydrateStringableEnumPropertyWithInvalidValue(): void public function testHydrateStringableEnumPropertyWithInvalidUnknownCase(): void { - if (\PHP_VERSION_ID < 80100) { - $this->markTestSkipped('php >= 8.1 is required.'); - } - $this->expectException(Exception\InvalidValueException::class); $this->expectExceptionMessage('The ObjectWithStringableEnum.value property '. 'expects one of the following values: '. @@ -547,10 +531,6 @@ public function testHydrateStringableEnumPropertyWithInvalidUnknownCase(): void */ public function testHydrateNumerableEnumProperty($value, $expected): void { - if (\PHP_VERSION_ID < 80100) { - $this->markTestSkipped('php >= 8.1 is required.'); - } - $object = (new Hydrator())->hydrate(Fixtures\ObjectWithNumerableEnum::class, ['value' => $value]); $this->assertSame($expected, $object->value); @@ -558,10 +538,6 @@ public function testHydrateNumerableEnumProperty($value, $expected): void public function numerableEnumValueProvider(): array { - if (\PHP_VERSION_ID < 80100) { - return []; - } - return [ [1, Fixtures\NumerableEnum::foo], [2, Fixtures\NumerableEnum::bar], @@ -576,10 +552,6 @@ public function numerableEnumValueProvider(): array public function testHydrateNumerableEnumPropertyWithInvalidValue(): void { - if (\PHP_VERSION_ID < 80100) { - $this->markTestSkipped('php >= 8.1 is required.'); - } - $this->expectException(Exception\InvalidValueException::class); $this->expectExceptionMessage('The ObjectWithNumerableEnum.value property '. 'expects the following type: int.'); @@ -589,10 +561,6 @@ public function testHydrateNumerableEnumPropertyWithInvalidValue(): void public function testHydrateNumerableEnumPropertyWithInvalidUnknownCase(): void { - if (\PHP_VERSION_ID < 80100) { - $this->markTestSkipped('php >= 8.1 is required.'); - } - $this->expectException(Exception\InvalidValueException::class); $this->expectExceptionMessage('The ObjectWithNumerableEnum.value property '. 'expects one of the following values: '. @@ -684,10 +652,6 @@ public function testInvalidValueExceptionProperty(): void public function testHydrateProductWithJsonAsArray(): void { - if (\PHP_VERSION_ID < 80100) { - $this->markTestSkipped('php >= 8.1 is required.'); - } - $json = <<<'JSON' { "name": "ac7ce13e-9b2e-4b09-ae7a-973769ea43df", @@ -717,10 +681,6 @@ public function testHydrateProductWithJsonAsArray(): void public function testHydrateProductWithJsonAsObject(): void { - if (\PHP_VERSION_ID < 80100) { - $this->markTestSkipped('php >= 8.1 is required.'); - } - $json = <<<'JSON' { "name": "0f61ac0e-f732-4088-8082-cc396e7dcb80", @@ -897,10 +857,6 @@ public function testHydrateWithContainerWithNestedInstances(): void public function testDisableDependencyInjection(): void { - if (\PHP_VERSION_ID < 80100) { - $this->markTestSkipped('php >= 8.1 is required.'); - } - $container = new Container(); $container->delegate(new ReflectionContainer()); From ce73c35b13b7ed2048049c006fc412f829880f73 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Tue, 27 Jun 2023 20:31:30 +0200 Subject: [PATCH 4/8] Use illuminate/container --- composer.json | 2 +- src/Annotation/DisableDependencyInjection.php | 4 ++++ tests/HydratorTest.php | 10 +++------- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 19e12cb..89eda76 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ ], "require": { "php": "^8.1", - "psr/container": "^1.1 || ^2.0" + "illuminate/container": "^10.0" }, "require-dev": { "phpunit/phpunit": "~9.5.0", diff --git a/src/Annotation/DisableDependencyInjection.php b/src/Annotation/DisableDependencyInjection.php index a2ecf8b..e0a9935 100644 --- a/src/Annotation/DisableDependencyInjection.php +++ b/src/Annotation/DisableDependencyInjection.php @@ -4,6 +4,10 @@ use Attribute; +/** + * @Annotation + * @Target({"CLASS"}) + */ #[Attribute(Attribute::TARGET_CLASS)] final class DisableDependencyInjection { diff --git a/tests/HydratorTest.php b/tests/HydratorTest.php index 10c14ab..f85a78e 100644 --- a/tests/HydratorTest.php +++ b/tests/HydratorTest.php @@ -2,9 +2,8 @@ namespace SergiX44\Hydrator\Tests; +use Illuminate\Container\Container; use InvalidArgumentException; -use League\Container\Container; -use League\Container\ReflectionContainer; use PHPUnit\Framework\TestCase; use SergiX44\Hydrator\Exception; use SergiX44\Hydrator\Exception\InvalidObjectException; @@ -768,8 +767,7 @@ public function testHydrateWithContainer(): void $sun = new Sun('andromeda'); $container = new Container(); - $container->delegate(new ReflectionContainer()); - $container->addShared(Sun::class, $sun); + $container->instance(Sun::class, $sun); $hydrator = new Hydrator($container); @@ -799,8 +797,7 @@ public function testHydrateWithContainerWithNestedInstances(): void $sun = new Sun('andromeda'); $container = new Container(); - $container->delegate(new ReflectionContainer()); - $container->addShared(Sun::class, $sun); + $container->instance(Sun::class, $sun); $hydrator = new Hydrator($container); @@ -858,7 +855,6 @@ public function testHydrateWithContainerWithNestedInstances(): void public function testDisableDependencyInjection(): void { $container = new Container(); - $container->delegate(new ReflectionContainer()); $object = (new Hydrator($container))->hydrate(Fixtures\ObjectWithEnumInConstructor::class, [ 'stringableEnum' => 'c1200a7e-136e-4a11-9bc3-cc937046e90f', From 8961f813d626784ef7b7f51c6256a485a417826b Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Tue, 27 Jun 2023 18:32:26 +0000 Subject: [PATCH 5/8] Apply fixes from StyleCI [ci skip] [skip ci] --- src/Annotation/DisableDependencyInjection.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Annotation/DisableDependencyInjection.php b/src/Annotation/DisableDependencyInjection.php index e0a9935..0058cff 100644 --- a/src/Annotation/DisableDependencyInjection.php +++ b/src/Annotation/DisableDependencyInjection.php @@ -6,6 +6,7 @@ /** * @Annotation + * * @Target({"CLASS"}) */ #[Attribute(Attribute::TARGET_CLASS)] From 95ae58c51299550b43af521bec6d1143f0e1c7fc Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Tue, 27 Jun 2023 20:39:28 +0200 Subject: [PATCH 6/8] Change attribute logic from "DisableDependencyInjection" to "SkipConstructor" --- ...dencyInjection.php => SkipConstructor.php} | 2 +- src/Hydrator.php | 208 +++++++++--------- .../Fixtures/ObjectWithEnumInConstructor.php | 6 +- tests/HydratorTest.php | 13 +- 4 files changed, 126 insertions(+), 103 deletions(-) rename src/Annotation/{DisableDependencyInjection.php => SkipConstructor.php} (79%) diff --git a/src/Annotation/DisableDependencyInjection.php b/src/Annotation/SkipConstructor.php similarity index 79% rename from src/Annotation/DisableDependencyInjection.php rename to src/Annotation/SkipConstructor.php index 0058cff..25792bc 100644 --- a/src/Annotation/DisableDependencyInjection.php +++ b/src/Annotation/SkipConstructor.php @@ -10,6 +10,6 @@ * @Target({"CLASS"}) */ #[Attribute(Attribute::TARGET_CLASS)] -final class DisableDependencyInjection +final class SkipConstructor { } diff --git a/src/Hydrator.php b/src/Hydrator.php index c0ace69..dccc90b 100644 --- a/src/Hydrator.php +++ b/src/Hydrator.php @@ -18,10 +18,9 @@ use SergiX44\Hydrator\Annotation\Alias; use SergiX44\Hydrator\Annotation\ArrayType; use SergiX44\Hydrator\Annotation\ConcreteResolver; -use SergiX44\Hydrator\Annotation\DisableDependencyInjection; +use SergiX44\Hydrator\Annotation\SkipConstructor; use SergiX44\Hydrator\Annotation\UnionResolver; use SergiX44\Hydrator\Exception\InvalidObjectException; - use function array_key_exists; use function class_exists; use function ctype_digit; @@ -37,7 +36,6 @@ use function is_subclass_of; use function sprintf; use function strtotime; - use const FILTER_NULL_ON_FAILURE; use const FILTER_VALIDATE_BOOLEAN; use const FILTER_VALIDATE_FLOAT; @@ -56,10 +54,11 @@ public function __construct(?ContainerInterface $container = null) * Hydrates the given object with the given data. * * @param class-string|T $object - * @param array|object $data + * @param array|object $data * - * @throws Exception\UntypedPropertyException - * If one of the object properties isn't typed. + * @return T + * + * @template T * @throws Exception\UnsupportedPropertyTypeException * If one of the object properties contains an unsupported type. * @throws Exception\MissingRequiredValueException @@ -71,9 +70,8 @@ public function __construct(?ContainerInterface $container = null) * @throws InvalidArgumentException * If the data isn't valid. * - * @return T - * - * @template T + * @throws Exception\UntypedPropertyException + * If one of the object properties isn't typed. */ public function hydrate(string|object $object, array|object $data): object { @@ -110,7 +108,8 @@ public function hydrate(string|object $object, array|object $data): object } if ($propertyType instanceof ReflectionUnionType) { - $resolver = $this->getAttributeInstance($property, UnionResolver::class, ReflectionAttribute::IS_INSTANCEOF); + $resolver = $this->getAttributeInstance($property, UnionResolver::class, + ReflectionAttribute::IS_INSTANCEOF); if (isset($resolver)) { $propertyType = $resolver->resolve($propertyType, $data[$key]); } else { @@ -144,17 +143,17 @@ public function hydrate(string|object $object, array|object $data): object * Hydrates the given object with the given JSON. * * @param class-string|T $object - * @param string $json - * @param ?int $flags - * - * @throws Exception\HydrationException - * If the object cannot be hydrated. - * @throws InvalidArgumentException - * If the JSON cannot be decoded. + * @param string $json + * @param ?int $flags * * @return T * * @template T + * @throws InvalidArgumentException + * If the JSON cannot be decoded. + * + * @throws Exception\HydrationException + * If the object cannot be hydrated. */ public function hydrateWithJson(string|object $object, string $json, ?int $flags = null): object { @@ -177,13 +176,14 @@ public function hydrateWithJson(string|object $object, string $json, ?int $flags /** * @param class-string|object $object * + * @return object|null * @throws \ReflectionException * - * @return object|null */ public function getConcreteResolverFor(string|object $object): ?ConcreteResolver { - return $this->getAttributeInstance(new ReflectionClass($object), ConcreteResolver::class, ReflectionAttribute::IS_INSTANCEOF); + return $this->getAttributeInstance(new ReflectionClass($object), ConcreteResolver::class, + ReflectionAttribute::IS_INSTANCEOF); } /** @@ -191,13 +191,13 @@ public function getConcreteResolverFor(string|object $object): ?ConcreteResolver * * @param class-string|T $object * - * @throws InvalidArgumentException - * @throws ContainerExceptionInterface - * If the object cannot be initialized. - * * @return T * * @template T + * @throws ContainerExceptionInterface + * If the object cannot be initialized. + * + * @throws InvalidArgumentException */ private function initializeObject(string|object $object, array|object $data): object { @@ -215,7 +215,8 @@ private function initializeObject(string|object $object, array|object $data): ob $reflectionClass = new ReflectionClass($object); if ($reflectionClass->isAbstract()) { - $attribute = $this->getAttributeInstance($reflectionClass, ConcreteResolver::class, ReflectionAttribute::IS_INSTANCEOF); + $attribute = $this->getAttributeInstance($reflectionClass, ConcreteResolver::class, + ReflectionAttribute::IS_INSTANCEOF); if ($attribute === null) { throw new InvalidObjectException(sprintf( @@ -228,8 +229,12 @@ private function initializeObject(string|object $object, array|object $data): ob } // if we have a container, get the instance through it - $resolveViaContainer = $this->getAttributeInstance($reflectionClass, DisableDependencyInjection::class); - if ($resolveViaContainer === null && $this->container !== null) { + $skipConstructor = $this->getAttributeInstance($reflectionClass, SkipConstructor::class); + if ($skipConstructor !== null) { + return $reflectionClass->newInstanceWithoutConstructor(); + } + + if ($this->container !== null) { return $this->container->get($object); } @@ -251,13 +256,16 @@ private function initializeObject(string|object $object, array|object $data): ob * @template T * * @param ReflectionProperty|ReflectionClass $target - * @param class-string $class - * @param int $criteria + * @param class-string $class + * @param int $criteria * * @return T|null */ - private function getAttributeInstance(ReflectionProperty|ReflectionClass $target, string $class, int $criteria = 0): mixed - { + private function getAttributeInstance( + ReflectionProperty|ReflectionClass $target, + string $class, + int $criteria = 0 + ): mixed { $attributes = $target->getAttributes($class, $criteria); if (isset($attributes[0])) { return $attributes[0]->newInstance(); @@ -269,18 +277,18 @@ private function getAttributeInstance(ReflectionProperty|ReflectionClass $target /** * Hydrates the given property with the given value. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @throws Exception\InvalidValueException - * If the given value isn't valid. + * @return void * @throws Exception\UnsupportedPropertyTypeException * If the given property contains an unsupported type. * - * @return void + * @throws Exception\InvalidValueException + * If the given value isn't valid. */ private function hydrateProperty( object $object, @@ -293,7 +301,8 @@ private function hydrateProperty( match (true) { // an empty string for a non-string type is always processes as null - '' === $value && 'string' !== $propertyType, null === $value => $this->propertyNull($object, $class, $property, $type), + '' === $value && 'string' !== $propertyType, null === $value => $this->propertyNull($object, $class, + $property, $type), 'bool' === $propertyType => $this->propertyBool($object, $class, $property, $type, $value), @@ -307,11 +316,14 @@ private function hydrateProperty( 'object' === $propertyType => $this->propertyObject($object, $class, $property, $type, $value), - DateTime::class === $propertyType, DateTimeImmutable::class === $propertyType => $this->propertyDateTime($object, $class, $property, $type, $value), + DateTime::class === $propertyType, DateTimeImmutable::class === $propertyType => $this->propertyDateTime($object, + $class, $property, $type, $value), - DateInterval::class === $propertyType => $this->propertyDateInterval($object, $class, $property, $type, $value), + DateInterval::class === $propertyType => $this->propertyDateInterval($object, $class, $property, $type, + $value), - PHP_VERSION_ID >= 80100 && is_subclass_of($propertyType, BackedEnum::class) => $this->propertyBackedEnum($object, $class, $property, $type, $value), + PHP_VERSION_ID >= 80100 && is_subclass_of($propertyType, + BackedEnum::class) => $this->propertyBackedEnum($object, $class, $property, $type, $value), class_exists($propertyType) => $this->propertyFromInstance($object, $class, $property, $type, $value), @@ -327,15 +339,15 @@ class_exists($propertyType) => $this->propertyFromInstance($object, $class, $pro /** * Hydrates the given property with null. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyNull( object $object, @@ -357,16 +369,16 @@ private function propertyNull( /** * Hydrates the given property with the given boolean value. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyBool( object $object, @@ -396,16 +408,16 @@ private function propertyBool( /** * Hydrates the given property with the given integer number. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyInt( object $object, @@ -437,16 +449,16 @@ private function propertyInt( /** * Hydrates the given property with the given number. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyFloat( object $object, @@ -476,16 +488,16 @@ private function propertyFloat( /** * Hydrates the given property with the given string. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyString( object $object, @@ -508,16 +520,16 @@ private function propertyString( /** * Hydrates the given property with the given array. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyArray( object $object, @@ -547,13 +559,13 @@ private function propertyArray( } /** - * @param array $array + * @param array $array * @param ArrayType $arrayType - * @param int $depth + * @param int $depth * + * @return array * @throws \ReflectionException * - * @return array */ private function hydrateObjectsInArray(array $array, ArrayType $arrayType, int $depth): array { @@ -577,16 +589,16 @@ private function hydrateObjectsInArray(array $array, ArrayType $arrayType, int $ /** * Hydrates the given property with the given object. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyObject( object $object, @@ -609,16 +621,16 @@ private function propertyObject( /** * Hydrates the given property with the given date-time. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyDateTime( object $object, @@ -648,16 +660,16 @@ private function propertyDateTime( /** * Hydrates the given property with the given date-interval. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyDateInterval( object $object, @@ -693,16 +705,16 @@ private function propertyDateInterval( /** * Hydrates the given property with the given backed-enum. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyBackedEnum( object $object, @@ -755,16 +767,16 @@ private function propertyBackedEnum( /** * Hydrates the given property with the given one association. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * + * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * - * @return void */ private function propertyFromInstance( object $object, diff --git a/tests/Fixtures/ObjectWithEnumInConstructor.php b/tests/Fixtures/ObjectWithEnumInConstructor.php index 3ca9769..ad390a2 100644 --- a/tests/Fixtures/ObjectWithEnumInConstructor.php +++ b/tests/Fixtures/ObjectWithEnumInConstructor.php @@ -3,9 +3,9 @@ namespace SergiX44\Hydrator\Tests\Fixtures; use SergiX44\Hydrator\Annotation\ArrayType; -use SergiX44\Hydrator\Annotation\DisableDependencyInjection; +use SergiX44\Hydrator\Annotation\SkipConstructor; -#[DisableDependencyInjection] +#[SkipConstructor] final class ObjectWithEnumInConstructor { public StringableEnum $stringableEnum; @@ -13,7 +13,7 @@ final class ObjectWithEnumInConstructor #[ArrayType(NumerableEnum::class)] public array $numerableEnums; - public function __construct(StringableEnum $value = StringableEnum::foo, array $numerableEnums = []) + public function __construct(StringableEnum $value, array $numerableEnums) { $this->stringableEnum = $value; $this->numerableEnums = $numerableEnums; diff --git a/tests/HydratorTest.php b/tests/HydratorTest.php index f85a78e..ae311c3 100644 --- a/tests/HydratorTest.php +++ b/tests/HydratorTest.php @@ -852,7 +852,18 @@ public function testHydrateWithContainerWithNestedInstances(): void $this->assertSame('andromeda', $o->trees[1]->getSun()->getFrom()); } - public function testDisableDependencyInjection(): void + public function testSkipConstructor(): void + { + $object = (new Hydrator())->hydrate(Fixtures\ObjectWithEnumInConstructor::class, [ + 'stringableEnum' => 'c1200a7e-136e-4a11-9bc3-cc937046e90f', + 'numerableEnums' => [1], + ]); + + $this->assertSame(Fixtures\StringableEnum::foo, $object->stringableEnum); + $this->assertSame(Fixtures\NumerableEnum::foo, $object->numerableEnums[0]); + } + + public function testSkipConstructorWithContainer(): void { $container = new Container(); From 09741493656f79814b96dbc19156e642f0526796 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Tue, 27 Jun 2023 18:40:35 +0000 Subject: [PATCH 7/8] Apply fixes from StyleCI [ci skip] [skip ci] --- src/Hydrator.php | 221 ++++++++++++++++++++++++++--------------------- 1 file changed, 124 insertions(+), 97 deletions(-) diff --git a/src/Hydrator.php b/src/Hydrator.php index dccc90b..06bb634 100644 --- a/src/Hydrator.php +++ b/src/Hydrator.php @@ -21,6 +21,7 @@ use SergiX44\Hydrator\Annotation\SkipConstructor; use SergiX44\Hydrator\Annotation\UnionResolver; use SergiX44\Hydrator\Exception\InvalidObjectException; + use function array_key_exists; use function class_exists; use function ctype_digit; @@ -36,6 +37,7 @@ use function is_subclass_of; use function sprintf; use function strtotime; + use const FILTER_NULL_ON_FAILURE; use const FILTER_VALIDATE_BOOLEAN; use const FILTER_VALIDATE_FLOAT; @@ -54,11 +56,8 @@ public function __construct(?ContainerInterface $container = null) * Hydrates the given object with the given data. * * @param class-string|T $object - * @param array|object $data - * - * @return T + * @param array|object $data * - * @template T * @throws Exception\UnsupportedPropertyTypeException * If one of the object properties contains an unsupported type. * @throws Exception\MissingRequiredValueException @@ -69,9 +68,12 @@ public function __construct(?ContainerInterface $container = null) * If the object cannot be hydrated. * @throws InvalidArgumentException * If the data isn't valid. - * * @throws Exception\UntypedPropertyException * If one of the object properties isn't typed. + * + * @return T + * + * @template T */ public function hydrate(string|object $object, array|object $data): object { @@ -108,8 +110,11 @@ public function hydrate(string|object $object, array|object $data): object } if ($propertyType instanceof ReflectionUnionType) { - $resolver = $this->getAttributeInstance($property, UnionResolver::class, - ReflectionAttribute::IS_INSTANCEOF); + $resolver = $this->getAttributeInstance( + $property, + UnionResolver::class, + ReflectionAttribute::IS_INSTANCEOF + ); if (isset($resolver)) { $propertyType = $resolver->resolve($propertyType, $data[$key]); } else { @@ -143,17 +148,17 @@ public function hydrate(string|object $object, array|object $data): object * Hydrates the given object with the given JSON. * * @param class-string|T $object - * @param string $json - * @param ?int $flags - * - * @return T + * @param string $json + * @param ?int $flags * - * @template T * @throws InvalidArgumentException * If the JSON cannot be decoded. - * * @throws Exception\HydrationException * If the object cannot be hydrated. + * + * @return T + * + * @template T */ public function hydrateWithJson(string|object $object, string $json, ?int $flags = null): object { @@ -176,14 +181,17 @@ public function hydrateWithJson(string|object $object, string $json, ?int $flags /** * @param class-string|object $object * - * @return object|null * @throws \ReflectionException * + * @return object|null */ public function getConcreteResolverFor(string|object $object): ?ConcreteResolver { - return $this->getAttributeInstance(new ReflectionClass($object), ConcreteResolver::class, - ReflectionAttribute::IS_INSTANCEOF); + return $this->getAttributeInstance( + new ReflectionClass($object), + ConcreteResolver::class, + ReflectionAttribute::IS_INSTANCEOF + ); } /** @@ -191,13 +199,13 @@ public function getConcreteResolverFor(string|object $object): ?ConcreteResolver * * @param class-string|T $object * - * @return T - * - * @template T * @throws ContainerExceptionInterface * If the object cannot be initialized. - * * @throws InvalidArgumentException + * + * @return T + * + * @template T */ private function initializeObject(string|object $object, array|object $data): object { @@ -215,8 +223,11 @@ private function initializeObject(string|object $object, array|object $data): ob $reflectionClass = new ReflectionClass($object); if ($reflectionClass->isAbstract()) { - $attribute = $this->getAttributeInstance($reflectionClass, ConcreteResolver::class, - ReflectionAttribute::IS_INSTANCEOF); + $attribute = $this->getAttributeInstance( + $reflectionClass, + ConcreteResolver::class, + ReflectionAttribute::IS_INSTANCEOF + ); if ($attribute === null) { throw new InvalidObjectException(sprintf( @@ -256,8 +267,8 @@ private function initializeObject(string|object $object, array|object $data): ob * @template T * * @param ReflectionProperty|ReflectionClass $target - * @param class-string $class - * @param int $criteria + * @param class-string $class + * @param int $criteria * * @return T|null */ @@ -277,18 +288,18 @@ private function getAttributeInstance( /** * Hydrates the given property with the given value. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\UnsupportedPropertyTypeException * If the given property contains an unsupported type. - * * @throws Exception\InvalidValueException * If the given value isn't valid. + * + * @return void */ private function hydrateProperty( object $object, @@ -301,8 +312,12 @@ private function hydrateProperty( match (true) { // an empty string for a non-string type is always processes as null - '' === $value && 'string' !== $propertyType, null === $value => $this->propertyNull($object, $class, - $property, $type), + '' === $value && 'string' !== $propertyType, null === $value => $this->propertyNull( + $object, + $class, + $property, + $type + ), 'bool' === $propertyType => $this->propertyBool($object, $class, $property, $type, $value), @@ -316,14 +331,26 @@ private function hydrateProperty( 'object' === $propertyType => $this->propertyObject($object, $class, $property, $type, $value), - DateTime::class === $propertyType, DateTimeImmutable::class === $propertyType => $this->propertyDateTime($object, - $class, $property, $type, $value), - - DateInterval::class === $propertyType => $this->propertyDateInterval($object, $class, $property, $type, - $value), - - PHP_VERSION_ID >= 80100 && is_subclass_of($propertyType, - BackedEnum::class) => $this->propertyBackedEnum($object, $class, $property, $type, $value), + DateTime::class === $propertyType, DateTimeImmutable::class === $propertyType => $this->propertyDateTime( + $object, + $class, + $property, + $type, + $value + ), + + DateInterval::class === $propertyType => $this->propertyDateInterval( + $object, + $class, + $property, + $type, + $value + ), + + PHP_VERSION_ID >= 80100 && is_subclass_of( + $propertyType, + BackedEnum::class + ) => $this->propertyBackedEnum($object, $class, $property, $type, $value), class_exists($propertyType) => $this->propertyFromInstance($object, $class, $property, $type, $value), @@ -339,15 +366,15 @@ class_exists($propertyType) => $this->propertyFromInstance($object, $class, $pro /** * Hydrates the given property with null. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyNull( object $object, @@ -369,16 +396,16 @@ private function propertyNull( /** * Hydrates the given property with the given boolean value. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyBool( object $object, @@ -408,16 +435,16 @@ private function propertyBool( /** * Hydrates the given property with the given integer number. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyInt( object $object, @@ -449,16 +476,16 @@ private function propertyInt( /** * Hydrates the given property with the given number. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyFloat( object $object, @@ -488,16 +515,16 @@ private function propertyFloat( /** * Hydrates the given property with the given string. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyString( object $object, @@ -520,16 +547,16 @@ private function propertyString( /** * Hydrates the given property with the given array. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyArray( object $object, @@ -559,13 +586,13 @@ private function propertyArray( } /** - * @param array $array + * @param array $array * @param ArrayType $arrayType - * @param int $depth + * @param int $depth * - * @return array * @throws \ReflectionException * + * @return array */ private function hydrateObjectsInArray(array $array, ArrayType $arrayType, int $depth): array { @@ -589,16 +616,16 @@ private function hydrateObjectsInArray(array $array, ArrayType $arrayType, int $ /** * Hydrates the given property with the given object. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyObject( object $object, @@ -621,16 +648,16 @@ private function propertyObject( /** * Hydrates the given property with the given date-time. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyDateTime( object $object, @@ -660,16 +687,16 @@ private function propertyDateTime( /** * Hydrates the given property with the given date-interval. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyDateInterval( object $object, @@ -705,16 +732,16 @@ private function propertyDateInterval( /** * Hydrates the given property with the given backed-enum. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyBackedEnum( object $object, @@ -767,16 +794,16 @@ private function propertyBackedEnum( /** * Hydrates the given property with the given one association. * - * @param object $object - * @param ReflectionClass $class - * @param ReflectionProperty $property + * @param object $object + * @param ReflectionClass $class + * @param ReflectionProperty $property * @param ReflectionNamedType $type - * @param mixed $value + * @param mixed $value * - * @return void * @throws Exception\InvalidValueException * If the given value isn't valid. * + * @return void */ private function propertyFromInstance( object $object, From 31dae94b404206abfdccea27f642ff6460117450 Mon Sep 17 00:00:00 2001 From: Luca Patera Date: Tue, 27 Jun 2023 21:35:02 +0200 Subject: [PATCH 8/8] Juan --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 89eda76..af45c17 100644 --- a/composer.json +++ b/composer.json @@ -25,11 +25,11 @@ ], "require": { "php": "^8.1", - "illuminate/container": "^10.0" + "psr/container": "^1.1 || ^2.0" }, "require-dev": { "phpunit/phpunit": "~9.5.0", - "league/container": "^4.2" + "illuminate/container": "^10.0" }, "autoload": { "psr-4": {