From b2c1f1939aef598b399f49a76747797470c3e7dd Mon Sep 17 00:00:00 2001 From: Nicolas Bastien Date: Sun, 2 Dec 2018 17:01:01 +0100 Subject: [PATCH] #11 : Doctrine loader : allow to work with unparsed relation + allow to pass null identifier for strict insertion --- src/Loader/DoctrineInsertUpdateLoader.php | 41 ++++++--- tests/Entity/Organisation.php | 87 +++++++++++++++++++ tests/Entity/Project.php | 7 ++ .../Loader/DoctrineInsertUpdateLoaderTest.php | 20 +++++ tests/Model/Project.php | 22 +++++ .../fixtures/doctrine-loader/organisation.yml | 4 + 6 files changed, 170 insertions(+), 11 deletions(-) create mode 100644 tests/Entity/Organisation.php create mode 100644 tests/fixtures/doctrine-loader/organisation.yml diff --git a/src/Loader/DoctrineInsertUpdateLoader.php b/src/Loader/DoctrineInsertUpdateLoader.php index 4650ce9..9cdd7e7 100644 --- a/src/Loader/DoctrineInsertUpdateLoader.php +++ b/src/Loader/DoctrineInsertUpdateLoader.php @@ -36,7 +36,7 @@ class DoctrineInsertUpdateLoader implements LoaderInterface * @var array */ protected $entitiesToProcess = []; - + public function __construct($entityManager) { $this->entityManager = $entityManager; @@ -46,11 +46,11 @@ public function __construct($entityManager) /** * @param string $entityClass * @param function $identifierCallback - * @param string $identifierProperty + * @param string $identifierProperty : if null this entity will be always insert * @param array $entityProperties properties to synchronize * @return $this */ - public function addEntityToProcess($entityClass, $identifierCallback, $identifierProperty, array $entityProperties) + public function addEntityToProcess($entityClass, $identifierCallback, $identifierProperty, array $entityProperties = []) { if (isset($this->entitiesToProcess[$entityClass])) { throw new EntityAlreadyRegisteredException($entityClass); @@ -79,7 +79,7 @@ public function load(array $data) $this->entityManager->flush(); $this->entityManager->commit(); } catch (\Exception $e) { - var_dump($e->getMessage()); + var_dump('EXCEPTION LOADER : ' . $e->getMessage()); $this->entityManager->rollback(); } } @@ -96,16 +96,21 @@ protected function processObject($object) throw new EntityTypeNotHandledException(get_class($object)); } $identifier = $this->entitiesToProcess[get_class($object)]['callback']($object); - + //Replace relations by their reference foreach ($this->entitiesToProcess[get_class($object)]['properties'] as $property) { - if (is_object($this->accessor->getValue($object, $property))) { - $relation = $this->accessor->getValue($object, $property); + $propertyValue = $this->accessor->getValue($object, $property); + if ($this->isEntityRelation($propertyValue)) { + $relation = $propertyValue; //better understanding if (!isset($this->entitiesToProcess[get_class($relation)])) { throw new EntityTypeNotHandledException(get_class($relation)); } $relationIdentifier = $this->entitiesToProcess[get_class($relation)]['callback']($relation); + if (!isset($this->references[$relationIdentifier])) { + //new relation should be processed before + $this->processObject($relation); + } $this->accessor->setValue( $object, $property, @@ -114,12 +119,15 @@ protected function processObject($object) } } - $dbObject = $this->entityManager->getRepository(get_class($object))->findOneBy([ - $this->entitiesToProcess[get_class($object)]['identifier'] => $identifier - ]); + $dbObject = null; + if (!is_null($this->entitiesToProcess[get_class($object)]['identifier'])) { + $dbObject = $this->entityManager->getRepository(get_class($object))->findOneBy([$this->entitiesToProcess[get_class($object)]['identifier'] => $identifier]); + } if ($dbObject === null) { $this->entityManager->persist($object); - $this->references[$identifier] = $object; + if (!is_null($identifier)) { + $this->references[$identifier] = $object; + } } else { foreach ($this->entitiesToProcess[get_class($object)]['properties'] as $property) { $this->accessor->setValue($dbObject, $property, $this->accessor->getValue($object, $property)); @@ -129,4 +137,15 @@ protected function processObject($object) return $object; } + + /** + * Check if $propertyValue is an entity relation to process + * + * @param mixed $propertyValue + * @return bool + */ + protected function isEntityRelation($propertyValue) + { + return (is_object($propertyValue) && !($propertyValue instanceof \DateTime)); + } } diff --git a/tests/Entity/Organisation.php b/tests/Entity/Organisation.php new file mode 100644 index 0000000..66f9cc3 --- /dev/null +++ b/tests/Entity/Organisation.php @@ -0,0 +1,87 @@ +id; + } + + /** + * @param int $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return ArrayCollection + */ + public function getProjects() + { + return $this->projects; + } + + /** + * @param ArrayCollection $projects + */ + public function setProjects($projects) + { + $this->projects = $projects; + } +} diff --git a/tests/Entity/Project.php b/tests/Entity/Project.php index cb0e739..04422d3 100644 --- a/tests/Entity/Project.php +++ b/tests/Entity/Project.php @@ -21,6 +21,13 @@ class Project extends ProjectModel */ protected $id; + /** + * @var Organisation + * @ORM\ManyToOne(targetEntity="Smart\EtlBundle\Tests\Entity\Organisation", inversedBy="projects") + * @ORM\JoinColumn(nullable=true) + */ + protected $organisation; + /** * @var string * diff --git a/tests/Loader/DoctrineInsertUpdateLoaderTest.php b/tests/Loader/DoctrineInsertUpdateLoaderTest.php index 3ea391a..c53fe43 100644 --- a/tests/Loader/DoctrineInsertUpdateLoaderTest.php +++ b/tests/Loader/DoctrineInsertUpdateLoaderTest.php @@ -6,6 +6,7 @@ use Doctrine\ORM\Tools\SchemaTool; use Liip\FunctionalTestBundle\Test\WebTestCase; use Smart\EtlBundle\Loader\DoctrineInsertUpdateLoader; +use Smart\EtlBundle\Tests\Entity\Organisation; use Smart\EtlBundle\Tests\Entity\Project; use Smart\EtlBundle\Tests\Entity\Task; @@ -28,14 +29,28 @@ public function testLoad() $schemaTool->createSchema([$metadatas]); $this->loadFixtureFiles([ + __DIR__ . '/../fixtures/doctrine-loader/organisation.yml', __DIR__ . '/../fixtures/doctrine-loader/project.yml', __DIR__ . '/../fixtures/doctrine-loader/task.yml', ]); + $smartbooster = new Organisation(); + $smartbooster->setName('SMART BOOSTER updated'); + $smartbooster->setImportId('smartbooster'); + $projectEtl = new Project('etl-bundle', 'ETL Bundle'); + $projectEtl->setOrganisation($smartbooster); $projectEtl->setDescription('new description updated'); $loader = new DoctrineInsertUpdateLoader($em); + $loader->addEntityToProcess( + 'Smart\EtlBundle\Tests\Entity\Organisation', + function ($e) { + return $e->getImportId(); + }, + 'importId', + [] //nothing to update, just for relation linking + ); $loader->addEntityToProcess( 'Smart\EtlBundle\Tests\Entity\Project', function ($e) { @@ -43,6 +58,7 @@ function ($e) { }, 'code', [ + 'organisation', 'code', 'name', 'description' @@ -70,6 +86,10 @@ function ($e) { $this->assertEquals('new description updated', $projectEtlLoaded->getDescription()); $this->assertEquals(2, $em->getRepository('Smart\EtlBundle\Tests\Entity\Project')->count([])); + //Test relation linking + $smartboosterDb = $projectEtlLoaded->getOrganisation(); + $this->assertEquals('SMART BOOSTER', $smartboosterDb->getName()); + //Test Insertion $newProject = new Project('new-project', 'new project'); $loader->load([$projectEtl, $newProject]); diff --git a/tests/Model/Project.php b/tests/Model/Project.php index 0966210..ffbdadb 100644 --- a/tests/Model/Project.php +++ b/tests/Model/Project.php @@ -3,6 +3,7 @@ namespace Smart\EtlBundle\Tests\Model; use Smart\EtlBundle\Entity\ImportableTrait; +use Smart\EtlBundle\Tests\Entity\Organisation; /** * Nicolas Bastien @@ -11,6 +12,11 @@ class Project { use ImportableTrait; + /** + * @var Organisation + */ + protected $organisation; + /** * @var string */ @@ -40,6 +46,22 @@ public function __toString() return (string) $this->getName(); } + /** + * @return Organisation + */ + public function getOrganisation() + { + return $this->organisation; + } + + /** + * @param Organisation $organisation + */ + public function setOrganisation($organisation) + { + $this->organisation = $organisation; + } + /** * @return string */ diff --git a/tests/fixtures/doctrine-loader/organisation.yml b/tests/fixtures/doctrine-loader/organisation.yml new file mode 100644 index 0000000..4898afc --- /dev/null +++ b/tests/fixtures/doctrine-loader/organisation.yml @@ -0,0 +1,4 @@ +Smart\EtlBundle\Tests\Entity\Organisation: + smartbooster: + name: SMART BOOSTER + import_id: smartbooster