Fixing issue with removing mapped Doctrine entities/documents

This commit is contained in:
Richard Miller 2012-01-25 19:51:10 +00:00
commit 65be0a415e
10 changed files with 191 additions and 30 deletions

View file

@ -316,13 +316,8 @@ class FOQElasticaExtension extends Extension
$listenerDef = new DefinitionDecorator($abstractListenerId);
$listenerDef->replaceArgument(0, new Reference($objectPersisterId));
$listenerDef->replaceArgument(1, $typeConfig['model']);
$events = array();
$doctrineEvents = array('insert' => 'postPersist', 'update' => 'postUpdate', 'delete' => 'postRemove');
foreach ($doctrineEvents as $event => $doctrineEvent) {
if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
$events[] = $doctrineEvent;
}
}
$listenerDef->replaceArgument(3, $typeConfig['identifier']);
$events = $this->getDoctrineEvents($typeConfig);
$listenerDef->replaceArgument(2, $events);
switch ($typeConfig['driver']) {
case 'orm': $listenerDef->addTag('doctrine.event_subscriber'); break;
@ -333,6 +328,22 @@ class FOQElasticaExtension extends Extension
return $listenerId;
}
private function getDoctrineEvents(array $typeConfig)
{
$events = array();
$eventMapping = array(
'insert' => array('postPersist'),
'update' => array('postUpdate'),
'delete' => array('postRemove', 'preRemove')
);
foreach ($eventMapping as $event => $doctrineEvents) {
if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) {
$events = array_merge($events, $doctrineEvents);
}
}
return $events;
}
protected function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, $typeDef, $indexName, $typeName)
{
if (isset($typeConfig['finder']['service'])) {

View file

@ -28,14 +28,19 @@ abstract class AbstractListener
*/
protected $events;
protected $identifier;
protected $scheduledForRemoval;
/**
* Constructor
**/
public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $events)
public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $events, $identifier = 'id')
{
$this->objectPersister = $objectPersister;
$this->objectClass = $objectClass;
$this->events = $events;
$this->objectPersister = $objectPersister;
$this->objectClass = $objectClass;
$this->events = $events;
$this->identifier = $identifier;
$this->scheduledForRemoval = new \SplObjectStorage();
}
/**
@ -46,4 +51,17 @@ abstract class AbstractListener
return $this->events;
}
protected function scheduleForRemoval($object)
{
$getIdentifierMethod = 'get' . ucfirst($this->identifier);
$this->scheduledForRemoval[$object] = $object->$getIdentifierMethod();
}
protected function removeIfScheduled($object)
{
if (isset($this->scheduledForRemoval[$object])) {
$this->objectPersister->deleteById($this->scheduledForRemoval[$object]);
}
}
}

View file

@ -26,12 +26,21 @@ class Listener extends AbstractListener implements EventSubscriber
}
}
public function preRemove(LifecycleEventArgs $eventArgs)
{
$document = $eventArgs->getDocument();
if ($document instanceof $this->objectClass) {
$this->scheduleForRemoval($document);
}
}
public function postRemove(LifecycleEventArgs $eventArgs)
{
$document = $eventArgs->getDocument();
if ($document instanceof $this->objectClass) {
$this->objectPersister->deleteOne($document);
$this->removeIfScheduled($document);
}
}
}

View file

@ -26,12 +26,22 @@ class Listener extends AbstractListener implements EventSubscriber
}
}
public function preRemove(LifecycleEventArgs $eventArgs)
{
$entity = $eventArgs->getEntity();
if ($entity instanceof $this->objectClass) {
$this->scheduleForRemoval($entity);
}
}
public function postRemove(LifecycleEventArgs $eventArgs)
{
$entity = $eventArgs->getEntity();
if ($entity instanceof $this->objectClass) {
$this->objectPersister->deleteOne($entity);
$this->removeIfScheduled($entity);
}
}
}

View file

@ -61,12 +61,28 @@ class ObjectPersister implements ObjectPersisterInterface
* @param object $object
* @return null
**/
public function deleteOne($object)
public function deleteOne($object, $id = null)
{
$document = $this->transformToElasticaDocument($object);
$this->type->deleteById($document->getId());
if (!$id) {
$document = $this->transformToElasticaDocument($object);
$id = $document->getId();
}
$this->type->deleteById($id);
}
/**
* Deletes one object in the type by id
*
* @param mixed $id
*
* @return null
**/
public function deleteById($id)
{
$this->type->deleteById($id);
}
/**
* Inserts an array of objects in the type
*

View file

@ -32,6 +32,15 @@ interface ObjectPersisterInterface
**/
function deleteOne($object);
/**
* Deletes one object in the type by id
*
* @param mixed $id
*
* @return null
**/
function deleteById($id);
/**
* Inserts an array of objects in the type
*

View file

@ -18,6 +18,7 @@
<argument /> <!-- object persister -->
<argument /> <!-- model -->
<argument type="collection" /> <!-- events -->
<argument/> <!-- identifier -->
</service>
<service id="foq_elastica.elastica_to_model_transformer.prototype.mongodb" class="FOQ\ElasticaBundle\Doctrine\MongoDB\ElasticaToModelTransformer" public="false">

View file

@ -18,6 +18,7 @@
<argument /> <!-- object persister -->
<argument /> <!-- model -->
<argument type="collection" /> <!-- events -->
<argument/> <!-- identifier -->
</service>
<service id="foq_elastica.elastica_to_model_transformer.prototype.orm" class="FOQ\ElasticaBundle\Doctrine\ORM\ElasticaToModelTransformer" public="false">

View file

@ -4,7 +4,20 @@ namespace FOQ\ElasticaBundle\Tests\Doctrine\MongoDB;
use FOQ\ElasticaBundle\Doctrine\MongoDB\Listener;
class Document{}
class Document
{
public function getId()
{
return ListenerTest::DOCUMENT_ID;
}
public function getIdentifier()
{
return ListenerTest::DOCUMENT_IDENTIFIER;
}
}
/**
* @author Richard Miller <info@limethinking.co.uk>
@ -12,6 +25,9 @@ class Document{}
class ListenerTest extends \PHPUnit_Framework_TestCase
{
const DOCUMENT_ID = 78;
const DOCUMENT_IDENTIFIER = 826;
public function testObjectInsertedOnPersist()
{
$persisterMock = $this->getMockBuilder('FOQ\ElasticaBundle\Persister\ObjectPersisterInterface')
@ -33,7 +49,7 @@ class ListenerTest extends \PHPUnit_Framework_TestCase
->method('insertOne')
->with($this->equalTo($document));
$listener = new Listener($persisterMock, $objectName, array(), null);
$listener = new Listener($persisterMock, $objectName, array());
$listener->postPersist($eventArgsMock);
}
@ -58,7 +74,7 @@ class ListenerTest extends \PHPUnit_Framework_TestCase
->method('replaceOne')
->with($this->equalTo($document));
$listener = new Listener($persisterMock, $objectName, array(), null);
$listener = new Listener($persisterMock, $objectName, array());
$listener->postUpdate($eventArgsMock);
}
@ -75,15 +91,42 @@ class ListenerTest extends \PHPUnit_Framework_TestCase
$objectName = 'FOQ\ElasticaBundle\Tests\Doctrine\MongoDB\Document';
$document = new Document();
$eventArgsMock->expects($this->once())
$eventArgsMock->expects($this->any())
->method('getDocument')
->will($this->returnValue($document));
$persisterMock->expects($this->once())
->method('deleteOne')
->with($this->equalTo($document));
->method('deleteById')
->with($this->equalTo(self::DOCUMENT_ID));
$listener = new Listener($persisterMock, $objectName, array(), null);
$listener = new Listener($persisterMock, $objectName, array());
$listener->preRemove($eventArgsMock);
$listener->postRemove($eventArgsMock);
}
public function testObjectWithNonStandardIdentifierDeletedOnRemove()
{
$persisterMock = $this->getMockBuilder('FOQ\ElasticaBundle\Persister\ObjectPersisterInterface')
->disableOriginalConstructor()
->getMock();
$eventArgsMock = $this->getMockBuilder('Doctrine\ODM\MongoDB\Event\LifecycleEventArgs')
->disableOriginalConstructor()
->getMock();
$objectName = 'FOQ\ElasticaBundle\Tests\Doctrine\MongoDB\Document';
$document = new Document();
$eventArgsMock->expects($this->any())
->method('getDocument')
->will($this->returnValue($document));
$persisterMock->expects($this->once())
->method('deleteById')
->with($this->equalTo(self::DOCUMENT_IDENTIFIER));
$listener = new Listener($persisterMock, $objectName, array(), 'identifier');
$listener->preRemove($eventArgsMock);
$listener->postRemove($eventArgsMock);
}

View file

@ -4,7 +4,20 @@ namespace FOQ\ElasticaBundle\Tests\Doctrine\ORM;
use FOQ\ElasticaBundle\Doctrine\ORM\Listener;
class Entity{}
class Entity
{
public function getId()
{
return ListenerTest::ENTITY_ID;
}
public function getIdentifier()
{
return ListenerTest::ENTITY_IDENTIFIER;
}
}
/**
* @author Richard Miller <info@limethinking.co.uk>
@ -12,6 +25,9 @@ class Entity{}
class ListenerTest extends \PHPUnit_Framework_TestCase
{
const ENTITY_ID = 21;
const ENTITY_IDENTIFIER = 912;
public function testObjectInsertedOnPersist()
{
$persisterMock = $this->getMockBuilder('FOQ\ElasticaBundle\Persister\ObjectPersisterInterface')
@ -33,7 +49,7 @@ class ListenerTest extends \PHPUnit_Framework_TestCase
->method('insertOne')
->with($this->equalTo($entity));
$listener = new Listener($persisterMock, $objectName, array(), null);
$listener = new Listener($persisterMock, $objectName, array());
$listener->postPersist($eventArgsMock);
}
@ -58,7 +74,7 @@ class ListenerTest extends \PHPUnit_Framework_TestCase
->method('replaceOne')
->with($this->equalTo($entity));
$listener = new Listener($persisterMock, $objectName, array(), null);
$listener = new Listener($persisterMock, $objectName, array());
$listener->postUpdate($eventArgsMock);
}
@ -75,15 +91,42 @@ class ListenerTest extends \PHPUnit_Framework_TestCase
$objectName = 'FOQ\ElasticaBundle\Tests\Doctrine\ORM\Entity';
$entity = new Entity;
$eventArgsMock->expects($this->once())
$eventArgsMock->expects($this->any())
->method('getEntity')
->will($this->returnValue($entity));
$persisterMock->expects($this->once())
->method('deleteOne')
->with($this->equalTo($entity));
->method('deleteById')
->with($this->equalTo(self::ENTITY_ID));
$listener = new Listener($persisterMock, $objectName, array(), null);
$listener = new Listener($persisterMock, $objectName, array());
$listener->preRemove($eventArgsMock);
$listener->postRemove($eventArgsMock);
}
public function testObjectWithNonStandardIdentifierDeletedOnRemove()
{
$persisterMock = $this->getMockBuilder('FOQ\ElasticaBundle\Persister\ObjectPersisterInterface')
->disableOriginalConstructor()
->getMock();
$eventArgsMock = $this->getMockBuilder('Doctrine\ORM\Event\LifecycleEventArgs')
->disableOriginalConstructor()
->getMock();
$objectName = 'FOQ\ElasticaBundle\Tests\Doctrine\ORM\Entity';
$entity = new Entity;
$eventArgsMock->expects($this->any())
->method('getEntity')
->will($this->returnValue($entity));
$persisterMock->expects($this->once())
->method('deleteById')
->with($this->equalTo(self::ENTITY_IDENTIFIER));
$listener = new Listener($persisterMock, $objectName, array(), 'identifier');
$listener->preRemove($eventArgsMock);
$listener->postRemove($eventArgsMock);
}