From 8ae6489eaacffeb3f94044c4c033052099d02a40 Mon Sep 17 00:00:00 2001 From: dantleech Date: Wed, 25 Mar 2015 09:14:09 +0000 Subject: [PATCH 1/4] Support order of tree operations --- lib/Doctrine/ODM/PHPCR/DocumentManager.php | 4 +- .../ODM/PHPCR/Queue/TreeOperation.php | 47 +++++++ .../ODM/PHPCR/Queue/TreeOperationBatch.php | 29 ++++ .../ODM/PHPCR/Queue/TreeOperationQueue.php | 107 +++++++++++++++ lib/Doctrine/ODM/PHPCR/UnitOfWork.php | 128 +++++++++--------- .../ODM/PHPCR/Functional/BasicCrudTest.php | 26 ++++ 6 files changed, 279 insertions(+), 62 deletions(-) create mode 100644 lib/Doctrine/ODM/PHPCR/Queue/TreeOperation.php create mode 100644 lib/Doctrine/ODM/PHPCR/Queue/TreeOperationBatch.php create mode 100644 lib/Doctrine/ODM/PHPCR/Queue/TreeOperationQueue.php diff --git a/lib/Doctrine/ODM/PHPCR/DocumentManager.php b/lib/Doctrine/ODM/PHPCR/DocumentManager.php index 9241e92e0..eb44168e4 100644 --- a/lib/Doctrine/ODM/PHPCR/DocumentManager.php +++ b/lib/Doctrine/ODM/PHPCR/DocumentManager.php @@ -389,7 +389,9 @@ public function findMany($className, array $ids) } $nodes = $this->session->getNodes($ids); - $hints = array('fallback' => true); + $hints = array( + 'fallback' => true, + ); $documents = $this->unitOfWork->getOrCreateDocuments($className, $nodes, $hints); return new ArrayCollection($documents); diff --git a/lib/Doctrine/ODM/PHPCR/Queue/TreeOperation.php b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperation.php new file mode 100644 index 000000000..be9527a33 --- /dev/null +++ b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperation.php @@ -0,0 +1,47 @@ +oid = $oid; + $this->type = $type; + $this->args = $args; + } + + public function getOid() + { + return $this->oid; + } + + public function getType() + { + return $this->type; + } + + public function getArgs() + { + return $this->args; + } + + public function invalidate() + { + $this->valid = false; + } + + public function isValid() + { + return $this->valid; + } +} diff --git a/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationBatch.php b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationBatch.php new file mode 100644 index 000000000..5d8a2f60d --- /dev/null +++ b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationBatch.php @@ -0,0 +1,29 @@ +type = $type; + } + + public function getSchedule() + { + return $this->schedule; + } + + public function schedule($oid, $args) + { + $this->schedule[$oid] = $args; + } + + public function getType() + { + return $this->type; + } +} diff --git a/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationQueue.php b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationQueue.php new file mode 100644 index 000000000..65e69cfd8 --- /dev/null +++ b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationQueue.php @@ -0,0 +1,107 @@ +queue[] = $operation; + } + + /** + * Partition into contiguous sets of operations + */ + public function getBatches() + { + $type = null; + $batches = array(); + + foreach ($this->queue as $operation) { + if (false === $operation->isValid()) { + continue; + } + + if ($operation->getType() !== $type) { + $batch = new TreeOperationBatch($operation->getType()); + $type = $operation->getType(); + $batches[] = $batch; + } + + $batch->schedule( + $operation->getOid(), + $operation->getArgs() + ); + } + + return $batches; + } + + public function clear() + { + $this->queue = array(); + } + + public function getSchedule($type) + { + $schedule = array(); + + foreach ($this->queue as $operation) { + if (false === $operation->isValid()) { + continue; + } + + $schedule[$operation->getOid()] = $operation->getArgs(); + } + + return $schedule; + } + + public function isQueued($type, $oid) + { + foreach ($this->queue as $operation) { + if (false === $operation->isValid()) { + continue; + } + + if ($operation->getType() !== $type) { + continue; + } + + if ($oid == $operation->getOid()) { + return true; + } + } + + return false; + } + + public function unqueue($type, $oid) + { + foreach ($this->queue as $operation) { + if ($operation->getType() !== $type) { + continue; + } + + if ($operation->getOid() !== $oid) { + continue; + } + + $operation->invalidate(); + } + } + + public function unregister($oid) + { + foreach ($this->queue as $operation) { + if ($operation->getOid() == $oid) { + $operation->invalidate(); + } + } + } +} diff --git a/lib/Doctrine/ODM/PHPCR/UnitOfWork.php b/lib/Doctrine/ODM/PHPCR/UnitOfWork.php index 8ddd01814..10319bbc8 100644 --- a/lib/Doctrine/ODM/PHPCR/UnitOfWork.php +++ b/lib/Doctrine/ODM/PHPCR/UnitOfWork.php @@ -57,6 +57,8 @@ use PHPCR\Util\NodeHelper; use Jackalope\Session as JackalopeSession; +use Doctrine\ODM\PHPCR\Queue\TreeOperation; +use Doctrine\ODM\PHPCR\Queue\TreeOperationQueue; /** * Unit of work class @@ -168,20 +170,6 @@ class UnitOfWork */ private $scheduledUpdates = array(); - /** - * List of documents that will be inserted on next flush - * oid => document - * @var array - */ - private $scheduledInserts = array(); - - /** - * List of documents that will be moved on next flush - * oid => array(document, target path) - * @var array - */ - private $scheduledMoves = array(); - /** * List of parent documents that have children that will be reordered on next flush * parent oid => list of array with records array(parent document, srcName, targetName, before) with @@ -194,13 +182,6 @@ class UnitOfWork */ private $scheduledReorders = array(); - /** - * List of documents that will be removed on next flush - * oid => document - * @var array - */ - private $scheduledRemovals = array(); - /** * @var array */ @@ -260,6 +241,11 @@ class UnitOfWork */ private $useFetchDepth; + /** + * @var TreeOperationQueue + */ + private $treeOpQueue; + /** * @param DocumentManager $dm */ @@ -269,6 +255,7 @@ public function __construct(DocumentManager $dm) $this->session = $dm->getPhpcrSession(); $this->eventListenersInvoker = new ListenersInvoker($dm); $this->eventManager = $dm->getEventManager(); + $this->treeOpQueue = new TreeOperationQueue(); $config = $dm->getConfiguration(); $this->documentClassMapper = $config->getDocumentClassMapper(); @@ -813,7 +800,7 @@ private function doScheduleInsert($document, &$visited, $overrideIdGenerator = n // TODO: Change Tracking Deferred Explicit break; case self::STATE_REMOVED: - unset($this->scheduledRemovals[$oid]); + $this->treeOpQueue->unqueue(TreeOperation::OP_REMOVE, $oid); $this->setDocumentState($oid, self::STATE_MANAGED); break; case self::STATE_DETACHED: @@ -927,16 +914,22 @@ public function scheduleMove($document, $targetPath) switch ($state) { case self::STATE_NEW: - unset($this->scheduledInserts[$oid]); break; case self::STATE_REMOVED: - unset($this->scheduledRemovals[$oid]); + $this->treeOpQueue->unqueue(TreeOperation::OP_REMOVE, $oid); break; case self::STATE_DETACHED: throw new InvalidArgumentException('Detached document passed to move(): '.self::objToStr($document, $this->dm)); } - $this->scheduledMoves[$oid] = array($document, $targetPath); + $this->treeOpQueue->push( + new TreeOperation( + TreeOperation::OP_MOVE, + $oid, + array($document, $targetPath) + ) + ); + $this->setDocumentState($oid, self::STATE_MANAGED); } @@ -975,17 +968,20 @@ private function doRemove($document, &$visited) $state = $this->getDocumentState($document); switch ($state) { case self::STATE_NEW: - unset($this->scheduledInserts[$oid]); - break; case self::STATE_MANAGED: - unset($this->scheduledMoves[$oid]); - unset($this->scheduledReorders[$oid]); break; case self::STATE_DETACHED: throw new InvalidArgumentException('Detached document passed to remove(): '.self::objToStr($document, $this->dm)); } - $this->scheduledRemovals[$oid] = $document; + $this->treeOpQueue->push( + new TreeOperation( + TreeOperation::OP_REMOVE, + $oid, + $document + ) + ); + $this->setDocumentState($oid, self::STATE_REMOVED); $class = $this->dm->getClassMetadata(get_class($document)); @@ -1100,7 +1096,7 @@ public function getDocumentState($document) */ public function isScheduledForInsert($document) { - return isset($this->scheduledInserts[spl_object_hash($document)]); + return $this->treeOpQueue->isQueued(TreeOperation::OP_INSERT); } /** @@ -1115,7 +1111,8 @@ public function computeSingleDocumentChangeSet($document) throw new InvalidArgumentException('Document has to be managed for single computation '.self::objToStr($document, $this->dm)); } - foreach ($this->scheduledInserts as $insertedDocument) { + $insertSchedule = $this->treeOpQueue->getSchedule(TreeOperation::OP_INSERT); + foreach ($insertSchedule as $insertedDocument) { $class = $this->dm->getClassMetadata(get_class($insertedDocument)); $this->computeChangeSet($class, $insertedDocument); } @@ -1126,7 +1123,7 @@ public function computeSingleDocumentChangeSet($document) } $oid = spl_object_hash($document); - if (!isset($this->scheduledInserts[$oid])) { + if (!isset($insertSchedule[$oid])) { $class = $this->dm->getClassMetadata(get_class($document)); $this->computeChangeSet($class, $document); } @@ -1577,7 +1574,6 @@ public function computeChangeSet(ClassMetadata $class, $document) if ($isNew) { $this->documentChangesets[$oid]['fields'] = $fields; - $this->scheduledInserts[$oid] = $document; return; } @@ -1769,6 +1765,14 @@ public function persistNew(ClassMetadata $class, $document, $overrideIdGenerator $id = $generator->generate($document, $class, $this->dm, $parent); $this->registerDocument($document, $id); + $this->treeOpQueue->push( + new TreeOperation( + TreeOperation::OP_INSERT, + spl_object_hash($document), + $document + ) + ); + if (!$generator instanceof AssignedIdGenerator) { $class->setIdentifierValue($document, $id); } @@ -2181,13 +2185,13 @@ public function commit($document = null) } $this->invokeGlobalEvent(Event::onFlush, new ManagerEventArgs($this->dm)); + $opBatches = $this->treeOpQueue->getBatches(); - if (empty($this->scheduledInserts) + if ( + empty($opBatches) && empty($this->scheduledUpdates) - && empty($this->scheduledRemovals) && empty($this->scheduledReorders) && empty($this->documentTranslations) - && empty($this->scheduledMoves) ) { $this->invokeGlobalEvent(Event::postFlush, new ManagerEventArgs($this->dm)); $this->changesetComputed = array(); @@ -2211,15 +2215,23 @@ public function commit($document = null) } try { - $this->executeInserts($this->scheduledInserts); - - $this->executeUpdates($this->scheduledUpdates); - $this->executeRemovals($this->scheduledRemovals); + foreach ($opBatches as $opBatch) { + switch ($opBatch->getType()) { + case TreeOperation::OP_INSERT: + $this->executeInserts($opBatch->getSchedule()); + continue; + case TreeOperation::OP_REMOVE: + $this->executeRemovals($opBatch->getSchedule()); + continue; + case TreeOperation::OP_MOVE: + $this->executeMoves($opBatch->getSchedule()); + continue; + } + } $this->executeReorders($this->scheduledReorders); - - $this->executeMoves($this->scheduledMoves); + $this->executeUpdates($this->scheduledUpdates); $this->session->save(); @@ -2259,11 +2271,9 @@ public function commit($document = null) } } + $this->treeOpQueue->clear(); $this->scheduledUpdates = - $this->scheduledRemovals = - $this->scheduledMoves = $this->scheduledReorders = - $this->scheduledInserts = $this->visitedCollections = $this->documentChangesets = $this->changesetComputed = array(); @@ -2281,10 +2291,6 @@ private function executeInserts($documents) // sort the documents to insert parents first but maintain child order $oids = array(); foreach ($documents as $oid => $document) { - if (!$this->contains($oid)) { - continue; - } - $oids[$oid] = $this->getDocumentId($document); } @@ -2318,7 +2324,9 @@ private function executeInserts($documents) && !$class->isNullable($fieldName) && !$this->isAutocreatedProperty($class, $fieldName) ) { - throw new PHPCRException(sprintf('Field "%s" of class "%s" is not nullable', $fieldName, $class->name)); + if (!$this->treeOpQueue->isQueued(TreeOperation::OP_REMOVE, $oid)) { + throw new PHPCRException(sprintf('Field "%s" of class "%s" is not nullable', $fieldName, $class->name)); + } } } @@ -3026,11 +3034,10 @@ private function unregisterDocument($document) unset($this->identityMap[$this->documentIds[$oid]]); } - unset($this->scheduledRemovals[$oid], + $this->treeOpQueue->unregister($oid); + unset( $this->scheduledUpdates[$oid], - $this->scheduledMoves[$oid], $this->scheduledReorders[$oid], - $this->scheduledInserts[$oid], $this->originalData[$oid], $this->originalTranslatedData[$oid], $this->documentIds[$oid], @@ -3075,7 +3082,7 @@ public function contains($document) { $oid = is_object($document) ? spl_object_hash($document) : $document; - return isset($this->documentIds[$oid]) && !isset($this->scheduledRemovals[$oid]); + return isset($this->documentIds[$oid]) && !$this->treeOpQueue->isQueued(TreeOperation::OP_REMOVE, $oid); } /** @@ -3177,14 +3184,13 @@ public function clear() $this->documentChangesets = $this->changesetComputed = $this->scheduledUpdates = - $this->scheduledInserts = - $this->scheduledMoves = $this->scheduledReorders = - $this->scheduledRemovals = $this->visitedCollections = $this->documentHistory = $this->documentVersion = array(); + $this->treeOpQueue->clear(); + $this->invokeGlobalEvent(Event::onClear, new OnClearEventArgs($this->dm)); $this->session->refresh(false); @@ -3818,7 +3824,7 @@ public function getScheduledUpdates() */ public function getScheduledInserts() { - return $this->scheduledInserts; + return $this->treeOpQueue->getSchedule(TreeOperation::OP_INSERT); } /** @@ -3828,7 +3834,7 @@ public function getScheduledInserts() */ public function getScheduledMoves() { - return $this->scheduledMoves; + return $this->treeOpQueue->getSchedule(TreeOperation::OP_MOVE); } /** @@ -3848,7 +3854,7 @@ public function getScheduledReorders() */ public function getScheduledRemovals() { - return $this->scheduledRemovals; + return $this->treeOpQueue->getSchedule(TreeOperation::OP_REMOVE); } /** diff --git a/tests/Doctrine/Tests/ODM/PHPCR/Functional/BasicCrudTest.php b/tests/Doctrine/Tests/ODM/PHPCR/Functional/BasicCrudTest.php index 047d7f527..97781b8ae 100644 --- a/tests/Doctrine/Tests/ODM/PHPCR/Functional/BasicCrudTest.php +++ b/tests/Doctrine/Tests/ODM/PHPCR/Functional/BasicCrudTest.php @@ -325,6 +325,32 @@ public function testRemoveAndInsertAfterFlush() $this->assertEquals($user->username, $userNew->username); } + public function testInsertMoveDelete() + { + $this->dm->clear(); + + $user = new User2(); + $user->username = "test"; + $user->id = '/functional/user1'; + $this->dm->persist($user); + + $user2 = new User2(); + $user2->username = "test"; + $user2->id = '/functional/user2'; + $this->dm->persist($user2); + + $subuser = new User2(); + $subuser->username = "test"; + $subuser->id = '/functional/user2/subuser'; + $this->dm->persist($subuser); + $this->dm->move($subuser, '/functional/user1/subuser'); + $this->dm->remove($user2); + $this->dm->flush(); + + $subuser = $this->dm->find(null, '/functional/user1/subuser'); + $this->assertNotNull($subuser); + } + public function testRemoveAndReinsert() { $this->dm->clear(); From 5d78fd7f35eb12fcfa4a5fdcde13c94d141c7593 Mon Sep 17 00:00:00 2001 From: dantleech Date: Wed, 25 Mar 2015 10:53:57 +0000 Subject: [PATCH 2/4] Added tests --- .../ODM/PHPCR/Queue/TreeOperation.php | 57 ++++++++ .../ODM/PHPCR/Queue/TreeOperationBatch.php | 46 ++++++ .../ODM/PHPCR/Queue/TreeOperationQueue.php | 58 ++++++++ lib/Doctrine/ODM/PHPCR/UnitOfWork.php | 1 + .../PHPCR/Queue/TreeOperationBatchTest.php | 33 +++++ .../PHPCR/Queue/TreeOperationQueueTest.php | 132 ++++++++++++++++++ .../ODM/PHPCR/Queue/TreeOperationTest.php | 29 ++++ 7 files changed, 356 insertions(+) create mode 100644 tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationBatchTest.php create mode 100644 tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationQueueTest.php create mode 100644 tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationTest.php diff --git a/lib/Doctrine/ODM/PHPCR/Queue/TreeOperation.php b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperation.php index be9527a33..6d9451fa9 100644 --- a/lib/Doctrine/ODM/PHPCR/Queue/TreeOperation.php +++ b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperation.php @@ -1,7 +1,30 @@ . + */ namespace Doctrine\ODM\PHPCR\Queue; +/** + * Represents a horizontal tree operation, encompassing + * MOVE, REMOVE and INSERT operations. + * + * @author Daniel Leech + */ class TreeOperation { const OP_MOVE = 'move'; @@ -13,6 +36,11 @@ class TreeOperation private $args; private $valid = true; + /** + * @param mixed $type + * @param mixed $oid + * @param mixed $args + */ public function __construct($type, $oid, $args) { $this->oid = $oid; @@ -20,26 +48,55 @@ public function __construct($type, $oid, $args) $this->args = $args; } + /** + * Return the SPL object ID which maps + * to the document on which the operaton should be + * performed. + * + * @return string + */ public function getOid() { return $this->oid; } + /** + * Return the type of operation, one of + * the self::OP_* constants. + * + * @return string + */ public function getType() { return $this->type; } + /** + * Return the arguments for the operation + * + * @return mixed + */ public function getArgs() { return $this->args; } + /** + * Invalidate this item so that it will not be processed. + * Invalidation is quicker than removing the item from the queue. + * + * @param boolean + */ public function invalidate() { $this->valid = false; } + /** + * Return true if this item should be processed + * + * @return boolean + */ public function isValid() { return $this->valid; diff --git a/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationBatch.php b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationBatch.php index 5d8a2f60d..86a32728b 100644 --- a/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationBatch.php +++ b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationBatch.php @@ -1,27 +1,73 @@ . + */ namespace Doctrine\ODM\PHPCR\Queue; +/** + * Represents a batch of operations of the same type + * + * @author Daniel Leech + */ class TreeOperationBatch { private $type; private $schedule = array(); + /** + * @param mixed $type + */ public function __construct($type) { $this->type = $type; } + /** + * Return the operation schedule, e.g. + * + * array( + * $oid => $args + * ) + * + * @return array + */ public function getSchedule() { return $this->schedule; } + /** + * Schedule an operation + * + * @param string $oid + * @param array $args + */ public function schedule($oid, $args) { $this->schedule[$oid] = $args; } + /** + * Return the operation type, one of the + * TreeOperation::OP_* constants. + * + * @return string + */ public function getType() { return $this->type; diff --git a/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationQueue.php b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationQueue.php index 65e69cfd8..e5f0bfe75 100644 --- a/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationQueue.php +++ b/lib/Doctrine/ODM/PHPCR/Queue/TreeOperationQueue.php @@ -1,14 +1,41 @@ . + */ namespace Doctrine\ODM\PHPCR\Queue; use Doctrine\ODM\PHPCR\Queue\TreeOperation; use Doctrine\ODM\PHPCR\Queue\TreeOperationBatch; +/** + * The tree operation queue + * + * @author Daniel Leech + */ class TreeOperationQueue { private $queue = array(); + /** + * Push a new operation onto the queue + * + * @param TreeOperation $operation + */ public function push(TreeOperation $operation) { $this->queue[] = $operation; @@ -16,6 +43,8 @@ public function push(TreeOperation $operation) /** * Partition into contiguous sets of operations + * + * @return TreeOperationBatch[] */ public function getBatches() { @@ -42,11 +71,21 @@ public function getBatches() return $batches; } + /** + * Clear the queue + */ public function clear() { $this->queue = array(); } + /** + * Return the entire schedule for the given operation type + * + * @param string $type + * + * @return array + */ public function getSchedule($type) { $schedule = array(); @@ -62,6 +101,14 @@ public function getSchedule($type) return $schedule; } + /** + * Return true if the spl object id is scheduled for the given type + * + * @param string $type + * @param string $oid + * + * @return boolean + */ public function isQueued($type, $oid) { foreach ($this->queue as $operation) { @@ -81,6 +128,12 @@ public function isQueued($type, $oid) return false; } + /** + * Remove all operations with the given spl object ID and type + * + * @param string $type + * @param string $oid + */ public function unqueue($type, $oid) { foreach ($this->queue as $operation) { @@ -96,6 +149,11 @@ public function unqueue($type, $oid) } } + /** + * Remove all references to the given spl object ID + * + * @param $oid string + */ public function unregister($oid) { foreach ($this->queue as $operation) { diff --git a/lib/Doctrine/ODM/PHPCR/UnitOfWork.php b/lib/Doctrine/ODM/PHPCR/UnitOfWork.php index 10319bbc8..c3648eaf7 100644 --- a/lib/Doctrine/ODM/PHPCR/UnitOfWork.php +++ b/lib/Doctrine/ODM/PHPCR/UnitOfWork.php @@ -3035,6 +3035,7 @@ private function unregisterDocument($document) } $this->treeOpQueue->unregister($oid); + unset( $this->scheduledUpdates[$oid], $this->scheduledReorders[$oid], diff --git a/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationBatchTest.php b/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationBatchTest.php new file mode 100644 index 000000000..1fad5ce1b --- /dev/null +++ b/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationBatchTest.php @@ -0,0 +1,33 @@ +batch = new TreeOperationBatch(TreeOperation::OP_MOVE); + } + + public function testGetters() + { + $this->assertEquals(TreeOperation::OP_MOVE, $this->batch->getType()); + } + + public function testSchedule() + { + $this->batch->schedule('1234', 'arg'); + $this->batch->schedule('4321', 'arg'); + + $this->assertEquals(array( + '1234' => 'arg', + '4321' => 'arg', + ), $this->batch->getSchedule()); + } +} + diff --git a/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationQueueTest.php b/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationQueueTest.php new file mode 100644 index 000000000..39864cfbb --- /dev/null +++ b/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationQueueTest.php @@ -0,0 +1,132 @@ +queue = new TreeOperationQueue(); + } + + public function provideGetBatches() + { + return array( + array( + array( + TreeOperation::OP_MOVE, + TreeOperation::OP_INSERT, + TreeOperation::OP_REMOVE, + ), + 3 + ), + array( + array( + TreeOperation::OP_REMOVE, + ), + 1 + ), + array( + array( + TreeOperation::OP_REMOVE, + TreeOperation::OP_REMOVE, + TreeOperation::OP_INSERT, + TreeOperation::OP_MOVE, + TreeOperation::OP_REMOVE, + ), + 4 + ) + ); + } + + /** + * @dataProvider provideGetBatches + */ + public function testGetBatches($operations, $expectedNbBatches) + { + foreach ($operations as $operation) { + $this->queue->push(new TreeOperation($operation, '1234', 'arg')); + } + + $batches = $this->queue->getBatches(); + + $this->assertCount($expectedNbBatches, $batches); + } + + public function provideSchedule() + { + return array( + array( + array( + array( + TreeOperation::OP_MOVE, + 1, + 'arg1', + true + ), + array( + TreeOperation::OP_MOVE, + 2, + 'arg2', + false + ), + array( + TreeOperation::OP_MOVE, + 3, + 'arg3', + true + ), + ), + TreeOperation::OP_MOVE, + array( + '1' => 'arg1', + '3' => 'arg3', + ), + ) + ); + } + + /** + * @dataProvider provideSchedule + */ + public function testSchedule($operations, $targetType, $expectedSchedule) + { + foreach ($operations as $operation) { + $treeOperation = new TreeOperation($operation[0], $operation[1], $operation[2]); + if (!$operation[3]) { + $treeOperation->invalidate(); + } + + $this->queue->push($treeOperation); + } + + $this->assertEquals($expectedSchedule, $this->queue->getSchedule($targetType)); + } + + public function testIsQueued() + { + $this->queue->push(new TreeOperation(TreeOperation::OP_MOVE, '1234', 'arg')); + $this->assertTrue($this->queue->isQueued(TreeOperation::OP_MOVE, '1234')); + $this->assertFalse($this->queue->isQueued(TreeOperation::OP_MOVE, '4321')); + $this->assertFalse($this->queue->isQueued(TreeOperation::OP_INSERT, '1234')); + } + + public function testUnqueue() + { + $this->queue->push(new TreeOperation(TreeOperation::OP_MOVE, '1234', 'arg')); + $this->queue->unqueue(TreeOperation::OP_MOVE, '1234'); + $this->assertFalse($this->queue->isQueued(TreeOperation::OP_MOVE, '1234')); + } + + public function testUnregister() + { + $this->queue->push(new TreeOperation(TreeOperation::OP_MOVE, '1234', 'arg')); + $this->queue->unregister('1234'); + $this->assertFalse($this->queue->isQueued(TreeOperation::OP_MOVE, '1234')); + } +} diff --git a/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationTest.php b/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationTest.php new file mode 100644 index 000000000..133ee9956 --- /dev/null +++ b/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationTest.php @@ -0,0 +1,29 @@ +treeOperation = new TreeOperation(TreeOperation::OP_MOVE, '1234', 'arg'); + } + + public function testGetters() + { + $this->assertEquals('1234', $this->treeOperation->getOid()); + $this->assertEquals('arg', $this->treeOperation->getArgs()); + $this->assertEquals(TreeOperation::OP_MOVE, $this->treeOperation->getType()); + } + + public function testInvalidate() + { + $this->assertTrue($this->treeOperation->isValid()); + $this->treeOperation->invalidate(); + $this->assertFalse($this->treeOperation->isValid()); + } +} From 72a315c3dd968a2b715f70b36052880eb25023fb Mon Sep 17 00:00:00 2001 From: dantleech Date: Wed, 25 Mar 2015 11:39:22 +0000 Subject: [PATCH 3/4] Queue wasn't filtering --- lib/Doctrine/ODM/PHPCR/.DocumentManager.php.swl | Bin 0 -> 16384 bytes .../ODM/PHPCR/Queue/TreeOperationQueue.php | 4 ++++ 2 files changed, 4 insertions(+) create mode 100644 lib/Doctrine/ODM/PHPCR/.DocumentManager.php.swl diff --git a/lib/Doctrine/ODM/PHPCR/.DocumentManager.php.swl b/lib/Doctrine/ODM/PHPCR/.DocumentManager.php.swl new file mode 100644 index 0000000000000000000000000000000000000000..b4e58930dc989a0567d2acc5abd07c404b494012 GIT binary patch literal 16384 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 ztejgetType()) { + continue; + } + $schedule[$operation->getOid()] = $operation->getArgs(); } From e084d22718fbb52e636c829836d5451136ab52f7 Mon Sep 17 00:00:00 2001 From: dantleech Date: Wed, 25 Mar 2015 11:45:08 +0000 Subject: [PATCH 4/4] Fixed test --- .../Tests/ODM/PHPCR/Queue/TreeOperationQueueTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationQueueTest.php b/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationQueueTest.php index 39864cfbb..90f1714c6 100644 --- a/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationQueueTest.php +++ b/tests/Doctrine/Tests/ODM/PHPCR/Queue/TreeOperationQueueTest.php @@ -75,6 +75,12 @@ public function provideSchedule() 'arg2', false ), + array( + TreeOperation::OP_REMOVE, + 6, + 'arg3', + true + ), array( TreeOperation::OP_MOVE, 3,