Skip to content

Commit

Permalink
#11 : Doctrine loader : allow to work with unparsed relation + allow …
Browse files Browse the repository at this point in the history
…to pass null identifier for strict insertion
  • Loading branch information
nicolas-bastien committed Dec 2, 2018
1 parent b98102f commit b2c1f19
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 11 deletions.
41 changes: 30 additions & 11 deletions src/Loader/DoctrineInsertUpdateLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class DoctrineInsertUpdateLoader implements LoaderInterface
* @var array
*/
protected $entitiesToProcess = [];

public function __construct($entityManager)
{
$this->entityManager = $entityManager;
Expand All @@ -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);
Expand Down Expand Up @@ -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();
}
}
Expand All @@ -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,
Expand All @@ -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));
Expand All @@ -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));
}
}
87 changes: 87 additions & 0 deletions tests/Entity/Organisation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

namespace Smart\EtlBundle\Tests\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Smart\EtlBundle\Entity\ImportableTrait;

/**
* @ORM\Entity()
* @ORM\Table(name="etlbundle_organisation")
*/
class Organisation
{
use ImportableTrait;

/**
* @var int
*
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;

/**
* @var string
*
* @ORM\Column(type="string", length=255, nullable=false)
*/
protected $name;

/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="Smart\EtlBundle\Tests\Entity\Project", mappedBy="organisation")
*/
protected $projects;

/**
* @return int
*/
public function getId()
{
return $this->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;
}
}
7 changes: 7 additions & 0 deletions tests/Entity/Project.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down
20 changes: 20 additions & 0 deletions tests/Loader/DoctrineInsertUpdateLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -28,21 +29,36 @@ 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) {
return $e->getCode();
},
'code',
[
'organisation',
'code',
'name',
'description'
Expand Down Expand Up @@ -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]);
Expand Down
22 changes: 22 additions & 0 deletions tests/Model/Project.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Smart\EtlBundle\Tests\Model;

use Smart\EtlBundle\Entity\ImportableTrait;
use Smart\EtlBundle\Tests\Entity\Organisation;

/**
* Nicolas Bastien <nicolas.bastien@smartbooster.io>
Expand All @@ -11,6 +12,11 @@ class Project
{
use ImportableTrait;

/**
* @var Organisation
*/
protected $organisation;

/**
* @var string
*/
Expand Down Expand Up @@ -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
*/
Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/doctrine-loader/organisation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Smart\EtlBundle\Tests\Entity\Organisation:
smartbooster:
name: SMART BOOSTER
import_id: smartbooster

0 comments on commit b2c1f19

Please # to comment.