diff --git a/src/Writer/DoctrineWriter.php b/src/Writer/DoctrineWriter.php index fca7cc38..676cc99b 100644 --- a/src/Writer/DoctrineWriter.php +++ b/src/Writer/DoctrineWriter.php @@ -131,6 +131,7 @@ public function prepare() /** * Return a new instance of the entity * + * @throws \Exception * @return object */ protected function getNewInstance() @@ -176,6 +177,7 @@ public function writeItem(array $item) { $entity = $this->findOrCreateItem($item); + $this->updateAssociations($item,$entity); $this->loadAssociationObjectsToEntity($item, $entity); $this->updateEntity($item, $entity); @@ -210,6 +212,60 @@ protected function updateEntity(array $item, $entity) } } + /** + * @param array $item + * @param $entity + * @throws \Exception + */ + public function updateAssociations(array &$item, $entity) + { + foreach ($this->entityMetadata->getAssociationMappings() as $map) { + // There is data for the association + if (isset($item[$map['fieldName']]) && is_array($item[$map['fieldName']])) { + $this->updateAssociation($item, $entity, $map['fieldName'], $map['targetEntity']); + } + } + } + + /** + * @param array $item + * @param object $entity + * @param string $fieldName + * @param string $targetEntity + * @throws \Exception + */ + public function updateAssociation(array &$item, $entity, $fieldName, $targetEntity) + { + $getterMethod = sprintf('get%s', $fieldName); + + if (method_exists($entity, $getterMethod)) { + $orgRepository = $this->entityRepository; + $orgMetadata = $this->entityMetadata; + $orgName = $this->entityName; + + $this->entityRepository = $this->entityManager->getRepository($targetEntity); + $this->entityMetadata = $this->entityManager->getClassMetadata($targetEntity); + $this->entityName = $this->entityMetadata->getName(); + + $association = call_user_func([$entity,$getterMethod]); + if (!$association) { + $association = $this->getNewInstance(); + } + + $value = $item[$fieldName]; + unset($item[$fieldName]); + + $this->updateEntity($value, $association); + + $setterMethod = sprintf('set%s',$fieldName); + call_user_func([$entity, $setterMethod],$association); + + $this->entityRepository = $orgRepository; + $this->entityMetadata = $orgMetadata; + $this->entityName = $orgName; + } + } + /** * Add the associated objects in case the item have for persist its relation * @@ -221,7 +277,7 @@ protected function loadAssociationObjectsToEntity(array $item, $entity) foreach ($this->entityMetadata->getAssociationMappings() as $associationMapping) { $value = null; - if (isset($item[$associationMapping['fieldName']]) && !is_object($item[$associationMapping['fieldName']])) { + if (isset($item[$associationMapping['fieldName']]) && !is_object($item[$associationMapping['fieldName']]) && !is_array($item[$associationMapping['fieldName']])) { $value = $this->entityManager->getReference($associationMapping['targetEntity'], $item[$associationMapping['fieldName']]); } @@ -268,6 +324,7 @@ protected function reEnableLogging() * Finds existing entity or create a new instance * * @param array $item + * @return mixed|null|object */ protected function findOrCreateItem(array $item) { diff --git a/tests/Fixtures/Entity/TestEntityAssociation.php b/tests/Fixtures/Entity/TestEntityAssociation.php new file mode 100644 index 00000000..d1ca76ec --- /dev/null +++ b/tests/Fixtures/Entity/TestEntityAssociation.php @@ -0,0 +1,37 @@ +aProperty; + } + + public function setAProperty($firstProperty) + { + $this->aProperty = $firstProperty; + } + + public function getBProperty() + { + return $this->bProperty; + } + + public function setBProperty($secondProperty) + { + $this->bProperty = $secondProperty; + } +} \ No newline at end of file diff --git a/tests/Writer/DoctrineWriterTest.php b/tests/Writer/DoctrineWriterTest.php index 5792512e..70ae8c80 100644 --- a/tests/Writer/DoctrineWriterTest.php +++ b/tests/Writer/DoctrineWriterTest.php @@ -41,6 +41,8 @@ protected function getEntityManager() ->disableOriginalConstructor() ->getMock(); + $assocMetadata = clone $metadata; + $metadata->expects($this->any()) ->method('getName') ->will($this->returnValue('Ddeboer\DataImport\Tests\Fixtures\Entity\TestEntity')); @@ -55,7 +57,19 @@ protected function getEntityManager() $metadata->expects($this->any()) ->method('getAssociationMappings') - ->will($this->returnValue(array(array('fieldName' => 'firstAssociation','targetEntity' => 'Ddeboer\DataImport\Tests\Fixtures\Entity\TestEntity')))); + ->will($this->returnValue(array(array('fieldName' => 'firstAssociation','targetEntity' => 'Ddeboer\DataImport\Tests\Fixtures\Entity\TestEntityAssociation')))); + + $assocMetadata->expects($this->any()) + ->method('getName') + ->will($this->returnValue('Ddeboer\DataImport\Tests\Fixtures\Entity\TestEntityAssociation')); + + $assocMetadata->expects($this->any()) + ->method('getFieldNames') + ->will($this->returnValue(array('aProperty', 'bProperty'))); + + $assocMetadata->expects($this->any()) + ->method('getAssociationNames') + ->will($this->returnValue(array())); $configuration = $this->getMockBuilder('Doctrine\DBAL\Configuration') ->setMethods(array('getConnection')) @@ -83,13 +97,15 @@ protected function getEntityManager() ->method('executeQuery') ->with('TRUNCATE SQL'); - $em->expects($this->once()) + $em->expects($this->any()) ->method('getRepository') ->will($this->returnValue($repo)); - $em->expects($this->once()) + $em->expects($this->any()) ->method('getClassMetadata') - ->will($this->returnValue($metadata)); + ->will($this->returnCallback(function($arg) use ($metadata,$assocMetadata){ + return ($arg =='DdeboerDataImport:TestEntity') ? $metadata :$assocMetadata; + })); $em->expects($this->any()) ->method('getConnection') @@ -149,6 +165,32 @@ public function testLoadAssociationWithPresetObject() $writer->writeItem($item); } + public function testUpdateAssociationUnmapped() + { + $em = $this->getEntityManager(); + + $em->expects($this->never()) + ->method('persist'); + + $em->expects($this->never()) + ->method('getReference'); + + $association = new TestEntity(); + $writer = new DoctrineWriter($em, 'DdeboerDataImport:TestEntity'); + $item = [ + 'firstProperty' => 'some value', + 'secondProperty' => 'some other value', + 'firstAssociation' => [ + 'aProperty' => 'another value', + 'bProperty' => 'another other value', + ] + ]; + + $writer->updateAssociations($item,$association); + $this->assertInstanceOf('Ddeboer\DataImport\Tests\Fixtures\Entity\TestEntityAssociation',$association->getFirstAssociation()); + $this->assertEquals('another value',$association->getFirstAssociation()->getAProperty()); + } + /** * Test to make sure that we are clearing the write entity */