From 81edaacc930103b7e59b8302b5a1ecacc5ec5699 Mon Sep 17 00:00:00 2001 From: webimpress Date: Sat, 26 Jan 2019 14:19:03 +0000 Subject: [PATCH] Move hotfix from DoctrineModule 2.1.8: hydration with nested entities See: https://github.com/doctrine/DoctrineModule/pull/663 --- src/DoctrineObject.php | 4 ++ test/Assets/OneToOneEntity.php | 17 +++++ test/DoctrineObjectTest.php | 122 ++++++++++++++++++++++++++++++++- 3 files changed, 142 insertions(+), 1 deletion(-) diff --git a/src/DoctrineObject.php b/src/DoctrineObject.php index 9cab3e3..a134e6b 100644 --- a/src/DoctrineObject.php +++ b/src/DoctrineObject.php @@ -318,6 +318,8 @@ protected function hydrateByValue(array $data, $object) $object->$setter($this->hydrateValue($field, $value, $data)); } + + $this->metadata = $metadata; } return $object; @@ -365,6 +367,8 @@ protected function hydrateByReference(array $data, $object) } else { $reflProperty->setValue($object, $this->hydrateValue($field, $value, $data)); } + + $this->metadata = $metadata; } return $object; diff --git a/test/Assets/OneToOneEntity.php b/test/Assets/OneToOneEntity.php index 880fb7f..0b02fe5 100644 --- a/test/Assets/OneToOneEntity.php +++ b/test/Assets/OneToOneEntity.php @@ -4,6 +4,8 @@ namespace DoctrineTest\Zend\Hydrator\Assets; +use DateTime; + class OneToOneEntity { /** @@ -16,6 +18,11 @@ class OneToOneEntity */ protected $toOne; + /** + * @var DateTime + */ + protected $createdAt; + public function setId($id) { @@ -47,4 +54,14 @@ public function getToOne($modifyValue = true) return $this->toOne; } + + public function setCreatedAt(DateTime $createdAt) + { + $this->createdAt = $createdAt; + } + + public function getCreatedAt() + { + return $this->createdAt; + } } diff --git a/test/DoctrineObjectTest.php b/test/DoctrineObjectTest.php index b551f90..2ca28f6 100644 --- a/test/DoctrineObjectTest.php +++ b/test/DoctrineObjectTest.php @@ -14,6 +14,7 @@ use InvalidArgumentException; use PHPUnit\Framework\TestCase; use PHPUnit_Framework_MockObject_MockObject; +use Prophecy\Argument; use ReflectionClass; use Zend\Hydrator\NamingStrategy\UnderscoreNamingStrategy; use Zend\Hydrator\Strategy\StrategyInterface; @@ -2649,7 +2650,7 @@ public function testOverrideDefaultStrategy() /** * https://github.com/doctrine/DoctrineModule/issues/639 */ - public function testStrategyWithArray() + public function testStrategyWithArrayByValue() { $entity = new Assets\SimpleEntity(); @@ -2672,4 +2673,123 @@ public function hydrate($value) : string $this->assertEquals('complex,value', $entity->getField()); } + + public function testStrategyWithArrayByReference() + { + $entity = new Assets\SimpleEntity(); + + $data = ['field' => ['complex', 'value']]; + $this->configureObjectManagerForSimpleEntity(); + $this->hydratorByReference->addStrategy('field', new class implements StrategyInterface { + public function extract($value) : array + { + return explode(',', $value); + } + + public function hydrate($value) : string + { + return implode(',', $value); + } + + }); + + $this->hydratorByReference->hydrate($data, $entity); + + $this->assertSame('complex,value', $entity->getField()); + } + + private function getObjectManagerForNestedHydration() + { + $oneToOneMetadata = $this->prophesize(ClassMetadata::class); + $oneToOneMetadata->getName()->willReturn(Assets\OneToOneEntity::class); + $oneToOneMetadata->getFieldNames()->willReturn(['id', 'toOne', 'createdAt']); + $oneToOneMetadata->getAssociationNames()->willReturn(['toOne']); + $oneToOneMetadata->getTypeOfField('id')->willReturn('integer'); + $oneToOneMetadata->getTypeOfField('toOne')->willReturn(Assets\ByValueDifferentiatorEntity::class); + $oneToOneMetadata->getTypeOfField('createdAt')->willReturn('datetime'); + $oneToOneMetadata->hasAssociation('id')->willReturn(false); + $oneToOneMetadata->hasAssociation('toOne')->willReturn(true); + $oneToOneMetadata->hasAssociation('createdAt')->willReturn(false); + $oneToOneMetadata->isSingleValuedAssociation('toOne')->willReturn(true); + $oneToOneMetadata->isCollectionValuedAssociation('toOne')->willReturn(false); + $oneToOneMetadata->getAssociationTargetClass('toOne')->willReturn(Assets\ByValueDifferentiatorEntity::class); + $oneToOneMetadata->getReflectionClass()->willReturn(new ReflectionClass(Assets\OneToOneEntity::class)); + $oneToOneMetadata->getIdentifier()->willReturn(['id']); + $oneToOneMetadata->getIdentifierFieldNames(Argument::type(Assets\OneToOneEntity::class))->willReturn(['id']); + + $byValueDifferentiatorEntity = $this->prophesize(ClassMetadata::class); + $byValueDifferentiatorEntity->getName()->willReturn(Assets\ByValueDifferentiatorEntity::class); + $byValueDifferentiatorEntity->getAssociationNames()->willReturn([]); + $byValueDifferentiatorEntity->getFieldNames()->willReturn(['id', 'field']); + $byValueDifferentiatorEntity->getTypeOfField('id')->willReturn('integer'); + $byValueDifferentiatorEntity->getTypeOfField('field')->willReturn('string'); + $byValueDifferentiatorEntity->hasAssociation(Argument::any())->willReturn(false); + $byValueDifferentiatorEntity->getIdentifier()->willReturn(['id']); + $byValueDifferentiatorEntity + ->getIdentifierFieldNames(Argument::type(Assets\ByValueDifferentiatorEntity::class)) + ->willReturn(['id']); + $byValueDifferentiatorEntity + ->getReflectionClass() + ->willReturn(new ReflectionClass(Assets\ByValueDifferentiatorEntity::class)); + + $objectManager = $this->prophesize(ObjectManager::class); + $objectManager + ->getClassMetadata(Assets\OneToOneEntity::class) + ->will([$oneToOneMetadata, 'reveal']); + $objectManager + ->getClassMetadata(Assets\ByValueDifferentiatorEntity::class) + ->will([$byValueDifferentiatorEntity, 'reveal']); + $objectManager->find(Assets\OneToOneEntity::class, ['id' => 12])->willReturn(false); + $objectManager->find(Assets\ByValueDifferentiatorEntity::class, ['id' => 13])->willReturn(false); + + return $objectManager->reveal(); + } + + public function testNestedHydrationByValue() + { + $objectManager = $this->getObjectManagerForNestedHydration(); + $hydrator = new DoctrineObjectHydrator($objectManager, true); + $entity = new Assets\OneToOneEntity(); + + $data = [ + 'id' => 12, + 'toOne' => [ + 'id' => 13, + 'field' => 'value', + ], + 'createdAt' => '2019-01-24 12:00:00', + ]; + + $hydrator->hydrate($data, $entity); + + $this->assertSame(12, $entity->getId()); + $this->assertInstanceOf(Assets\ByValueDifferentiatorEntity::class, $entity->getToOne(false)); + $this->assertSame(13, $entity->getToOne(false)->getId()); + $this->assertSame('Modified from setToOne setter', $entity->getToOne(false)->getField(false)); + $this->assertSame('2019-01-24 12:00:00', $entity->getCreatedAt()->format('Y-m-d H:i:s')); + } + + public function testNestedHydrationByReference() + { + $objectManager = $this->getObjectManagerForNestedHydration(); + $hydrator = new DoctrineObjectHydrator($objectManager, false); + $entity = new Assets\OneToOneEntity(); + + $data = [ + 'id' => 12, + 'toOne' => [ + 'id' => 13, + 'field' => 'value', + ], + 'createdAt' => '2019-01-24 12:00:00', + ]; + + $hydrator->hydrate($data, $entity); + + $this->assertSame(12, $entity->getId()); + $this->assertInstanceOf(Assets\ByValueDifferentiatorEntity::class, $entity->getToOne(false)); + $this->assertSame(13, $entity->getToOne(false)->getId()); + $this->assertSame('value', $entity->getToOne(false)->getField(false)); + $this->assertSame('2019-01-24 12:00:00', $entity->getCreatedAt()->format('Y-m-d H:i:s')); + } }