Skip to content

Commit

Permalink
Merge pull request ntidev#6 from ntidev/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
ntidev authored Jul 18, 2018
2 parents d540715 + a992791 commit 2195d6b
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 138 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
# Backup entities generated with doctrine:generate:entities command
**/Entity/*~

./.idea
13 changes: 13 additions & 0 deletions Annotations/SyncEntity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace NTI\SyncBundle\Annotations;
use Doctrine\Common\Annotations\Annotation\Required;

/**
* Class SyncParent
* @package NTI\SyncBundle\Annotations
* @Annotation
*/
class SyncEntity {

}
17 changes: 17 additions & 0 deletions Annotations/SyncParent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace NTI\SyncBundle\Annotations;
use Doctrine\Common\Annotations\Annotation\Required;

/**
* Class SyncParent
* @package NTI\SyncBundle\Annotations
* @Annotation
*/
class SyncParent {
/**
* @var string
* @Required()
*/
public $getter;
}
2 changes: 1 addition & 1 deletion Entity/SyncFailedItemState.php
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class SyncFailedItemState {
/**
* @var string
*
* @ORM\Column(name="errors", columnDefinition="TEXT", length=65535, nullable=true)
* @ORM\Column(name="errors", type="text", nullable=true)
*/
private $errors;

Expand Down
2 changes: 1 addition & 1 deletion Entity/SyncMapping.php
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class SyncMapping
/**
* @var string
*
* @ORM\Column(name="sync_service", type="string", length=255, nullable=false)
* @ORM\Column(name="sync_service", type="string", length=255, nullable=true)
*/
private $syncService;

Expand Down
99 changes: 0 additions & 99 deletions EventListener/DoctrineEventSubscriber.php

This file was deleted.

127 changes: 127 additions & 0 deletions EventSubscriber/DoctrineEventSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?php

namespace NTI\SyncBundle\EventSubscriber;

use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\EventSubscriber;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\UnitOfWork;
use NTI\SyncBundle\Annotations\SyncEntity;
use NTI\SyncBundle\Annotations\SyncParent;
use NTI\SyncBundle\Entity\SyncMapping;
use NTI\SyncBundle\Entity\SyncState;
use Symfony\Component\DependencyInjection\ContainerInterface;

class DoctrineEventSubscriber implements EventSubscriber
{
private $container;
private $syncService;

public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->syncService = $this->container->get('nti.sync');
}

public function getSubscribedEvents()
{
return array(
'onFlush',
);
}

public function onFlush(OnFlushEventArgs $args)
{

$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();

foreach ($uow->getScheduledEntityUpdates() as $entity) {
$this->processEntity($em, $entity);
}

foreach ($uow->getScheduledEntityInsertions() as $entity) {
$this->processEntity($em, $entity);
}

foreach ($uow->getScheduledEntityDeletions() as $entity) {
$this->processEntity($em, $entity, true);
$this->container->get('nti.sync')->addToDeleteSyncState(ClassUtils::getClass($entity), $entity->getId());

}

/** @var PersistentCollection $collectionUpdate */
foreach ($uow->getScheduledCollectionUpdates() as $collectionUpdate) {
foreach($collectionUpdate as $entity) {
$this->processEntity($em, $entity);
}
}

/** @var PersistentCollection $collectionDeletion */
foreach($uow->getScheduledCollectionDeletions() as $collectionDeletion) {
foreach($collectionDeletion as $entity) {
$this->processEntity($em, $entity, true);
$this->container->get('nti.sync')->addToDeleteSyncState(ClassUtils::getClass($entity), $entity->getId());
}
}

}

private function processEntity(EntityManagerInterface $em, $entity, $deleting = false)
{

$reflection = new \ReflectionClass(ClassUtils::getClass($entity));
$annotationReader = new AnnotationReader();
$syncEntityAnnotation = $annotationReader->getClassAnnotation($reflection, SyncEntity::class);
// Check if the entity should be synchronized
if (!$syncEntityAnnotation) {
return;
}

$uow = $em->getUnitOfWork();
$timestamp = time();

// Update the mapping's sync state if exists
$mapping = $em->getRepository(SyncMapping::class)->findOneBy(array("class" => ClassUtils::getClass($entity)));
if($mapping) {
$syncState = $em->getRepository(SyncState::class)->findOneBy(array("mapping" => $mapping));
if(!$syncState) {
$syncState = new SyncState();
$syncState->setMapping($mapping);
$em->persist($syncState);
}
$syncState->setTimestamp($timestamp);
if($uow->getEntityState($syncState) == UnitOfWork::STATE_MANAGED) {
$uow->recomputeSingleEntityChangeSet($em->getClassMetadata(SyncState::class), $syncState);
}
}

// Check if this class itself has a lastTimestamp
if(!$deleting && method_exists($entity, 'setLastTimestamp')) {
$entity->setLastTimestamp($timestamp);
$uow->recomputeSingleEntityChangeSet($em->getClassMetadata(ClassUtils::getClass($entity)), $entity);
}

// Notify relationships
/** @var \ReflectionProperty $property */
foreach ($reflection->getProperties() as $property) {

/** @var SyncParent $annotation */
if (null !== ($annotation = $annotationReader->getPropertyAnnotation($property, SyncParent::class))) {
$getter = $annotation->getter;
$parent = $entity->$getter();
// Using ClassUtils as $parent is actually a Proxy of the class
$reflrectionParent = new \ReflectionClass(ClassUtils::getClass($parent));
$syncParentAnnotation = $annotationReader->getClassAnnotation($reflrectionParent, SyncEntity::class);
if(!$syncParentAnnotation) {
continue;
}
$this->processEntity($em, $parent);
}
}
}
}
2 changes: 1 addition & 1 deletion Resources/config/services.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
services:
nti.sync.doctrine.listener:
class: NTI\SyncBundle\EventListener\DoctrineEventSubscriber
class: NTI\SyncBundle\EventSubscriber\DoctrineEventSubscriber
arguments: ["@service_container"]
tags:
- { name: doctrine.event_subscriber, connection: default }
Expand Down
42 changes: 6 additions & 36 deletions Service/SyncService.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use NTI\SyncBundle\Entity\SyncDeleteState;
use NTI\SyncBundle\Entity\SyncFailedItemState;
use NTI\SyncBundle\Entity\SyncMapping;
use NTI\SyncBundle\Entity\SyncNewItemState;
use NTI\SyncBundle\Entity\SyncState;
Expand Down Expand Up @@ -62,10 +63,7 @@ public function getFromMappings($mappings) {

$deletes = $this->em->getRepository(SyncDeleteState::class)->findFromTimestamp($mappingName, $timestamp);
$newItems = $this->em->getRepository(SyncNewItemState::class)->findFromTimestampAndMapping($mappingName, $timestamp);
/**
* Failed Items Synchronization
*/
$failedItems = $this->em->getRepository('NTISyncBundle:SyncFailedItemState')->findFromTimestampAndMapping($mappingName, $timestamp);
$failedItems = $this->em->getRepository(SyncFailedItemState::class)->findFromTimestampAndMapping($mappingName, $timestamp);

/** @var SyncRepositoryInterface $repository */
$repository = $this->em->getRepository($syncMapping->getClass());
Expand All @@ -80,38 +78,14 @@ public function getFromMappings($mappings) {
'changes' => $result["data"],
'deletes' => json_decode($this->container->get('jms_serializer')->serialize($deletes, 'json'), true),
'newItems' => json_decode($this->container->get('jms_serializer')->serialize($newItems, 'json'), true),
'failedItems' => json_decode($this->container->get('jms_serializer')->serialize($failedItems, 'json'), true),
'failedItems' => json_decode($this->container->get('jms_serializer')->serialize($failedItems, 'json'), true),
SyncState::REAL_LAST_TIMESTAMP => $result[SyncState::REAL_LAST_TIMESTAMP],
);
}

return $changes;
}

public function updateSyncState(EntityManagerInterface $em, $class, $timestamp) {

$mapping = $em->getRepository(SyncMapping::class)->findOneBy(array("class" => $class));
if(!$mapping) {
return;
}

$syncState = $em->getRepository(SyncState::class)->findOneBy(array("mapping" => $mapping));

$uow = $em->getUnitOfWork();

if(!$syncState) {
$syncState = new SyncState();
$syncState->setMapping($mapping);
$syncState->setTimestamp($timestamp);
$em->persist($syncState);
$uow->computeChangeSet($em->getClassMetadata(SyncState::class), $syncState);
} else {
$syncState->setTimestamp($timestamp);
$uow->recomputeSingleEntityChangeSet($em->getClassMetadata(SyncState::class), $syncState);
}

}

/**
* Create a new SyncDeleteState for the given class/id
*
Expand All @@ -122,6 +96,7 @@ public function addToDeleteSyncState($class, $id) {

$this->em = $this->container->get('doctrine')->getManager();

/** @var SyncMapping $mapping */
$mapping = $this->em->getRepository(SyncMapping::class)->findOneBy(array("class" => $class));
if(!$mapping) {
return;
Expand All @@ -133,12 +108,7 @@ public function addToDeleteSyncState($class, $id) {
$deleteEntry->setTimestamp(time());

$this->em->persist($deleteEntry);

try {
$this->em->flush();
} catch (\Exception $ex) {
error_log("Unable to register deletion of object: " . $class . " with ID " . $id);
error_log($ex->getMessage());
}
$uow = $this->em->getUnitOfWork();
$uow->computeChangeSet($this->em->getClassMetadata(SyncDeleteState::class), $deleteEntry);
}
}

0 comments on commit 2195d6b

Please sign in to comment.