From bdb08b092ec1a9f2f733ace2aec2b880b18a7879 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Wed, 5 Aug 2015 16:29:10 +0100 Subject: [PATCH 01/31] Initial sketch for #87 --- src/IDriver.php | 136 ++++++++++++++++++++++++-- src/IEventHook.php | 42 ++++++++ src/mongo/Driver.class.php | 20 ++++ src/mongo/base/DriverBase.class.php | 29 ++++++ src/mongo/delegates/Updates.class.php | 14 +++ 5 files changed, 234 insertions(+), 7 deletions(-) create mode 100644 src/IEventHook.php diff --git a/src/IDriver.php b/src/IDriver.php index 70d547a2..cf283574 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -8,8 +8,6 @@ */ interface IDriver { - // graph functions - public function graph($query,$includeProperties=array()); /** @@ -19,33 +17,157 @@ public function graph($query,$includeProperties=array()); * @return mixed */ public function describe($query); + + /** + * Return (DESCRIBE) the concise bound description of a resource + * @param $resource string uri resource you'd like to describe + * @param null $context string uri of the context, or named graph, you'd like to describe from + * @return ExtendedGraph + */ public function describeResource($resource,$context=null); + + /** + * Return (DESCRIBE) the concise bound descriptions of a bunch of resources + * @param array $resources uris of resources you'd like to describe + * @param null $context string uri of the context, or named graph, you'd like to describe from + * @return ExtendedGraph + */ public function describeResources(Array $resources,$context=null); + /** + * Get a view of a given type for a given resource + * @param $resource string uri of the resource you'd like the view for + * @param $viewType string type of view + * @return ExtendedGraph + */ public function getViewForResource($resource,$viewType); + + /** + * Get views for multiple resources in one graph + * @param array $resources uris of resources you'd like to describe + * @param $viewType string type of view + * @return ExtendedGraph + */ public function getViewForResources(Array $resources,$viewType); + + /** + * Get views based on a pattern-match $filter + * @param array $filter pattern to match to select views + * @param $viewType string type of view + * @return ExtendedGraph + */ public function getViews(Array $filter,$viewType); + /** + * Returns the etag of a resource, useful for caching + */ public function getETag($resource,$context=null); - // tabular functions - - public function select($query,$fields,$sortBy=null,$limit=null,$context=null); + /** + * Select data in a tabular format + * @param array $filter pattern to match to select views + * @param $fields + * @param null $sortBy + * @param null $limit + * @param null $context + * @return array + */ + public function select($filter,$fields,$sortBy=null,$limit=null,$context=null); + /** + * Select data from a table + * @param $tableType + * @param array $filter + * @param array $sortBy + * @param int $offset + * @param int $limit + * @return mixed + */ public function getTableRows($tableType,$filter=array(),$sortBy=array(),$offset=0,$limit=10); - public function generateTableRows($tableType,$resource=null,$context=null); + /** + * todo: work out what this does + * @param $tableType + * @param $fieldName + * @param array $filter + * @return mixed + */ public function getDistinctTableColumnValues($tableType, $fieldName, array $filter = array()); - // aggregate, save and search functions + /** + * Get a count of resources matching the pattern in $query. Optionally group counts by specifying a $groupBy predicate + * @param $query + * @param null $groupBy + * @return mixed + */ public function getCount($query,$groupBy=null); + /** + * Save the changes between $oldGraph -> $newGraph + * @param ExtendedGraph $oldGraph + * @param ExtendedGraph $newGraph + * @param null $context + * @param null $description + * @return mixed + */ public function saveChanges(ExtendedGraph $oldGraph, ExtendedGraph $newGraph,$context=null,$description=null); + /** + * Register an event hook, which + * @param $eventType + * @param IEventHook $ + * @return mixed + */ + public function registerHook($eventType,IEventHook $hook); + + /** + * Generates table rows + * @deprecated calling save will generate table rows - this method seems to be only used in tests and does not belong on the interface + * @param $tableType + * @param null $resource + * @param null $context + * @return mixed + */ + public function generateTableRows($tableType,$resource=null,$context=null); + + /** + * Submits search params to configured search provider + * the params array must contain the following keys + * -q the query string to search for + * -type the search document type to restrict results to, in other words _id.type + * -indices an array of indices (from spec) to match query terms against, must specify at least one + * -fields an array of the fields (from spec) you want included in the search results, must specify at least one + * -limit integer the number of results to return per page + * -offset the offset to skip to when returning results + * + * this method looks for the above keys in the params array and naively passes them to the search provider which will + * throw SearchException if any of the params are invalid + * + * @deprecated Search will be removed from a future version of Tripod as its functionality is equivalent to tables + * @param Array $params + * @throws \Tripod\Exceptions\Exception - if search provider cannot be found + * @throws \Tripod\Exceptions\SearchException - if something goes wrong + * @return Array results + */ public function search(Array $params); + /** + * Get any documents that were left in a locked state + * @deprecated this is a feature of the mongo implementation - this method will move from the interface to the mongo-specific Driver class soon. + * @param null $fromDateTime + * @param null $tillDateTime + * @return mixed + */ public function getLockedDocuments($fromDateTime =null , $tillDateTime = null); + /** + * Remove any inert locks left by a given transaction + * @deprecated this is a feature of the mongo implementation - this method will move from the interface to the mongo-specific Driver class soon. + * @param $transaction_id + * @param $reason + * @return mixed + */ public function removeInertLocks($transaction_id, $reason); + } \ No newline at end of file diff --git a/src/IEventHook.php b/src/IEventHook.php new file mode 100644 index 00000000..2c9f7b2a --- /dev/null +++ b/src/IEventHook.php @@ -0,0 +1,42 @@ +getDataUpdater()->replayTransactionLog($fromDate, $toDate); } + /** + * Register an event hook, which + * @param $eventType + * @param IEventHook $ + * @return mixed + */ + public function registerHook($eventType, IEventHook $hook) + { + switch ($eventType) { + case IEventHook::EVENT_SAVE_CHANGES: + $this->getDataUpdater()->registerSaveChangesEventHook($hook); + default: + throw new Exception("Unrecognised type $eventType whilst registering event hook"); + } + } + + /** * For mocking * @return Config diff --git a/src/mongo/base/DriverBase.class.php b/src/mongo/base/DriverBase.class.php index 9a4d6cd1..195cf636 100644 --- a/src/mongo/base/DriverBase.class.php +++ b/src/mongo/base/DriverBase.class.php @@ -7,6 +7,8 @@ $TOTAL_TIME=0; use Monolog\Logger; +use Tripod\Exceptions\Exception; +use Tripod\IEventHook; /** * Class DriverBase @@ -376,6 +378,33 @@ protected function getCollection() return $this->collection; } + protected function applyPreHooks($hooks,$args=array()) + { + $this->applyHooks("pre",$hooks,$args); + } + + protected function applyPostHooks($hooks,$args=array()) + { + $this->applyHooks("post",$hooks,$args); + } + + private function applyHooks($fn,$hooks,$args=array()) + { + foreach ($hooks as $hook) + { + try + { + /* @var $hook IEventHook */ + $hook->$fn($args); + } + catch (\Exception $e) + { + // don't let rabbid hooks stop tripod + $this->getLogger()->error("Hook ".get_class($hook)." threw exception {$e->getMessage()}, continuing"); + } + } + } + } /** diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index b70df06d..3329c1bf 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -2,6 +2,8 @@ namespace Tripod\Mongo; +use Tripod\IEventHook; + require_once TRIPOD_DIR . 'mongo/Config.class.php'; /** @@ -68,6 +70,11 @@ class Updates extends DriverBase { */ protected $discoverImpactedSubjects; + /** + * @var array + */ + private $saveChangesHooks = array(); + /** * @param Driver $tripod * @param array $opts @@ -144,6 +151,7 @@ public function saveChanges( $context=null, $description=null) { + $this->applyPreHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); $this->setReadPreferenceToPrimary(); try{ $contextAlias = $this->getContextAlias($context); @@ -180,6 +188,7 @@ public function saveChanges( $this->resetOriginalReadPreference(); + $this->applyPostHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); return true; } @@ -1296,6 +1305,11 @@ protected function getLocksCollection() } + protected function registerSaveChangesEventHook(IEventHook $hook) + { + $this->saveChangesHooks[] = $hook; + } + /** * @return array */ From 7b1b95b194124359151236dbc23e21178dccd602 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Wed, 5 Aug 2015 21:31:51 +0100 Subject: [PATCH 02/31] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6b99f08f..c7cee24e 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "semsol/arc2": "v2.2.4", "chrisboulton/php-resque": "dev-master#98fde571db008a8b48e73022599d1d1c07d4a7b5", - "monolog/monolog" : "1.13.1" + "monolog/monolog" : "~1.13" }, "require-dev": { "phpunit/phpunit": "4.1.*" From 3e048971d3c0563c6bb2de98c3c4550e611a011f Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 5 Aug 2015 22:16:48 +0100 Subject: [PATCH 03/31] Chaning post save hook args --- src/mongo/delegates/Updates.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 3329c1bf..9727dd3c 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -153,6 +153,7 @@ public function saveChanges( { $this->applyPreHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); $this->setReadPreferenceToPrimary(); + $subjectsAndPredicatesOfChange = array(); try{ $contextAlias = $this->getContextAlias($context); @@ -188,7 +189,7 @@ public function saveChanges( $this->resetOriginalReadPreference(); - $this->applyPostHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); + $this->applyPostHooks($this->saveChangesHooks,array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange)); return true; } From ae2abb1261c591916a6ddafd7729687cd4728b60 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 5 Aug 2015 22:29:53 +0100 Subject: [PATCH 04/31] Add include, fix public --- src/mongo/delegates/Updates.class.php | 15 +++++++++------ src/tripod.inc.php | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 9727dd3c..edc1b81d 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -1214,7 +1214,15 @@ public function setTransactionLog(TransactionLog $transactionLog) $this->transactionLog = $transactionLog; } - + /** + * Register save changes event hooks + * @param IEventHook $hook + */ + public function registerSaveChangesEventHook(IEventHook $hook) + { + $this->saveChangesHooks[] = $hook; + } + /** * Saves a transaction * @param array $transaction @@ -1306,11 +1314,6 @@ protected function getLocksCollection() } - protected function registerSaveChangesEventHook(IEventHook $hook) - { - $this->saveChangesHooks[] = $hook; - } - /** * @return array */ diff --git a/src/tripod.inc.php b/src/tripod.inc.php index a63e7b12..6c374dd8 100644 --- a/src/tripod.inc.php +++ b/src/tripod.inc.php @@ -23,6 +23,7 @@ require_once TRIPOD_DIR . 'mongo/delegates/Views.class.php'; require_once TRIPOD_DIR . 'mongo/delegates/Tables.class.php'; require_once TRIPOD_DIR . 'mongo/delegates/SearchIndexer.class.php'; +require_once TRIPOD_DIR . 'IEventHook.php'; require_once TRIPOD_DIR . 'IDriver.php'; require_once TRIPOD_DIR.'classes/ChangeSet.class.php'; require_once TRIPOD_DIR.'classes/Labeller.class.php'; From 4eba15f9e5b4dd5a84aa95e65d389785d1df2a39 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 5 Aug 2015 22:32:33 +0100 Subject: [PATCH 05/31] Missing break --- src/mongo/Driver.class.php | 1 + src/mongo/delegates/Updates.class.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mongo/Driver.class.php b/src/mongo/Driver.class.php index 7c3927dc..6f39ec7d 100755 --- a/src/mongo/Driver.class.php +++ b/src/mongo/Driver.class.php @@ -612,6 +612,7 @@ public function registerHook($eventType, IEventHook $hook) switch ($eventType) { case IEventHook::EVENT_SAVE_CHANGES: $this->getDataUpdater()->registerSaveChangesEventHook($hook); + break; default: throw new Exception("Unrecognised type $eventType whilst registering event hook"); } diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index edc1b81d..b84b5fa5 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -1222,7 +1222,7 @@ public function registerSaveChangesEventHook(IEventHook $hook) { $this->saveChangesHooks[] = $hook; } - + /** * Saves a transaction * @param array $transaction From 040b64e4bd01365962c2067af718efdf4a94defd Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Thu, 6 Aug 2015 18:28:39 +0100 Subject: [PATCH 06/31] Adding more args to post commit hook --- src/mongo/delegates/Updates.class.php | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index b84b5fa5..8fd4e68b 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -153,7 +153,6 @@ public function saveChanges( { $this->applyPreHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); $this->setReadPreferenceToPrimary(); - $subjectsAndPredicatesOfChange = array(); try{ $contextAlias = $this->getContextAlias($context); @@ -169,6 +168,7 @@ public function saveChanges( $args = array('before' => $oldIndex, 'after' => $newIndex, 'changeReason' => $description); $cs = new \Tripod\ChangeSet($args); + $subjectsAndPredicatesOfChange = array(); if ($cs->has_changes()) { // store the actual CBDs @@ -180,6 +180,12 @@ public function saveChanges( // Schedule calculation of any async activity $this->queueAsyncOperations($subjectsAndPredicatesOfChange,$contextAlias); } + + $this->applyPostHooks($this->saveChangesHooks,array( + "pod"=>$this->getPodName(), + "changeSet"=>$cs, + "subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange + )); } catch(\Exception $e){ // ensure we reset the original read preference in the event of an exception @@ -189,7 +195,6 @@ public function saveChanges( $this->resetOriginalReadPreference(); - $this->applyPostHooks($this->saveChangesHooks,array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange)); return true; } @@ -1066,12 +1071,12 @@ protected function lockSingleDocument($s, $transaction_id, $contextAlias) { $countEntriesInLocksCollection = $this->getLocksCollection() ->count( - array( - _ID_KEY => array( - _ID_RESOURCE => $this->labeller->uri_to_alias($s), - _ID_CONTEXT => $contextAlias) - ) - ); + array( + _ID_KEY => array( + _ID_RESOURCE => $this->labeller->uri_to_alias($s), + _ID_CONTEXT => $contextAlias) + ) + ); if($countEntriesInLocksCollection > 0) //Subject is already locked return false; From 5e886f829e97542d42284aacca3b2b5ef0a536e1 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 11 Aug 2015 17:10:31 +0100 Subject: [PATCH 07/31] Fixes #91 --- src/mongo/providers/MongoSearchProvider.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mongo/providers/MongoSearchProvider.class.php b/src/mongo/providers/MongoSearchProvider.class.php index 614f0a8d..68680bcb 100644 --- a/src/mongo/providers/MongoSearchProvider.class.php +++ b/src/mongo/providers/MongoSearchProvider.class.php @@ -106,7 +106,7 @@ public function deleteDocument($resource, $context, $specId = array()) { return; } - $query[_ID_KEY . '.' . _ID_TYPE] = array('$in'=>$specId); + $query[_ID_KEY . '.' . _ID_TYPE] = array('$in'=>array_values($specId)); $searchTypes = $specId; } } From 7290bc53023f119d0b2fa40d4dd5f00bb33bd51e Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 11 Aug 2015 17:11:27 +0100 Subject: [PATCH 08/31] Fixes #90 --- src/mongo/delegates/Tables.class.php | 21 +++++++++++++-------- test/unit/mongo/MongoTripodTablesTest.php | 4 ++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/mongo/delegates/Tables.class.php b/src/mongo/delegates/Tables.class.php index 99b55ddf..50371571 100644 --- a/src/mongo/delegates/Tables.class.php +++ b/src/mongo/delegates/Tables.class.php @@ -252,6 +252,8 @@ public function getTableRows($tableSpecId,$filter=array(),$sortBy=array(),$offse $rows = array(); foreach ($results as $doc) { +// $log = new \Monolog\Logger("TEST"); +// $log->error("Doc",$doc); if (array_key_exists(_IMPACT_INDEX,$doc['value'])) unset($doc['value'][_IMPACT_INDEX]); // remove impact index from client $rows[] = $doc['value']; } @@ -509,16 +511,19 @@ public function generateTableRows($tableType,$resource=null,$context=null,$queue ); // ensure any custom view indexes - if (isset($tableSpec['ensureIndexes'])) + foreach (Config::getInstance()->getTableSpecifications($this->storeName) as $tSpec) { - foreach ($tableSpec['ensureIndexes'] as $ensureIndex) + if (isset($tSpec['ensureIndexes'])) { - $collection->ensureIndex( - $ensureIndex, - array( - 'background'=>1 - ) - ); + foreach ($tSpec['ensureIndexes'] as $ensureIndex) + { + $collection->ensureIndex( + $ensureIndex, + array( + 'background'=>1 + ) + ); + } } } diff --git a/test/unit/mongo/MongoTripodTablesTest.php b/test/unit/mongo/MongoTripodTablesTest.php index 4f2abeb4..eba9d701 100644 --- a/test/unit/mongo/MongoTripodTablesTest.php +++ b/test/unit/mongo/MongoTripodTablesTest.php @@ -178,7 +178,7 @@ public function testGenerateTableRowsWithCountUpdateAndRequery() $this->assertEquals(count($t2['results']),2); foreach ($t2['results'] as $r) { - if ($r['_id']['r'] = $subject) { + if ($r['_id']['r'] == $subject) { $result = $r; } } @@ -224,7 +224,7 @@ public function testGenerateTableRowsWithCountAndRegexUpdateAndRequery() $this->assertEquals(count($t2['results']),2); foreach ($t2['results'] as $r) { - if ($r['_id']['r'] = $subject) { + if ($r['_id']['r'] == $subject) { $result = $r; } } From 01d52ef688fa9f73ef3548138270319c098d897d Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 11 Aug 2015 17:31:19 +0100 Subject: [PATCH 09/31] Adding tests for event hooks --- src/mongo/delegates/Updates.class.php | 12 +++- test/unit/mongo/MongoTripodDriverTest.php | 80 ++++++++++++++++++++++- 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 8fd4e68b..3dc35a23 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -151,7 +151,12 @@ public function saveChanges( $context=null, $description=null) { - $this->applyPreHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); + $this->applyPreHooks($this->saveChangesHooks,array( + "pod"=>$this->getPodName(), + "oldGraph"=>$oldGraph, + "newGraph"=>$newGraph, + "context"=>$context + )); $this->setReadPreferenceToPrimary(); try{ $contextAlias = $this->getContextAlias($context); @@ -183,8 +188,11 @@ public function saveChanges( $this->applyPostHooks($this->saveChangesHooks,array( "pod"=>$this->getPodName(), + "oldGraph"=>$oldGraph, + "newGraph"=>$newGraph, + "context"=>$context, "changeSet"=>$cs, - "subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange + "subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange, )); } catch(\Exception $e){ diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index 9ea1ebf0..7c69c738 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -26,7 +26,7 @@ protected function setUp() // Stub ouf 'addToElastic' search to prevent writes into Elastic Search happening by default. $this->tripod = $this->getMock( '\Tripod\Mongo\Driver', - array('addToSearchIndexQueue'), + array('validateGraphCardinality'), array( 'CBD_testing', 'tripod_php_testing', @@ -1975,6 +1975,82 @@ public function testRemoveInertLocks() $this->assertEquals(0, count($docs)); } - /** END: removeInertLocks tests */ + + /** START: saveChangesHooks tests */ + public function testRegisteredHooksAreCalled() + { + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post'), array(), '', false); + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post'), array(), '', false); + + $mockHookA->expects($this->once())->method("pre"); + $mockHookA->expects($this->once())->method("post"); + $mockHookB->expects($this->once())->method("pre"); + $mockHookB->expects($this->once())->method("post"); + + $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookA); + $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookB); + + $this->tripod->saveChanges(new \Tripod\ExtendedGraph(),new \Tripod\ExtendedGraph()); + } + + public function testRegisteredPostHooksAreNotCalledOnException() + { + $this->setExpectedException('\Tripod\Exceptions\Exception','Could not validate'); + + /* @var $tripodUpdate \Tripod\Mongo\Updates|PHPUnit_Framework_MockObject_MockObject */ + $tripodUpdate = $this->getMock( + '\Tripod\Mongo\Updates', + array('validateGraphCardinality'), + array($this->tripod) + ); + + /* @var $mockHookA \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post'), array(), '', false); + /* @var $mockHookB \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post'), array(), '', false); + + $mockHookA->expects($this->once())->method("pre"); + $mockHookA->expects($this->never())->method("post"); + $mockHookB->expects($this->once())->method("pre"); + $mockHookB->expects($this->never())->method("post"); + + $tripodUpdate->registerSaveChangesEventHook($mockHookA); + $tripodUpdate->registerSaveChangesEventHook($mockHookB); + + $tripodUpdate->expects($this->once())->method('validateGraphCardinality')->willThrowException(new \Tripod\Exceptions\Exception("Could not validate")); + $tripodUpdate->saveChanges(new \Tripod\ExtendedGraph(),new \Tripod\ExtendedGraph()); + } + + /** END: saveChangesHooks tests */ + } +class TestSaveChangesHookA implements \Tripod\IEventHook +{ + /** + * This method gets called just before the event happens. The arguments passed depend on the event in question, see + * the documentation for that event type for details + * @param $args array of arguments + */ + public function pre(array $args) + { + // do nothing + } + + /** + * This method gets called after the event has successfully completed. The arguments passed depend on the event in + * question, see the documentation for that event type for details + * If the event throws an exception or fatal error, this method will not be called. + * @param $args array of arguments + */ + public function post(array $args) + { + // do nothing + } + +} + +class TestSaveChangesHookB extends TestSaveChangesHookA +{ + // empty +} \ No newline at end of file From 8d46cf07f3b7cdb7fc6733d12ef8fbcd56311682 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 11 Aug 2015 17:38:16 +0100 Subject: [PATCH 10/31] Adding failure condition --- src/IEventHook.php | 7 +++++++ src/mongo/base/DriverBase.class.php | 5 +++++ src/mongo/delegates/Updates.class.php | 6 ++++++ test/unit/mongo/MongoTripodDriverTest.php | 17 +++++++++++++++-- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/IEventHook.php b/src/IEventHook.php index 2c9f7b2a..b8b71274 100644 --- a/src/IEventHook.php +++ b/src/IEventHook.php @@ -39,4 +39,11 @@ public function pre(array $args); * @param $args array of arguments */ public function post(array $args); + + /** + * This method gets called if the event failed for any reason. The arguments passed should be the same as IEventHook::pre + * @param array $args + * @return mixed + */ + public function failure(array $args); } \ No newline at end of file diff --git a/src/mongo/base/DriverBase.class.php b/src/mongo/base/DriverBase.class.php index 195cf636..f4a9f665 100644 --- a/src/mongo/base/DriverBase.class.php +++ b/src/mongo/base/DriverBase.class.php @@ -388,6 +388,11 @@ protected function applyPostHooks($hooks,$args=array()) $this->applyHooks("post",$hooks,$args); } + protected function applyFailureHooks($hooks,$args=array()) + { + $this->applyHooks("failure",$hooks,$args); + } + private function applyHooks($fn,$hooks,$args=array()) { foreach ($hooks as $hook) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 3dc35a23..8a82e6bb 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -198,6 +198,12 @@ public function saveChanges( catch(\Exception $e){ // ensure we reset the original read preference in the event of an exception $this->resetOriginalReadPreference(); + $this->applyFailureHooks($this->saveChangesHooks,array( + "pod"=>$this->getPodName(), + "oldGraph"=>$oldGraph, + "newGraph"=>$newGraph, + "context"=>$context + )); throw $e; } diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index 7c69c738..6bfa65ad 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -1985,8 +1985,10 @@ public function testRegisteredHooksAreCalled() $mockHookA->expects($this->once())->method("pre"); $mockHookA->expects($this->once())->method("post"); + $mockHookA->expects($this->never())->method("failure"); $mockHookB->expects($this->once())->method("pre"); $mockHookB->expects($this->once())->method("post"); + $mockHookB->expects($this->never())->method("failure"); $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookA); $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookB); @@ -2006,14 +2008,16 @@ public function testRegisteredPostHooksAreNotCalledOnException() ); /* @var $mockHookA \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ - $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post'), array(), '', false); + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post', 'failure'), array(), '', false); /* @var $mockHookB \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ - $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post'), array(), '', false); + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post', 'failure'), array(), '', false); $mockHookA->expects($this->once())->method("pre"); $mockHookA->expects($this->never())->method("post"); + $mockHookA->expects($this->once())->method("failure"); $mockHookB->expects($this->once())->method("pre"); $mockHookB->expects($this->never())->method("post"); + $mockHookB->expects($this->once())->method("failure"); $tripodUpdate->registerSaveChangesEventHook($mockHookA); $tripodUpdate->registerSaveChangesEventHook($mockHookB); @@ -2048,6 +2052,15 @@ public function post(array $args) // do nothing } + /** + * This method gets called if the event failed for any reason. The arguments passed should be the same as IEventHook::pre + * @param array $args + * @return mixed + */ + public function failure(array $args) + { + // do nothing + } } class TestSaveChangesHookB extends TestSaveChangesHookA From 121964a4846fa068270725cbaab627b475d177fd Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Wed, 12 Aug 2015 11:10:06 +0100 Subject: [PATCH 11/31] More elegence for executing hooks --- src/mongo/base/DriverBase.class.php | 32 +++++++++++++-------------- src/mongo/delegates/Updates.class.php | 6 ++--- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/mongo/base/DriverBase.class.php b/src/mongo/base/DriverBase.class.php index f4a9f665..9d82b162 100644 --- a/src/mongo/base/DriverBase.class.php +++ b/src/mongo/base/DriverBase.class.php @@ -16,6 +16,13 @@ */ abstract class DriverBase { + /** + * constants for the supported hook functions that can be applied + */ + const HOOK_FN_PRE = "pre"; + const HOOK_FN_POST = "post"; + const HOOK_FN_FAILURE = "failure"; + /** * @var \MongoCollection */ @@ -378,23 +385,16 @@ protected function getCollection() return $this->collection; } - protected function applyPreHooks($hooks,$args=array()) - { - $this->applyHooks("pre",$hooks,$args); - } - - protected function applyPostHooks($hooks,$args=array()) - { - $this->applyHooks("post",$hooks,$args); - } - - protected function applyFailureHooks($hooks,$args=array()) - { - $this->applyHooks("failure",$hooks,$args); - } - - private function applyHooks($fn,$hooks,$args=array()) + protected function applyHooks($fn,$hooks,$args=array()) { + switch ($fn) { + case $this::HOOK_FN_PRE: + case $this::HOOK_FN_POST: + case $this::HOOK_FN_FAILURE: + break; + default: + throw new Exception("Invalid hook function $fn requested"); + } foreach ($hooks as $hook) { try diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 8a82e6bb..0b11ac0d 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -151,7 +151,7 @@ public function saveChanges( $context=null, $description=null) { - $this->applyPreHooks($this->saveChangesHooks,array( + $this->applyHooks($this::HOOK_FN_PRE,$this->saveChangesHooks,array( "pod"=>$this->getPodName(), "oldGraph"=>$oldGraph, "newGraph"=>$newGraph, @@ -186,7 +186,7 @@ public function saveChanges( $this->queueAsyncOperations($subjectsAndPredicatesOfChange,$contextAlias); } - $this->applyPostHooks($this->saveChangesHooks,array( + $this->applyHooks($this::HOOK_FN_POST,$this->saveChangesHooks,array( "pod"=>$this->getPodName(), "oldGraph"=>$oldGraph, "newGraph"=>$newGraph, @@ -198,7 +198,7 @@ public function saveChanges( catch(\Exception $e){ // ensure we reset the original read preference in the event of an exception $this->resetOriginalReadPreference(); - $this->applyFailureHooks($this->saveChangesHooks,array( + $this->applyHooks($this::HOOK_FN_FAILURE,$this->saveChangesHooks,array( "pod"=>$this->getPodName(), "oldGraph"=>$oldGraph, "newGraph"=>$newGraph, From b0a1758108953d47ff8e606dc50e6832b3017159 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Wed, 12 Aug 2015 11:10:48 +0100 Subject: [PATCH 12/31] Less rabbits --- src/mongo/base/DriverBase.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mongo/base/DriverBase.class.php b/src/mongo/base/DriverBase.class.php index 9d82b162..134d8394 100644 --- a/src/mongo/base/DriverBase.class.php +++ b/src/mongo/base/DriverBase.class.php @@ -404,7 +404,7 @@ protected function applyHooks($fn,$hooks,$args=array()) } catch (\Exception $e) { - // don't let rabbid hooks stop tripod + // don't let rabid hooks stop tripod $this->getLogger()->error("Hook ".get_class($hook)." threw exception {$e->getMessage()}, continuing"); } } From db376ab448ede8a322d3138621c059402a6ecb3c Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Wed, 12 Aug 2015 11:25:38 +0100 Subject: [PATCH 13/31] Improve interface documentation --- src/IDriver.php | 75 ++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/src/IDriver.php b/src/IDriver.php index cf283574..a0b5c32d 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -8,20 +8,18 @@ */ interface IDriver { - public function graph($query,$includeProperties=array()); - /** - * @deprecated - * @abstract - * @param $query + * Equivalent to CONSTRUCT + * @param array $filter conditions to filter by + * @param array $includeProperties only include these predicates, empty array means return all predicates * @return mixed */ - public function describe($query); + public function graph($filter,$includeProperties=array()); /** * Return (DESCRIBE) the concise bound description of a resource - * @param $resource string uri resource you'd like to describe - * @param null $context string uri of the context, or named graph, you'd like to describe from + * @param string $resource uri resource you'd like to describe + * @param null|string $context string uri of the context, or named graph, you'd like to describe from * @return ExtendedGraph */ public function describeResource($resource,$context=null); @@ -29,15 +27,15 @@ public function describeResource($resource,$context=null); /** * Return (DESCRIBE) the concise bound descriptions of a bunch of resources * @param array $resources uris of resources you'd like to describe - * @param null $context string uri of the context, or named graph, you'd like to describe from + * @param null|string $context string uri of the context, or named graph, you'd like to describe from * @return ExtendedGraph */ public function describeResources(Array $resources,$context=null); /** * Get a view of a given type for a given resource - * @param $resource string uri of the resource you'd like the view for - * @param $viewType string type of view + * @param string $resource uri of the resource you'd like the view for + * @param string $viewType string type of view * @return ExtendedGraph */ public function getViewForResource($resource,$viewType); @@ -45,7 +43,7 @@ public function getViewForResource($resource,$viewType); /** * Get views for multiple resources in one graph * @param array $resources uris of resources you'd like to describe - * @param $viewType string type of view + * @param string $viewType type of view * @return ExtendedGraph */ public function getViewForResources(Array $resources,$viewType); @@ -53,13 +51,16 @@ public function getViewForResources(Array $resources,$viewType); /** * Get views based on a pattern-match $filter * @param array $filter pattern to match to select views - * @param $viewType string type of view + * @param string $viewType type of view * @return ExtendedGraph */ public function getViews(Array $filter,$viewType); /** * Returns the etag of a resource, useful for caching + * @param string $resource + * @param null|string $context + * @return string */ public function getETag($resource,$context=null); @@ -81,7 +82,7 @@ public function select($filter,$fields,$sortBy=null,$limit=null,$context=null); * @param array $sortBy * @param int $offset * @param int $limit - * @return mixed + * @return array */ public function getTableRows($tableType,$filter=array(),$sortBy=array(),$offset=0,$limit=10); @@ -90,7 +91,7 @@ public function getTableRows($tableType,$filter=array(),$sortBy=array(),$offset= * @param $tableType * @param $fieldName * @param array $filter - * @return mixed + * @return array */ public function getDistinctTableColumnValues($tableType, $fieldName, array $filter = array()); @@ -98,8 +99,8 @@ public function getDistinctTableColumnValues($tableType, $fieldName, array $filt /** * Get a count of resources matching the pattern in $query. Optionally group counts by specifying a $groupBy predicate * @param $query - * @param null $groupBy - * @return mixed + * @param null|string $groupBy + * @return array|int multidimensional array with int values if grouped by, otherwise int */ public function getCount($query,$groupBy=null); @@ -107,27 +108,35 @@ public function getCount($query,$groupBy=null); * Save the changes between $oldGraph -> $newGraph * @param ExtendedGraph $oldGraph * @param ExtendedGraph $newGraph - * @param null $context - * @param null $description - * @return mixed + * @param null|string $context + * @param null|string $description + * @return bool true or throws exception on error */ public function saveChanges(ExtendedGraph $oldGraph, ExtendedGraph $newGraph,$context=null,$description=null); /** - * Register an event hook, which + * Register an event hook, which will be executed when the event fires. * @param $eventType - * @param IEventHook $ - * @return mixed + * @param IEventHook $hook */ public function registerHook($eventType,IEventHook $hook); + /* START Deprecated methods that will be removed in 1.x.x */ + + /** + * Return (DESCRIBE) according to a filter + * @deprecated Use graph() instead + * @param array $filter conditions to filter by + * @return ExtendedGraph + */ + public function describe($filter); + /** * Generates table rows * @deprecated calling save will generate table rows - this method seems to be only used in tests and does not belong on the interface * @param $tableType - * @param null $resource - * @param null $context - * @return mixed + * @param null|string $resource + * @param null|string $context */ public function generateTableRows($tableType,$resource=null,$context=null); @@ -155,19 +164,21 @@ public function search(Array $params); /** * Get any documents that were left in a locked state * @deprecated this is a feature of the mongo implementation - this method will move from the interface to the mongo-specific Driver class soon. - * @param null $fromDateTime - * @param null $tillDateTime - * @return mixed + * @param null|string $fromDateTime strtotime compatible string + * @param null|string $tillDateTime strtotime compatible string + * @return array of locked documents */ public function getLockedDocuments($fromDateTime =null , $tillDateTime = null); /** * Remove any inert locks left by a given transaction * @deprecated this is a feature of the mongo implementation - this method will move from the interface to the mongo-specific Driver class soon. - * @param $transaction_id - * @param $reason - * @return mixed + * @param string $transaction_id + * @param string $reason + * @return bool true or throws exception on error */ public function removeInertLocks($transaction_id, $reason); + /* END Deprecated methods that will be removed in 1.x.x */ + } \ No newline at end of file From cb9b59d5e3de8f98c14c518bdd4fd16ee800f074 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 18 Aug 2015 10:28:28 +0100 Subject: [PATCH 14/31] Returning transaction_id to hook --- src/mongo/delegates/Updates.class.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 0b11ac0d..fded50a0 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -2,6 +2,7 @@ namespace Tripod\Mongo; +use Tripod\Exceptions\Exception; use Tripod\IEventHook; require_once TRIPOD_DIR . 'mongo/Config.class.php'; @@ -174,10 +175,16 @@ public function saveChanges( $cs = new \Tripod\ChangeSet($args); $subjectsAndPredicatesOfChange = array(); + $transaction_id = null; if ($cs->has_changes()) { // store the actual CBDs - $subjectsAndPredicatesOfChange = $this->storeChanges($cs, $contextAlias); + $result = $this->storeChanges($cs, $contextAlias); + if (!isset($result['subjectsAndPredicatesOfChange'])|| !isset($result['transaction_id'])) { + $this->errorLog("Result of storeChanges malformed, should have transaction_id and subjectsAndPredicatesOfChange array keys",array("result"=>$result)); + throw new Exception("Result of storeChanges malformed, should have transaction_id and subjectsAndPredicatesOfChange array keys"); + } + extract($result); // will unpack into $subjectsAndPredicatesOfChange // Process any syncronous operations $this->processSyncOperations($subjectsAndPredicatesOfChange,$contextAlias); @@ -193,6 +200,7 @@ public function saveChanges( "context"=>$context, "changeSet"=>$cs, "subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange, + "transaction_id"=>$transaction_id )); } catch(\Exception $e){ @@ -366,7 +374,7 @@ protected function storeChanges(\Tripod\ChangeSet $cs, $contextAlias) $this->timingLog(MONGO_WRITE, array('duration'=>$t->result(), 'subjectsOfChange'=>implode(", ",$subjectsOfChange))); $this->getStat()->timer(MONGO_WRITE.".{$this->getPodName()}",$t->result()); - return $changes['subjectsAndPredicatesOfChange']; + return $changes; } catch(\Exception $e) { @@ -625,7 +633,8 @@ protected function applyChangeSet(\Tripod\ChangeSet $cs, $originalCBDs, $context return array( 'newCBDs'=>$newCBDs, - 'subjectsAndPredicatesOfChange'=>$this->subjectsAndPredicatesOfChangeUrisToAliases($subjectsAndPredicatesOfChange) + 'subjectsAndPredicatesOfChange'=>$this->subjectsAndPredicatesOfChangeUrisToAliases($subjectsAndPredicatesOfChange), + 'transaction_id'=>$transaction_id ); } else From afdb74565f2c58f016602e97d91ff3ab816436ab Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Wed, 5 Aug 2015 16:29:10 +0100 Subject: [PATCH 15/31] Initial sketch for #87 --- src/IDriver.php | 136 ++++++++++++++++++++++++-- src/IEventHook.php | 42 ++++++++ src/mongo/Driver.class.php | 20 ++++ src/mongo/base/DriverBase.class.php | 29 ++++++ src/mongo/delegates/Updates.class.php | 14 +++ 5 files changed, 234 insertions(+), 7 deletions(-) create mode 100644 src/IEventHook.php diff --git a/src/IDriver.php b/src/IDriver.php index 70d547a2..cf283574 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -8,8 +8,6 @@ */ interface IDriver { - // graph functions - public function graph($query,$includeProperties=array()); /** @@ -19,33 +17,157 @@ public function graph($query,$includeProperties=array()); * @return mixed */ public function describe($query); + + /** + * Return (DESCRIBE) the concise bound description of a resource + * @param $resource string uri resource you'd like to describe + * @param null $context string uri of the context, or named graph, you'd like to describe from + * @return ExtendedGraph + */ public function describeResource($resource,$context=null); + + /** + * Return (DESCRIBE) the concise bound descriptions of a bunch of resources + * @param array $resources uris of resources you'd like to describe + * @param null $context string uri of the context, or named graph, you'd like to describe from + * @return ExtendedGraph + */ public function describeResources(Array $resources,$context=null); + /** + * Get a view of a given type for a given resource + * @param $resource string uri of the resource you'd like the view for + * @param $viewType string type of view + * @return ExtendedGraph + */ public function getViewForResource($resource,$viewType); + + /** + * Get views for multiple resources in one graph + * @param array $resources uris of resources you'd like to describe + * @param $viewType string type of view + * @return ExtendedGraph + */ public function getViewForResources(Array $resources,$viewType); + + /** + * Get views based on a pattern-match $filter + * @param array $filter pattern to match to select views + * @param $viewType string type of view + * @return ExtendedGraph + */ public function getViews(Array $filter,$viewType); + /** + * Returns the etag of a resource, useful for caching + */ public function getETag($resource,$context=null); - // tabular functions - - public function select($query,$fields,$sortBy=null,$limit=null,$context=null); + /** + * Select data in a tabular format + * @param array $filter pattern to match to select views + * @param $fields + * @param null $sortBy + * @param null $limit + * @param null $context + * @return array + */ + public function select($filter,$fields,$sortBy=null,$limit=null,$context=null); + /** + * Select data from a table + * @param $tableType + * @param array $filter + * @param array $sortBy + * @param int $offset + * @param int $limit + * @return mixed + */ public function getTableRows($tableType,$filter=array(),$sortBy=array(),$offset=0,$limit=10); - public function generateTableRows($tableType,$resource=null,$context=null); + /** + * todo: work out what this does + * @param $tableType + * @param $fieldName + * @param array $filter + * @return mixed + */ public function getDistinctTableColumnValues($tableType, $fieldName, array $filter = array()); - // aggregate, save and search functions + /** + * Get a count of resources matching the pattern in $query. Optionally group counts by specifying a $groupBy predicate + * @param $query + * @param null $groupBy + * @return mixed + */ public function getCount($query,$groupBy=null); + /** + * Save the changes between $oldGraph -> $newGraph + * @param ExtendedGraph $oldGraph + * @param ExtendedGraph $newGraph + * @param null $context + * @param null $description + * @return mixed + */ public function saveChanges(ExtendedGraph $oldGraph, ExtendedGraph $newGraph,$context=null,$description=null); + /** + * Register an event hook, which + * @param $eventType + * @param IEventHook $ + * @return mixed + */ + public function registerHook($eventType,IEventHook $hook); + + /** + * Generates table rows + * @deprecated calling save will generate table rows - this method seems to be only used in tests and does not belong on the interface + * @param $tableType + * @param null $resource + * @param null $context + * @return mixed + */ + public function generateTableRows($tableType,$resource=null,$context=null); + + /** + * Submits search params to configured search provider + * the params array must contain the following keys + * -q the query string to search for + * -type the search document type to restrict results to, in other words _id.type + * -indices an array of indices (from spec) to match query terms against, must specify at least one + * -fields an array of the fields (from spec) you want included in the search results, must specify at least one + * -limit integer the number of results to return per page + * -offset the offset to skip to when returning results + * + * this method looks for the above keys in the params array and naively passes them to the search provider which will + * throw SearchException if any of the params are invalid + * + * @deprecated Search will be removed from a future version of Tripod as its functionality is equivalent to tables + * @param Array $params + * @throws \Tripod\Exceptions\Exception - if search provider cannot be found + * @throws \Tripod\Exceptions\SearchException - if something goes wrong + * @return Array results + */ public function search(Array $params); + /** + * Get any documents that were left in a locked state + * @deprecated this is a feature of the mongo implementation - this method will move from the interface to the mongo-specific Driver class soon. + * @param null $fromDateTime + * @param null $tillDateTime + * @return mixed + */ public function getLockedDocuments($fromDateTime =null , $tillDateTime = null); + /** + * Remove any inert locks left by a given transaction + * @deprecated this is a feature of the mongo implementation - this method will move from the interface to the mongo-specific Driver class soon. + * @param $transaction_id + * @param $reason + * @return mixed + */ public function removeInertLocks($transaction_id, $reason); + } \ No newline at end of file diff --git a/src/IEventHook.php b/src/IEventHook.php new file mode 100644 index 00000000..2c9f7b2a --- /dev/null +++ b/src/IEventHook.php @@ -0,0 +1,42 @@ +getDataUpdater()->replayTransactionLog($fromDate, $toDate); } + /** + * Register an event hook, which + * @param $eventType + * @param IEventHook $ + * @return mixed + */ + public function registerHook($eventType, IEventHook $hook) + { + switch ($eventType) { + case IEventHook::EVENT_SAVE_CHANGES: + $this->getDataUpdater()->registerSaveChangesEventHook($hook); + default: + throw new Exception("Unrecognised type $eventType whilst registering event hook"); + } + } + + /** * For mocking * @return Config diff --git a/src/mongo/base/DriverBase.class.php b/src/mongo/base/DriverBase.class.php index 9a4d6cd1..195cf636 100644 --- a/src/mongo/base/DriverBase.class.php +++ b/src/mongo/base/DriverBase.class.php @@ -7,6 +7,8 @@ $TOTAL_TIME=0; use Monolog\Logger; +use Tripod\Exceptions\Exception; +use Tripod\IEventHook; /** * Class DriverBase @@ -376,6 +378,33 @@ protected function getCollection() return $this->collection; } + protected function applyPreHooks($hooks,$args=array()) + { + $this->applyHooks("pre",$hooks,$args); + } + + protected function applyPostHooks($hooks,$args=array()) + { + $this->applyHooks("post",$hooks,$args); + } + + private function applyHooks($fn,$hooks,$args=array()) + { + foreach ($hooks as $hook) + { + try + { + /* @var $hook IEventHook */ + $hook->$fn($args); + } + catch (\Exception $e) + { + // don't let rabbid hooks stop tripod + $this->getLogger()->error("Hook ".get_class($hook)." threw exception {$e->getMessage()}, continuing"); + } + } + } + } /** diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index b70df06d..3329c1bf 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -2,6 +2,8 @@ namespace Tripod\Mongo; +use Tripod\IEventHook; + require_once TRIPOD_DIR . 'mongo/Config.class.php'; /** @@ -68,6 +70,11 @@ class Updates extends DriverBase { */ protected $discoverImpactedSubjects; + /** + * @var array + */ + private $saveChangesHooks = array(); + /** * @param Driver $tripod * @param array $opts @@ -144,6 +151,7 @@ public function saveChanges( $context=null, $description=null) { + $this->applyPreHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); $this->setReadPreferenceToPrimary(); try{ $contextAlias = $this->getContextAlias($context); @@ -180,6 +188,7 @@ public function saveChanges( $this->resetOriginalReadPreference(); + $this->applyPostHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); return true; } @@ -1296,6 +1305,11 @@ protected function getLocksCollection() } + protected function registerSaveChangesEventHook(IEventHook $hook) + { + $this->saveChangesHooks[] = $hook; + } + /** * @return array */ From 06b5f5d4dbc44c04c16faf88e0f4bcdba1678511 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Wed, 5 Aug 2015 21:31:51 +0100 Subject: [PATCH 16/31] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6b99f08f..c7cee24e 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "semsol/arc2": "v2.2.4", "chrisboulton/php-resque": "dev-master#98fde571db008a8b48e73022599d1d1c07d4a7b5", - "monolog/monolog" : "1.13.1" + "monolog/monolog" : "~1.13" }, "require-dev": { "phpunit/phpunit": "4.1.*" From 85247e484fc3a39f9a3c714e298fa66be65513d9 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 5 Aug 2015 22:16:48 +0100 Subject: [PATCH 17/31] Chaning post save hook args --- src/mongo/delegates/Updates.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 3329c1bf..9727dd3c 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -153,6 +153,7 @@ public function saveChanges( { $this->applyPreHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); $this->setReadPreferenceToPrimary(); + $subjectsAndPredicatesOfChange = array(); try{ $contextAlias = $this->getContextAlias($context); @@ -188,7 +189,7 @@ public function saveChanges( $this->resetOriginalReadPreference(); - $this->applyPostHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); + $this->applyPostHooks($this->saveChangesHooks,array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange)); return true; } From 0be10fbaef9dc3bbc33832cd763bb2f7add4f8aa Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 5 Aug 2015 22:29:53 +0100 Subject: [PATCH 18/31] Add include, fix public --- src/mongo/delegates/Updates.class.php | 15 +++++++++------ src/tripod.inc.php | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 9727dd3c..edc1b81d 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -1214,7 +1214,15 @@ public function setTransactionLog(TransactionLog $transactionLog) $this->transactionLog = $transactionLog; } - + /** + * Register save changes event hooks + * @param IEventHook $hook + */ + public function registerSaveChangesEventHook(IEventHook $hook) + { + $this->saveChangesHooks[] = $hook; + } + /** * Saves a transaction * @param array $transaction @@ -1306,11 +1314,6 @@ protected function getLocksCollection() } - protected function registerSaveChangesEventHook(IEventHook $hook) - { - $this->saveChangesHooks[] = $hook; - } - /** * @return array */ diff --git a/src/tripod.inc.php b/src/tripod.inc.php index a63e7b12..6c374dd8 100644 --- a/src/tripod.inc.php +++ b/src/tripod.inc.php @@ -23,6 +23,7 @@ require_once TRIPOD_DIR . 'mongo/delegates/Views.class.php'; require_once TRIPOD_DIR . 'mongo/delegates/Tables.class.php'; require_once TRIPOD_DIR . 'mongo/delegates/SearchIndexer.class.php'; +require_once TRIPOD_DIR . 'IEventHook.php'; require_once TRIPOD_DIR . 'IDriver.php'; require_once TRIPOD_DIR.'classes/ChangeSet.class.php'; require_once TRIPOD_DIR.'classes/Labeller.class.php'; From 470e14b2816642aa7ed01e529931cf1a0acf738f Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 5 Aug 2015 22:32:33 +0100 Subject: [PATCH 19/31] Missing break --- src/mongo/Driver.class.php | 1 + src/mongo/delegates/Updates.class.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mongo/Driver.class.php b/src/mongo/Driver.class.php index 7c3927dc..6f39ec7d 100755 --- a/src/mongo/Driver.class.php +++ b/src/mongo/Driver.class.php @@ -612,6 +612,7 @@ public function registerHook($eventType, IEventHook $hook) switch ($eventType) { case IEventHook::EVENT_SAVE_CHANGES: $this->getDataUpdater()->registerSaveChangesEventHook($hook); + break; default: throw new Exception("Unrecognised type $eventType whilst registering event hook"); } diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index edc1b81d..b84b5fa5 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -1222,7 +1222,7 @@ public function registerSaveChangesEventHook(IEventHook $hook) { $this->saveChangesHooks[] = $hook; } - + /** * Saves a transaction * @param array $transaction From 504816ee41124cc402262a420200ae01bfa00102 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Thu, 6 Aug 2015 18:28:39 +0100 Subject: [PATCH 20/31] Adding more args to post commit hook --- src/mongo/delegates/Updates.class.php | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index b84b5fa5..8fd4e68b 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -153,7 +153,6 @@ public function saveChanges( { $this->applyPreHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); $this->setReadPreferenceToPrimary(); - $subjectsAndPredicatesOfChange = array(); try{ $contextAlias = $this->getContextAlias($context); @@ -169,6 +168,7 @@ public function saveChanges( $args = array('before' => $oldIndex, 'after' => $newIndex, 'changeReason' => $description); $cs = new \Tripod\ChangeSet($args); + $subjectsAndPredicatesOfChange = array(); if ($cs->has_changes()) { // store the actual CBDs @@ -180,6 +180,12 @@ public function saveChanges( // Schedule calculation of any async activity $this->queueAsyncOperations($subjectsAndPredicatesOfChange,$contextAlias); } + + $this->applyPostHooks($this->saveChangesHooks,array( + "pod"=>$this->getPodName(), + "changeSet"=>$cs, + "subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange + )); } catch(\Exception $e){ // ensure we reset the original read preference in the event of an exception @@ -189,7 +195,6 @@ public function saveChanges( $this->resetOriginalReadPreference(); - $this->applyPostHooks($this->saveChangesHooks,array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange)); return true; } @@ -1066,12 +1071,12 @@ protected function lockSingleDocument($s, $transaction_id, $contextAlias) { $countEntriesInLocksCollection = $this->getLocksCollection() ->count( - array( - _ID_KEY => array( - _ID_RESOURCE => $this->labeller->uri_to_alias($s), - _ID_CONTEXT => $contextAlias) - ) - ); + array( + _ID_KEY => array( + _ID_RESOURCE => $this->labeller->uri_to_alias($s), + _ID_CONTEXT => $contextAlias) + ) + ); if($countEntriesInLocksCollection > 0) //Subject is already locked return false; From 7e5196b58a54f9bc8210dd4be565052319fb3b2b Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 11 Aug 2015 17:10:31 +0100 Subject: [PATCH 21/31] Fixes #91 --- src/mongo/providers/MongoSearchProvider.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mongo/providers/MongoSearchProvider.class.php b/src/mongo/providers/MongoSearchProvider.class.php index 614f0a8d..68680bcb 100644 --- a/src/mongo/providers/MongoSearchProvider.class.php +++ b/src/mongo/providers/MongoSearchProvider.class.php @@ -106,7 +106,7 @@ public function deleteDocument($resource, $context, $specId = array()) { return; } - $query[_ID_KEY . '.' . _ID_TYPE] = array('$in'=>$specId); + $query[_ID_KEY . '.' . _ID_TYPE] = array('$in'=>array_values($specId)); $searchTypes = $specId; } } From ef1507b7dade434277adada6d0d805e48bb1f6a2 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 11 Aug 2015 17:11:27 +0100 Subject: [PATCH 22/31] Fixes #90 --- src/mongo/delegates/Tables.class.php | 21 +++++++++++++-------- test/unit/mongo/MongoTripodTablesTest.php | 4 ++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/mongo/delegates/Tables.class.php b/src/mongo/delegates/Tables.class.php index 99b55ddf..50371571 100644 --- a/src/mongo/delegates/Tables.class.php +++ b/src/mongo/delegates/Tables.class.php @@ -252,6 +252,8 @@ public function getTableRows($tableSpecId,$filter=array(),$sortBy=array(),$offse $rows = array(); foreach ($results as $doc) { +// $log = new \Monolog\Logger("TEST"); +// $log->error("Doc",$doc); if (array_key_exists(_IMPACT_INDEX,$doc['value'])) unset($doc['value'][_IMPACT_INDEX]); // remove impact index from client $rows[] = $doc['value']; } @@ -509,16 +511,19 @@ public function generateTableRows($tableType,$resource=null,$context=null,$queue ); // ensure any custom view indexes - if (isset($tableSpec['ensureIndexes'])) + foreach (Config::getInstance()->getTableSpecifications($this->storeName) as $tSpec) { - foreach ($tableSpec['ensureIndexes'] as $ensureIndex) + if (isset($tSpec['ensureIndexes'])) { - $collection->ensureIndex( - $ensureIndex, - array( - 'background'=>1 - ) - ); + foreach ($tSpec['ensureIndexes'] as $ensureIndex) + { + $collection->ensureIndex( + $ensureIndex, + array( + 'background'=>1 + ) + ); + } } } diff --git a/test/unit/mongo/MongoTripodTablesTest.php b/test/unit/mongo/MongoTripodTablesTest.php index 4f2abeb4..eba9d701 100644 --- a/test/unit/mongo/MongoTripodTablesTest.php +++ b/test/unit/mongo/MongoTripodTablesTest.php @@ -178,7 +178,7 @@ public function testGenerateTableRowsWithCountUpdateAndRequery() $this->assertEquals(count($t2['results']),2); foreach ($t2['results'] as $r) { - if ($r['_id']['r'] = $subject) { + if ($r['_id']['r'] == $subject) { $result = $r; } } @@ -224,7 +224,7 @@ public function testGenerateTableRowsWithCountAndRegexUpdateAndRequery() $this->assertEquals(count($t2['results']),2); foreach ($t2['results'] as $r) { - if ($r['_id']['r'] = $subject) { + if ($r['_id']['r'] == $subject) { $result = $r; } } From 9eaf4b8ab82544ae9a35065f713cf19a7fe1986b Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 11 Aug 2015 17:31:19 +0100 Subject: [PATCH 23/31] Adding tests for event hooks --- src/mongo/delegates/Updates.class.php | 12 +++- test/unit/mongo/MongoTripodDriverTest.php | 80 ++++++++++++++++++++++- 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 8fd4e68b..3dc35a23 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -151,7 +151,12 @@ public function saveChanges( $context=null, $description=null) { - $this->applyPreHooks($this->saveChangesHooks,array("oldGraph"=>$oldGraph,"newGraph"=>$newGraph,"context"=>$context)); + $this->applyPreHooks($this->saveChangesHooks,array( + "pod"=>$this->getPodName(), + "oldGraph"=>$oldGraph, + "newGraph"=>$newGraph, + "context"=>$context + )); $this->setReadPreferenceToPrimary(); try{ $contextAlias = $this->getContextAlias($context); @@ -183,8 +188,11 @@ public function saveChanges( $this->applyPostHooks($this->saveChangesHooks,array( "pod"=>$this->getPodName(), + "oldGraph"=>$oldGraph, + "newGraph"=>$newGraph, + "context"=>$context, "changeSet"=>$cs, - "subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange + "subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange, )); } catch(\Exception $e){ diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index 9ea1ebf0..7c69c738 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -26,7 +26,7 @@ protected function setUp() // Stub ouf 'addToElastic' search to prevent writes into Elastic Search happening by default. $this->tripod = $this->getMock( '\Tripod\Mongo\Driver', - array('addToSearchIndexQueue'), + array('validateGraphCardinality'), array( 'CBD_testing', 'tripod_php_testing', @@ -1975,6 +1975,82 @@ public function testRemoveInertLocks() $this->assertEquals(0, count($docs)); } - /** END: removeInertLocks tests */ + + /** START: saveChangesHooks tests */ + public function testRegisteredHooksAreCalled() + { + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post'), array(), '', false); + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post'), array(), '', false); + + $mockHookA->expects($this->once())->method("pre"); + $mockHookA->expects($this->once())->method("post"); + $mockHookB->expects($this->once())->method("pre"); + $mockHookB->expects($this->once())->method("post"); + + $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookA); + $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookB); + + $this->tripod->saveChanges(new \Tripod\ExtendedGraph(),new \Tripod\ExtendedGraph()); + } + + public function testRegisteredPostHooksAreNotCalledOnException() + { + $this->setExpectedException('\Tripod\Exceptions\Exception','Could not validate'); + + /* @var $tripodUpdate \Tripod\Mongo\Updates|PHPUnit_Framework_MockObject_MockObject */ + $tripodUpdate = $this->getMock( + '\Tripod\Mongo\Updates', + array('validateGraphCardinality'), + array($this->tripod) + ); + + /* @var $mockHookA \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post'), array(), '', false); + /* @var $mockHookB \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post'), array(), '', false); + + $mockHookA->expects($this->once())->method("pre"); + $mockHookA->expects($this->never())->method("post"); + $mockHookB->expects($this->once())->method("pre"); + $mockHookB->expects($this->never())->method("post"); + + $tripodUpdate->registerSaveChangesEventHook($mockHookA); + $tripodUpdate->registerSaveChangesEventHook($mockHookB); + + $tripodUpdate->expects($this->once())->method('validateGraphCardinality')->willThrowException(new \Tripod\Exceptions\Exception("Could not validate")); + $tripodUpdate->saveChanges(new \Tripod\ExtendedGraph(),new \Tripod\ExtendedGraph()); + } + + /** END: saveChangesHooks tests */ + } +class TestSaveChangesHookA implements \Tripod\IEventHook +{ + /** + * This method gets called just before the event happens. The arguments passed depend on the event in question, see + * the documentation for that event type for details + * @param $args array of arguments + */ + public function pre(array $args) + { + // do nothing + } + + /** + * This method gets called after the event has successfully completed. The arguments passed depend on the event in + * question, see the documentation for that event type for details + * If the event throws an exception or fatal error, this method will not be called. + * @param $args array of arguments + */ + public function post(array $args) + { + // do nothing + } + +} + +class TestSaveChangesHookB extends TestSaveChangesHookA +{ + // empty +} \ No newline at end of file From 3fa5cacb1046a5ff4e6de90ae1bdd8a93dfa6f93 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 11 Aug 2015 17:38:16 +0100 Subject: [PATCH 24/31] Adding failure condition --- src/IEventHook.php | 7 +++++++ src/mongo/base/DriverBase.class.php | 5 +++++ src/mongo/delegates/Updates.class.php | 6 ++++++ test/unit/mongo/MongoTripodDriverTest.php | 17 +++++++++++++++-- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/IEventHook.php b/src/IEventHook.php index 2c9f7b2a..b8b71274 100644 --- a/src/IEventHook.php +++ b/src/IEventHook.php @@ -39,4 +39,11 @@ public function pre(array $args); * @param $args array of arguments */ public function post(array $args); + + /** + * This method gets called if the event failed for any reason. The arguments passed should be the same as IEventHook::pre + * @param array $args + * @return mixed + */ + public function failure(array $args); } \ No newline at end of file diff --git a/src/mongo/base/DriverBase.class.php b/src/mongo/base/DriverBase.class.php index 195cf636..f4a9f665 100644 --- a/src/mongo/base/DriverBase.class.php +++ b/src/mongo/base/DriverBase.class.php @@ -388,6 +388,11 @@ protected function applyPostHooks($hooks,$args=array()) $this->applyHooks("post",$hooks,$args); } + protected function applyFailureHooks($hooks,$args=array()) + { + $this->applyHooks("failure",$hooks,$args); + } + private function applyHooks($fn,$hooks,$args=array()) { foreach ($hooks as $hook) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 3dc35a23..8a82e6bb 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -198,6 +198,12 @@ public function saveChanges( catch(\Exception $e){ // ensure we reset the original read preference in the event of an exception $this->resetOriginalReadPreference(); + $this->applyFailureHooks($this->saveChangesHooks,array( + "pod"=>$this->getPodName(), + "oldGraph"=>$oldGraph, + "newGraph"=>$newGraph, + "context"=>$context + )); throw $e; } diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index 7c69c738..6bfa65ad 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -1985,8 +1985,10 @@ public function testRegisteredHooksAreCalled() $mockHookA->expects($this->once())->method("pre"); $mockHookA->expects($this->once())->method("post"); + $mockHookA->expects($this->never())->method("failure"); $mockHookB->expects($this->once())->method("pre"); $mockHookB->expects($this->once())->method("post"); + $mockHookB->expects($this->never())->method("failure"); $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookA); $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookB); @@ -2006,14 +2008,16 @@ public function testRegisteredPostHooksAreNotCalledOnException() ); /* @var $mockHookA \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ - $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post'), array(), '', false); + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post', 'failure'), array(), '', false); /* @var $mockHookB \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ - $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post'), array(), '', false); + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post', 'failure'), array(), '', false); $mockHookA->expects($this->once())->method("pre"); $mockHookA->expects($this->never())->method("post"); + $mockHookA->expects($this->once())->method("failure"); $mockHookB->expects($this->once())->method("pre"); $mockHookB->expects($this->never())->method("post"); + $mockHookB->expects($this->once())->method("failure"); $tripodUpdate->registerSaveChangesEventHook($mockHookA); $tripodUpdate->registerSaveChangesEventHook($mockHookB); @@ -2048,6 +2052,15 @@ public function post(array $args) // do nothing } + /** + * This method gets called if the event failed for any reason. The arguments passed should be the same as IEventHook::pre + * @param array $args + * @return mixed + */ + public function failure(array $args) + { + // do nothing + } } class TestSaveChangesHookB extends TestSaveChangesHookA From 039a19060c4eebc405601ba68fd670d35df5c3c5 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Wed, 12 Aug 2015 11:10:06 +0100 Subject: [PATCH 25/31] More elegence for executing hooks --- src/mongo/base/DriverBase.class.php | 32 +++++++++++++-------------- src/mongo/delegates/Updates.class.php | 6 ++--- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/mongo/base/DriverBase.class.php b/src/mongo/base/DriverBase.class.php index f4a9f665..9d82b162 100644 --- a/src/mongo/base/DriverBase.class.php +++ b/src/mongo/base/DriverBase.class.php @@ -16,6 +16,13 @@ */ abstract class DriverBase { + /** + * constants for the supported hook functions that can be applied + */ + const HOOK_FN_PRE = "pre"; + const HOOK_FN_POST = "post"; + const HOOK_FN_FAILURE = "failure"; + /** * @var \MongoCollection */ @@ -378,23 +385,16 @@ protected function getCollection() return $this->collection; } - protected function applyPreHooks($hooks,$args=array()) - { - $this->applyHooks("pre",$hooks,$args); - } - - protected function applyPostHooks($hooks,$args=array()) - { - $this->applyHooks("post",$hooks,$args); - } - - protected function applyFailureHooks($hooks,$args=array()) - { - $this->applyHooks("failure",$hooks,$args); - } - - private function applyHooks($fn,$hooks,$args=array()) + protected function applyHooks($fn,$hooks,$args=array()) { + switch ($fn) { + case $this::HOOK_FN_PRE: + case $this::HOOK_FN_POST: + case $this::HOOK_FN_FAILURE: + break; + default: + throw new Exception("Invalid hook function $fn requested"); + } foreach ($hooks as $hook) { try diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 8a82e6bb..0b11ac0d 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -151,7 +151,7 @@ public function saveChanges( $context=null, $description=null) { - $this->applyPreHooks($this->saveChangesHooks,array( + $this->applyHooks($this::HOOK_FN_PRE,$this->saveChangesHooks,array( "pod"=>$this->getPodName(), "oldGraph"=>$oldGraph, "newGraph"=>$newGraph, @@ -186,7 +186,7 @@ public function saveChanges( $this->queueAsyncOperations($subjectsAndPredicatesOfChange,$contextAlias); } - $this->applyPostHooks($this->saveChangesHooks,array( + $this->applyHooks($this::HOOK_FN_POST,$this->saveChangesHooks,array( "pod"=>$this->getPodName(), "oldGraph"=>$oldGraph, "newGraph"=>$newGraph, @@ -198,7 +198,7 @@ public function saveChanges( catch(\Exception $e){ // ensure we reset the original read preference in the event of an exception $this->resetOriginalReadPreference(); - $this->applyFailureHooks($this->saveChangesHooks,array( + $this->applyHooks($this::HOOK_FN_FAILURE,$this->saveChangesHooks,array( "pod"=>$this->getPodName(), "oldGraph"=>$oldGraph, "newGraph"=>$newGraph, From ec0cf11877a5c30206cbebb38e223bbb963b78fd Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Wed, 12 Aug 2015 11:10:48 +0100 Subject: [PATCH 26/31] Less rabbits --- src/mongo/base/DriverBase.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mongo/base/DriverBase.class.php b/src/mongo/base/DriverBase.class.php index 9d82b162..134d8394 100644 --- a/src/mongo/base/DriverBase.class.php +++ b/src/mongo/base/DriverBase.class.php @@ -404,7 +404,7 @@ protected function applyHooks($fn,$hooks,$args=array()) } catch (\Exception $e) { - // don't let rabbid hooks stop tripod + // don't let rabid hooks stop tripod $this->getLogger()->error("Hook ".get_class($hook)." threw exception {$e->getMessage()}, continuing"); } } From 9f4cf047bb58283b71938e4d2231f4cf5a0bc0b0 Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Wed, 12 Aug 2015 11:25:38 +0100 Subject: [PATCH 27/31] Improve interface documentation --- src/IDriver.php | 75 ++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/src/IDriver.php b/src/IDriver.php index cf283574..a0b5c32d 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -8,20 +8,18 @@ */ interface IDriver { - public function graph($query,$includeProperties=array()); - /** - * @deprecated - * @abstract - * @param $query + * Equivalent to CONSTRUCT + * @param array $filter conditions to filter by + * @param array $includeProperties only include these predicates, empty array means return all predicates * @return mixed */ - public function describe($query); + public function graph($filter,$includeProperties=array()); /** * Return (DESCRIBE) the concise bound description of a resource - * @param $resource string uri resource you'd like to describe - * @param null $context string uri of the context, or named graph, you'd like to describe from + * @param string $resource uri resource you'd like to describe + * @param null|string $context string uri of the context, or named graph, you'd like to describe from * @return ExtendedGraph */ public function describeResource($resource,$context=null); @@ -29,15 +27,15 @@ public function describeResource($resource,$context=null); /** * Return (DESCRIBE) the concise bound descriptions of a bunch of resources * @param array $resources uris of resources you'd like to describe - * @param null $context string uri of the context, or named graph, you'd like to describe from + * @param null|string $context string uri of the context, or named graph, you'd like to describe from * @return ExtendedGraph */ public function describeResources(Array $resources,$context=null); /** * Get a view of a given type for a given resource - * @param $resource string uri of the resource you'd like the view for - * @param $viewType string type of view + * @param string $resource uri of the resource you'd like the view for + * @param string $viewType string type of view * @return ExtendedGraph */ public function getViewForResource($resource,$viewType); @@ -45,7 +43,7 @@ public function getViewForResource($resource,$viewType); /** * Get views for multiple resources in one graph * @param array $resources uris of resources you'd like to describe - * @param $viewType string type of view + * @param string $viewType type of view * @return ExtendedGraph */ public function getViewForResources(Array $resources,$viewType); @@ -53,13 +51,16 @@ public function getViewForResources(Array $resources,$viewType); /** * Get views based on a pattern-match $filter * @param array $filter pattern to match to select views - * @param $viewType string type of view + * @param string $viewType type of view * @return ExtendedGraph */ public function getViews(Array $filter,$viewType); /** * Returns the etag of a resource, useful for caching + * @param string $resource + * @param null|string $context + * @return string */ public function getETag($resource,$context=null); @@ -81,7 +82,7 @@ public function select($filter,$fields,$sortBy=null,$limit=null,$context=null); * @param array $sortBy * @param int $offset * @param int $limit - * @return mixed + * @return array */ public function getTableRows($tableType,$filter=array(),$sortBy=array(),$offset=0,$limit=10); @@ -90,7 +91,7 @@ public function getTableRows($tableType,$filter=array(),$sortBy=array(),$offset= * @param $tableType * @param $fieldName * @param array $filter - * @return mixed + * @return array */ public function getDistinctTableColumnValues($tableType, $fieldName, array $filter = array()); @@ -98,8 +99,8 @@ public function getDistinctTableColumnValues($tableType, $fieldName, array $filt /** * Get a count of resources matching the pattern in $query. Optionally group counts by specifying a $groupBy predicate * @param $query - * @param null $groupBy - * @return mixed + * @param null|string $groupBy + * @return array|int multidimensional array with int values if grouped by, otherwise int */ public function getCount($query,$groupBy=null); @@ -107,27 +108,35 @@ public function getCount($query,$groupBy=null); * Save the changes between $oldGraph -> $newGraph * @param ExtendedGraph $oldGraph * @param ExtendedGraph $newGraph - * @param null $context - * @param null $description - * @return mixed + * @param null|string $context + * @param null|string $description + * @return bool true or throws exception on error */ public function saveChanges(ExtendedGraph $oldGraph, ExtendedGraph $newGraph,$context=null,$description=null); /** - * Register an event hook, which + * Register an event hook, which will be executed when the event fires. * @param $eventType - * @param IEventHook $ - * @return mixed + * @param IEventHook $hook */ public function registerHook($eventType,IEventHook $hook); + /* START Deprecated methods that will be removed in 1.x.x */ + + /** + * Return (DESCRIBE) according to a filter + * @deprecated Use graph() instead + * @param array $filter conditions to filter by + * @return ExtendedGraph + */ + public function describe($filter); + /** * Generates table rows * @deprecated calling save will generate table rows - this method seems to be only used in tests and does not belong on the interface * @param $tableType - * @param null $resource - * @param null $context - * @return mixed + * @param null|string $resource + * @param null|string $context */ public function generateTableRows($tableType,$resource=null,$context=null); @@ -155,19 +164,21 @@ public function search(Array $params); /** * Get any documents that were left in a locked state * @deprecated this is a feature of the mongo implementation - this method will move from the interface to the mongo-specific Driver class soon. - * @param null $fromDateTime - * @param null $tillDateTime - * @return mixed + * @param null|string $fromDateTime strtotime compatible string + * @param null|string $tillDateTime strtotime compatible string + * @return array of locked documents */ public function getLockedDocuments($fromDateTime =null , $tillDateTime = null); /** * Remove any inert locks left by a given transaction * @deprecated this is a feature of the mongo implementation - this method will move from the interface to the mongo-specific Driver class soon. - * @param $transaction_id - * @param $reason - * @return mixed + * @param string $transaction_id + * @param string $reason + * @return bool true or throws exception on error */ public function removeInertLocks($transaction_id, $reason); + /* END Deprecated methods that will be removed in 1.x.x */ + } \ No newline at end of file From 75f912c16a2ad03075fa18ba5cda4a91e0b1131e Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 18 Aug 2015 10:28:28 +0100 Subject: [PATCH 28/31] Returning transaction_id to hook --- src/mongo/delegates/Updates.class.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index 0b11ac0d..fded50a0 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -2,6 +2,7 @@ namespace Tripod\Mongo; +use Tripod\Exceptions\Exception; use Tripod\IEventHook; require_once TRIPOD_DIR . 'mongo/Config.class.php'; @@ -174,10 +175,16 @@ public function saveChanges( $cs = new \Tripod\ChangeSet($args); $subjectsAndPredicatesOfChange = array(); + $transaction_id = null; if ($cs->has_changes()) { // store the actual CBDs - $subjectsAndPredicatesOfChange = $this->storeChanges($cs, $contextAlias); + $result = $this->storeChanges($cs, $contextAlias); + if (!isset($result['subjectsAndPredicatesOfChange'])|| !isset($result['transaction_id'])) { + $this->errorLog("Result of storeChanges malformed, should have transaction_id and subjectsAndPredicatesOfChange array keys",array("result"=>$result)); + throw new Exception("Result of storeChanges malformed, should have transaction_id and subjectsAndPredicatesOfChange array keys"); + } + extract($result); // will unpack into $subjectsAndPredicatesOfChange // Process any syncronous operations $this->processSyncOperations($subjectsAndPredicatesOfChange,$contextAlias); @@ -193,6 +200,7 @@ public function saveChanges( "context"=>$context, "changeSet"=>$cs, "subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange, + "transaction_id"=>$transaction_id )); } catch(\Exception $e){ @@ -366,7 +374,7 @@ protected function storeChanges(\Tripod\ChangeSet $cs, $contextAlias) $this->timingLog(MONGO_WRITE, array('duration'=>$t->result(), 'subjectsOfChange'=>implode(", ",$subjectsOfChange))); $this->getStat()->timer(MONGO_WRITE.".{$this->getPodName()}",$t->result()); - return $changes['subjectsAndPredicatesOfChange']; + return $changes; } catch(\Exception $e) { @@ -625,7 +633,8 @@ protected function applyChangeSet(\Tripod\ChangeSet $cs, $originalCBDs, $context return array( 'newCBDs'=>$newCBDs, - 'subjectsAndPredicatesOfChange'=>$this->subjectsAndPredicatesOfChangeUrisToAliases($subjectsAndPredicatesOfChange) + 'subjectsAndPredicatesOfChange'=>$this->subjectsAndPredicatesOfChangeUrisToAliases($subjectsAndPredicatesOfChange), + 'transaction_id'=>$transaction_id ); } else From 08a3ab823fe92407aa54949a25f300137df15518 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 24 Aug 2015 21:36:20 +0100 Subject: [PATCH 29/31] Adding/fixing tests --- test/unit/mongo/MongoTripodDriverTest.php | 28 +++++++++++++++---- .../mongo/MongoTripodSearchIndexerTest.php | 4 +-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index 6bfa65ad..ec7cb5a6 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -937,7 +937,7 @@ public function testDiscoverImpactedSubjectsAreDoneAllOperationsASync() $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue($subjectsAndPredicatesOfChange)); + ->will($this->returnValue(array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange,"transaction_id"=>"t1234"))); $mockTripod->expects($this->once()) ->method('getDataUpdater') @@ -1134,7 +1134,7 @@ public function testDiscoverImpactedSubjectsForDeletionsSyncOpsAreDoneAsyncJobSu $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue($subjectsAndPredicatesOfChange)); + ->will($this->returnValue(array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange,"transaction_id"=>"t1234"))); $mockTripod->expects($this->exactly(2)) ->method('getComposite') @@ -1279,7 +1279,7 @@ public function testDiscoverImpactedSubjectsForDefaultOperationsSetting() $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue($subjectsAndPredicatesOfChange)); + ->will($this->returnValue(array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange,"transaction_id"=>"t1234"))); $mockTripod->expects($this->once()) ->method('getDataUpdater') @@ -1429,7 +1429,7 @@ public function testSpecifyQueueForAsyncOperations() $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue($subjectsAndPredicatesOfChange)); + ->will($this->returnValue(array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange,"transaction_id"=>"t1234"))); $mockTripod->expects($this->once()) ->method('getDataUpdater') @@ -2026,6 +2026,24 @@ public function testRegisteredPostHooksAreNotCalledOnException() $tripodUpdate->saveChanges(new \Tripod\ExtendedGraph(),new \Tripod\ExtendedGraph()); } + public function testMisbehavingHookDoesNotPreventSaveOrInterfereWithOtherHooks() + { + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post'), array(), '', false); + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post'), array(), '', false); + + $mockHookA->expects($this->once())->method("pre")->will($this->throwException(new Exception("Misbehaving hook"))); + $mockHookA->expects($this->once())->method("post")->will($this->throwException(new Exception("Misbehaving hook"))); + $mockHookA->expects($this->never())->method("failure"); + $mockHookB->expects($this->once())->method("pre"); + $mockHookB->expects($this->once())->method("post"); + $mockHookB->expects($this->never())->method("failure"); + + $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookA); + $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookB); + + $this->tripod->saveChanges(new \Tripod\ExtendedGraph(),new \Tripod\ExtendedGraph()); + } + /** END: saveChangesHooks tests */ } @@ -2066,4 +2084,4 @@ public function failure(array $args) class TestSaveChangesHookB extends TestSaveChangesHookA { // empty -} \ No newline at end of file +} diff --git a/test/unit/mongo/MongoTripodSearchIndexerTest.php b/test/unit/mongo/MongoTripodSearchIndexerTest.php index d9c74820..6abdad7b 100644 --- a/test/unit/mongo/MongoTripodSearchIndexerTest.php +++ b/test/unit/mongo/MongoTripodSearchIndexerTest.php @@ -64,7 +64,7 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() $tripodUpdate->expects($this->atLeastOnce()) ->method('storeChanges') - ->will($this->returnValue($subjectsAndPredicatesOfChange)); + ->will($this->returnValue(array("subjectsAndPredicatesOfChange"=>$subjectsAndPredicatesOfChange,"transaction_id"=>"t1234"))); $tripod->expects($this->atLeastOnce()) ->method('getDataUpdater') @@ -364,7 +364,7 @@ function testSearchDocumentsNotRegeneratedIfChangeIsNotInSearchSpec() ); $tripodUpdate->expects($this->atLeastOnce()) ->method('storeChanges') - ->will($this->returnValue(array('deletedSubjects'=>array()))); + ->will($this->returnValue(array('deletedSubjects'=>array(),"subjectsAndPredicatesOfChange"=>array(),"transaction_id"=>'t1234'))); $tripod->expects($this->atLeastOnce()) ->method('getDataUpdater') From 1147a6fcfe7e1dd83d4e793f3b8a3bfc5066445e Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 24 Aug 2015 22:23:07 +0100 Subject: [PATCH 30/31] Fixed tests --- test/unit/mongo/MongoGraphTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/mongo/MongoGraphTest.php b/test/unit/mongo/MongoGraphTest.php index 98243b98..92fbf591 100644 --- a/test/unit/mongo/MongoGraphTest.php +++ b/test/unit/mongo/MongoGraphTest.php @@ -209,8 +209,8 @@ public function addTripodArrayContainingInvalidPredicates_Provider(){ */ public function testAddTripodArrayContainingEmptyPredicate() { - // An Uninitialized string offset should occur if an empty predicate is passed. - $this->setExpectedException("PHPUnit_Framework_Error"); + // Should not be able to label '' + $this->setExpectedException('\Tripod\Exceptions\LabellerException'); $doc = array( "_id"=>array("r"=>"http://talisaspire.com/works/4d101f63c10a6-2", "c"=>"http://talisaspire.com/works/4d101f63c10a6-2"), "_version"=>0, From 9aa6d297294c71b167bcc636a880a0ae48478bca Mon Sep 17 00:00:00 2001 From: Chris Clarke Date: Tue, 25 Aug 2015 16:50:28 +0100 Subject: [PATCH 31/31] Fixing tests, post->success --- src/IEventHook.php | 2 +- src/mongo/MongoGraph.class.php | 15 ++++++++---- src/mongo/base/DriverBase.class.php | 4 ++-- src/mongo/delegates/Updates.class.php | 2 +- test/unit/mongo/MongoGraphTest.php | 2 +- test/unit/mongo/MongoTripodDriverTest.php | 28 +++++++++++------------ 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/IEventHook.php b/src/IEventHook.php index b8b71274..a46da36c 100644 --- a/src/IEventHook.php +++ b/src/IEventHook.php @@ -38,7 +38,7 @@ public function pre(array $args); * If the event throws an exception or fatal error, this method will not be called. * @param $args array of arguments */ - public function post(array $args); + public function success(array $args); /** * This method gets called if the event failed for any reason. The arguments passed should be the same as IEventHook::pre diff --git a/src/mongo/MongoGraph.class.php b/src/mongo/MongoGraph.class.php index 436131c9..f4924854 100644 --- a/src/mongo/MongoGraph.class.php +++ b/src/mongo/MongoGraph.class.php @@ -127,18 +127,25 @@ private function add_tarray_to_index($tarray) $predObjects = array(); foreach ($tarray as $key=>$value) { - if($key[0] != '_') + if (empty($key)) + { + throw new \Tripod\Exceptions\Exception("The predicate cannot be an empty string"); + } + else if($key[0] != '_') { $predicate = $this->qname_to_uri($key); $graphValueObject = $this->toGraphValueObject($value); // Only add if valid values have been found - if (!empty($graphValueObject)) { + if (!empty($graphValueObject)) + { $predObjects[$predicate] = $graphValueObject; } } - else if($key == "_id"){ + else if($key == "_id") + { // If the subject is invalid then throw an exception - if(!isset($value['r']) || !$this->isValidResource($value['r'])){ + if(!isset($value['r']) || !$this->isValidResource($value['r'])) + { throw new \Tripod\Exceptions\Exception("The subject cannot be an empty string"); } } diff --git a/src/mongo/base/DriverBase.class.php b/src/mongo/base/DriverBase.class.php index 134d8394..bf5f8ac7 100644 --- a/src/mongo/base/DriverBase.class.php +++ b/src/mongo/base/DriverBase.class.php @@ -20,7 +20,7 @@ abstract class DriverBase * constants for the supported hook functions that can be applied */ const HOOK_FN_PRE = "pre"; - const HOOK_FN_POST = "post"; + const HOOK_FN_SUCCESS = "success"; const HOOK_FN_FAILURE = "failure"; /** @@ -389,7 +389,7 @@ protected function applyHooks($fn,$hooks,$args=array()) { switch ($fn) { case $this::HOOK_FN_PRE: - case $this::HOOK_FN_POST: + case $this::HOOK_FN_SUCCESS: case $this::HOOK_FN_FAILURE: break; default: diff --git a/src/mongo/delegates/Updates.class.php b/src/mongo/delegates/Updates.class.php index fded50a0..edf6d2de 100644 --- a/src/mongo/delegates/Updates.class.php +++ b/src/mongo/delegates/Updates.class.php @@ -193,7 +193,7 @@ public function saveChanges( $this->queueAsyncOperations($subjectsAndPredicatesOfChange,$contextAlias); } - $this->applyHooks($this::HOOK_FN_POST,$this->saveChangesHooks,array( + $this->applyHooks($this::HOOK_FN_SUCCESS,$this->saveChangesHooks,array( "pod"=>$this->getPodName(), "oldGraph"=>$oldGraph, "newGraph"=>$newGraph, diff --git a/test/unit/mongo/MongoGraphTest.php b/test/unit/mongo/MongoGraphTest.php index 92fbf591..1f0f484f 100644 --- a/test/unit/mongo/MongoGraphTest.php +++ b/test/unit/mongo/MongoGraphTest.php @@ -210,7 +210,7 @@ public function addTripodArrayContainingInvalidPredicates_Provider(){ public function testAddTripodArrayContainingEmptyPredicate() { // Should not be able to label '' - $this->setExpectedException('\Tripod\Exceptions\LabellerException'); + $this->setExpectedException('\Tripod\Exceptions\Exception','The predicate cannot be an empty string'); $doc = array( "_id"=>array("r"=>"http://talisaspire.com/works/4d101f63c10a6-2", "c"=>"http://talisaspire.com/works/4d101f63c10a6-2"), "_version"=>0, diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index c75a84fe..590977db 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -1980,14 +1980,14 @@ public function testRemoveInertLocks() /** START: saveChangesHooks tests */ public function testRegisteredHooksAreCalled() { - $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post'), array(), '', false); - $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post'), array(), '', false); + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'success'), array(), '', false); + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'success'), array(), '', false); $mockHookA->expects($this->once())->method("pre"); - $mockHookA->expects($this->once())->method("post"); + $mockHookA->expects($this->once())->method("success"); $mockHookA->expects($this->never())->method("failure"); $mockHookB->expects($this->once())->method("pre"); - $mockHookB->expects($this->once())->method("post"); + $mockHookB->expects($this->once())->method("success"); $mockHookB->expects($this->never())->method("failure"); $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookA); @@ -1996,7 +1996,7 @@ public function testRegisteredHooksAreCalled() $this->tripod->saveChanges(new \Tripod\ExtendedGraph(),new \Tripod\ExtendedGraph()); } - public function testRegisteredPostHooksAreNotCalledOnException() + public function testRegisteredSuccessHooksAreNotCalledOnException() { $this->setExpectedException('\Tripod\Exceptions\Exception','Could not validate'); @@ -2008,15 +2008,15 @@ public function testRegisteredPostHooksAreNotCalledOnException() ); /* @var $mockHookA \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ - $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post', 'failure'), array(), '', false); + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'success', 'failure'), array(), '', false); /* @var $mockHookB \Tripod\IEventHook|PHPUnit_Framework_MockObject_MockObject*/ - $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post', 'failure'), array(), '', false); + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'success', 'failure'), array(), '', false); $mockHookA->expects($this->once())->method("pre"); - $mockHookA->expects($this->never())->method("post"); + $mockHookA->expects($this->never())->method("success"); $mockHookA->expects($this->once())->method("failure"); $mockHookB->expects($this->once())->method("pre"); - $mockHookB->expects($this->never())->method("post"); + $mockHookB->expects($this->never())->method("success"); $mockHookB->expects($this->once())->method("failure"); $tripodUpdate->registerSaveChangesEventHook($mockHookA); @@ -2028,14 +2028,14 @@ public function testRegisteredPostHooksAreNotCalledOnException() public function testMisbehavingHookDoesNotPreventSaveOrInterfereWithOtherHooks() { - $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'post'), array(), '', false); - $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'post'), array(), '', false); + $mockHookA = $this->getMock("TestSaveChangesHookA", array('pre', 'success'), array(), '', false); + $mockHookB = $this->getMock("TestSaveChangesHookB", array('pre', 'success'), array(), '', false); $mockHookA->expects($this->once())->method("pre")->will($this->throwException(new Exception("Misbehaving hook"))); - $mockHookA->expects($this->once())->method("post")->will($this->throwException(new Exception("Misbehaving hook"))); + $mockHookA->expects($this->once())->method("success")->will($this->throwException(new Exception("Misbehaving hook"))); $mockHookA->expects($this->never())->method("failure"); $mockHookB->expects($this->once())->method("pre"); - $mockHookB->expects($this->once())->method("post"); + $mockHookB->expects($this->once())->method("success"); $mockHookB->expects($this->never())->method("failure"); $this->tripod->registerHook(\Tripod\IEventHook::EVENT_SAVE_CHANGES,$mockHookA); @@ -2065,7 +2065,7 @@ public function pre(array $args) * If the event throws an exception or fatal error, this method will not be called. * @param $args array of arguments */ - public function post(array $args) + public function success(array $args) { // do nothing }