From 8ff1fa21a5c5634ee3b370c7043aadb13424d91e Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Thu, 26 Feb 2026 23:00:41 +0000 Subject: [PATCH 01/56] Apply Rector --- scripts/mongo/BSONToQuads.php | 2 +- scripts/mongo/BSONToTriples.php | 3 +- scripts/mongo/createSearchDocuments.php | 21 +- scripts/mongo/createTables.php | 27 +- scripts/mongo/createViews.php | 27 +- scripts/mongo/detectNamespaces.php | 26 +- scripts/mongo/discoverUnnamespacedUris.php | 38 +- scripts/mongo/ensureIndexes.php | 5 +- scripts/mongo/loadTriples.php | 17 +- scripts/mongo/triplesToBSON.php | 6 +- scripts/mongo/validateConfig.php | 5 +- src/Config.php | 15 +- src/IDriver.php | 2 + src/IEventHook.php | 2 + src/ITripodConfig.php | 2 + src/ITripodConfigSerializer.php | 2 + src/ITripodStat.php | 6 +- src/TripodConfigFactory.php | 11 +- src/TripodStatFactory.php | 3 + src/classes/ChangeSet.php | 63 +-- src/classes/ExtendedGraph.php | 374 ++++++++---------- src/classes/Labeller.php | 102 ++--- src/classes/StatsD.php | 83 ++-- src/classes/Timer.php | 10 +- src/exceptions/CardinalityException.php | 2 + src/exceptions/ConfigException.php | 2 + src/exceptions/Exception.php | 2 + src/exceptions/JobException.php | 2 + src/exceptions/LabellerException.php | 4 +- src/exceptions/SearchException.php | 2 + src/exceptions/TimerException.php | 2 + src/exceptions/ViewException.php | 2 + src/mongo/Config.php | 257 ++++++------ src/mongo/Driver.php | 75 ++-- src/mongo/IComposite.php | 2 + src/mongo/IConfigInstance.php | 2 + src/mongo/ImpactedSubject.php | 25 +- src/mongo/JobGroup.php | 10 +- src/mongo/Labeller.php | 4 +- src/mongo/MongoGraph.php | 38 +- src/mongo/base/CompositeBase.php | 12 +- src/mongo/base/DriverBase.php | 69 ++-- src/mongo/base/JobBase.php | 52 ++- src/mongo/delegates/SearchDocuments.php | 79 ++-- src/mongo/delegates/SearchIndexer.php | 42 +- src/mongo/delegates/Tables.php | 363 ++++++++--------- src/mongo/delegates/TransactionLog.php | 17 +- src/mongo/delegates/Updates.php | 150 ++++--- src/mongo/delegates/Views.php | 155 ++++---- src/mongo/documents/Tables.php | 6 +- src/mongo/jobs/ApplyOperation.php | 29 +- src/mongo/jobs/DiscoverImpactedSubjects.php | 42 +- src/mongo/jobs/EnsureIndexes.php | 22 +- src/mongo/providers/ISearchProvider.php | 2 + src/mongo/providers/MongoSearchProvider.php | 66 ++-- src/mongo/serializers/NQuadSerializer.php | 62 +-- src/mongo/util/DateUtil.php | 6 +- src/mongo/util/IndexUtils.php | 35 +- src/mongo/util/TriplesUtil.php | 39 +- test/performance/mongo/LargeGraphTest.php | 10 +- .../mongo/MongoTripodConfigTest.php | 4 +- .../mongo/MongoTripodPerformanceTestBase.php | 2 + test/unit/ExtendedGraphTest.php | 230 ++++++----- test/unit/TimerTest.php | 20 +- test/unit/mongo/ApplyOperationTest.php | 157 ++++---- test/unit/mongo/ConfigGeneratorTest.php | 29 +- test/unit/mongo/DateUtilTest.php | 10 +- .../mongo/DiscoverImpactedSubjectsTest.php | 98 +++-- test/unit/mongo/EnsureIndexesTest.php | 56 +-- test/unit/mongo/IndexUtilsTest.php | 62 +-- test/unit/mongo/JobBaseTest.php | 9 +- test/unit/mongo/MongoGraphTest.php | 123 +++--- test/unit/mongo/MongoSearchProviderTest.php | 155 ++++---- test/unit/mongo/MongoTransactionLogTest.php | 105 ++--- .../mongo/MongoTripodComputedFieldsTest.php | 18 +- test/unit/mongo/MongoTripodConfigUnitTest.php | 246 ++++++------ .../MongoTripodDocumentStructureTest.php | 13 +- test/unit/mongo/MongoTripodDriverTest.php | 325 +++++++-------- .../mongo/MongoTripodNQuadSerializerTest.php | 8 +- .../mongo/MongoTripodQueueOperationsTest.php | 24 +- .../mongo/MongoTripodSearchDocumentsTest.php | 49 ++- .../mongo/MongoTripodSearchIndexerTest.php | 63 +-- test/unit/mongo/MongoTripodStatTest.php | 48 +-- test/unit/mongo/MongoTripodTablesTest.php | 243 ++++++------ test/unit/mongo/MongoTripodTestBase.php | 71 ++-- .../MongoTripodTransactionRollbackTest.php | 45 ++- test/unit/mongo/MongoTripodViewsTest.php | 207 +++++----- test/unit/mongo/ResqueJobTestBase.php | 8 +- test/unit/mongo/TestConfigGenerator.php | 8 +- test/unit/mongo/TestJobBase.php | 6 +- test/unit/mongo/TriplesUtilTest.php | 4 +- 91 files changed, 2553 insertions(+), 2434 deletions(-) diff --git a/scripts/mongo/BSONToQuads.php b/scripts/mongo/BSONToQuads.php index a95f2900..a4399d6f 100644 --- a/scripts/mongo/BSONToQuads.php +++ b/scripts/mongo/BSONToQuads.php @@ -8,7 +8,7 @@ require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; -if ($argc != 2) { +if ($argc !== 2) { echo "usage: ./BSONToQuads.php tripodConfig.json < bsondata\n"; echo " When exporting bson data from Mongo use: \n"; echo " mongoexport -d -c > bsondata.txt \n"; diff --git a/scripts/mongo/BSONToTriples.php b/scripts/mongo/BSONToTriples.php index a6698828..f16dbd40 100644 --- a/scripts/mongo/BSONToTriples.php +++ b/scripts/mongo/BSONToTriples.php @@ -8,13 +8,14 @@ require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; -if ($argc != 2) { +if ($argc !== 2) { echo "usage: ./BSONToTriples.php tripodConfig.json < bsondata\n"; echo " When exporting bson data from Mongo use: \n"; echo " mongoexport -d -c > bsondata.txt \n"; exit; } + array_shift($argv); $config = json_decode(file_get_contents($argv[0]), true); Config::setConfig($config); diff --git a/scripts/mongo/createSearchDocuments.php b/scripts/mongo/createSearchDocuments.php index b40d498d..2c4fd564 100644 --- a/scripts/mongo/createSearchDocuments.php +++ b/scripts/mongo/createSearchDocuments.php @@ -20,7 +20,7 @@ ] ); -function showUsage($scriptName) +function showUsage($scriptName): void { $help = <<getSearchDocumentSpecification($storeName, $specId); if (array_key_exists('from', $spec)) { Config::getInstance()->setMongoCursorTimeout(-1); - echo "Generating {$specId}"; + echo 'Generating ' . $specId; $tripod = new Driver($spec['from'], $storeName, ['stat' => $stat]); $search = $tripod->getSearchIndexer(); if ($id) { @@ -85,11 +86,7 @@ function generateSearchDocuments($id, $specId, $storeName, $stat = null, $queue Config::setConfig(json_decode(file_get_contents($configLocation), true)); -if (isset($options['s']) || isset($options['storename'])) { - $storeName = $options['s'] ?? $options['storename']; -} else { - $storeName = null; -} +$storeName = isset($options['s']) || isset($options['storename']) ? $options['s'] ?? $options['storename'] : null; if (isset($options['d']) || isset($options['spec'])) { $specId = isset($options['d']) ? $options['t'] : $options['spec']; @@ -97,11 +94,7 @@ function generateSearchDocuments($id, $specId, $storeName, $stat = null, $queue $specId = null; } -if (isset($options['i']) || isset($options['id'])) { - $id = $options['i'] ?? $options['id']; -} else { - $id = null; -} +$id = isset($options['i']) || isset($options['id']) ? $options['i'] ?? $options['id'] : null; $queue = null; if (isset($options['a']) || isset($options['async'])) { diff --git a/scripts/mongo/createTables.php b/scripts/mongo/createTables.php index 10f70370..cb7dd1d2 100644 --- a/scripts/mongo/createTables.php +++ b/scripts/mongo/createTables.php @@ -20,7 +20,7 @@ ] ); -function showUsage() +function showUsage(): void { $help = <<<'END' createTables.php @@ -44,7 +44,7 @@ function showUsage() echo $help; } -if (empty($options) || isset($options['h']) || isset($options['help']) +if ($options === [] || $options === false || isset($options['h']) || isset($options['help']) || (!isset($options['c']) && !isset($options['config'])) || (!isset($options['s']) && !isset($options['storename'])) ) { @@ -52,6 +52,7 @@ function showUsage() exit; } + $configLocation = $options['c'] ?? $options['config']; require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; @@ -63,13 +64,13 @@ function showUsage() * @param ITripodStat|null $stat * @param string|null $queue */ -function generateTables($id, $tableId, $storeName, $stat = null, $queue = null) +function generateTables($id, $tableId, $storeName, $stat = null, $queue = null): void { $tableSpec = Config::getInstance()->getTableSpecification($storeName, $tableId); if (array_key_exists('from', $tableSpec)) { Config::getInstance()->setMongoCursorTimeout(-1); - echo "Generating {$tableId}"; + echo 'Generating ' . $tableId; $tripod = new Driver($tableSpec['from'], $storeName, ['stat' => $stat]); $tTables = $tripod->getTripodTables(); if ($id) { @@ -87,23 +88,11 @@ function generateTables($id, $tableId, $storeName, $stat = null, $queue = null) Config::setConfig(json_decode(file_get_contents($configLocation), true)); -if (isset($options['s']) || isset($options['storename'])) { - $storeName = $options['s'] ?? $options['storename']; -} else { - $storeName = null; -} +$storeName = isset($options['s']) || isset($options['storename']) ? $options['s'] ?? $options['storename'] : null; -if (isset($options['t']) || isset($options['spec'])) { - $tableId = $options['t'] ?? $options['spec']; -} else { - $tableId = null; -} +$tableId = isset($options['t']) || isset($options['spec']) ? $options['t'] ?? $options['spec'] : null; -if (isset($options['i']) || isset($options['id'])) { - $id = $options['i'] ?? $options['id']; -} else { - $id = null; -} +$id = isset($options['i']) || isset($options['id']) ? $options['i'] ?? $options['id'] : null; $queue = null; if (isset($options['a']) || isset($options['async'])) { diff --git a/scripts/mongo/createViews.php b/scripts/mongo/createViews.php index 3537f2f2..2e9334f8 100644 --- a/scripts/mongo/createViews.php +++ b/scripts/mongo/createViews.php @@ -20,7 +20,7 @@ ] ); -function showUsage() +function showUsage(): void { $help = <<<'END' createViews.php @@ -44,7 +44,7 @@ function showUsage() echo $help; } -if (empty($options) || isset($options['h']) || isset($options['help']) +if ($options === [] || $options === false || isset($options['h']) || isset($options['help']) || (!isset($options['c']) && !isset($options['config'])) || (!isset($options['s']) && !isset($options['storename'])) ) { @@ -52,6 +52,7 @@ function showUsage() exit; } + $configLocation = $options['c'] ?? $options['config']; require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; @@ -63,13 +64,13 @@ function showUsage() * @param ITripodStat|null $stat * @param string $queue */ -function generateViews($id, $viewId, $storeName, $stat, $queue) +function generateViews($id, $viewId, $storeName, $stat, $queue): void { $viewSpec = Config::getInstance()->getViewSpecification($storeName, $viewId); if (array_key_exists('from', $viewSpec)) { Config::getInstance()->setMongoCursorTimeout(-1); - echo "Generating {$viewId}"; + echo 'Generating ' . $viewId; $tripod = new Driver($viewSpec['from'], $storeName, ['stat' => $stat]); $views = $tripod->getTripodViews(); if ($id) { @@ -87,23 +88,11 @@ function generateViews($id, $viewId, $storeName, $stat, $queue) Config::setConfig(json_decode(file_get_contents($configLocation), true)); -if (isset($options['s']) || isset($options['storename'])) { - $storeName = $options['s'] ?? $options['storename']; -} else { - $storeName = null; -} +$storeName = isset($options['s']) || isset($options['storename']) ? $options['s'] ?? $options['storename'] : null; -if (isset($options['v']) || isset($options['spec'])) { - $viewId = $options['v'] ?? $options['spec']; -} else { - $viewId = null; -} +$viewId = isset($options['v']) || isset($options['spec']) ? $options['v'] ?? $options['spec'] : null; -if (isset($options['i']) || isset($options['id'])) { - $id = $options['i'] ?? $options['id']; -} else { - $id = null; -} +$id = isset($options['i']) || isset($options['id']) ? $options['i'] ?? $options['id'] : null; $queue = null; if (isset($options['a']) || isset($options['async'])) { diff --git a/scripts/mongo/detectNamespaces.php b/scripts/mongo/detectNamespaces.php index ad3c9b93..5f48db6b 100644 --- a/scripts/mongo/detectNamespaces.php +++ b/scripts/mongo/detectNamespaces.php @@ -9,11 +9,12 @@ ini_set('memory_limit', '32M'); -if ($argc != 1) { +if ($argc !== 1) { echo "usage: php detectNamespaces.php < triples\n"; exit; } + array_shift($argv); $dummyDbConfig = [ @@ -51,16 +52,18 @@ $parts = preg_split('/\s/', $line); $subject = trim($parts[0], '><'); - if (($i % 2500) == 0) { + if ($i % 2500 === 0) { echo '.'; } - if (($i % 50000) == 0) { + + if ($i % 50000 === 0) { foreach ($objectNs as $key => $val) { if ($val < 5) { // flush unset($objectNs[$key]); } } + gc_collect_cycles(); echo 'F'; } @@ -76,12 +79,14 @@ if (array_key_exists($prefix, $config['namespaces'])) { $prefix .= uniqid(); } + $newNsConfig[$prefix] = $n; echo "\nFound ns {$n} suggest prefix {$prefix}"; $config['namespaces'] = array_merge($config['namespaces'], $newNsConfig); Config::setConfig($config); } } + $ns = $util->extractMissingObjectNs($triples); if (count($ns) > 0) { $newNsConfig = []; @@ -91,11 +96,13 @@ } else { $objectNs[$n] = 1; } + if ($objectNs[$n] > 500) { $prefix = $util->suggestPrefix($n); if (array_key_exists($prefix, $config['namespaces'])) { $prefix .= uniqid(); } + $newNsConfig[$prefix] = $n; echo "\nFound object ns {$n} occurs > 500 times, suggest prefix {$prefix}"; $config['namespaces'] = array_merge($config['namespaces'], $newNsConfig); @@ -107,6 +114,7 @@ $currentSubject = $subject; // reset current subject to next subject $triples = []; // reset triples } + $triples[] = $line; } @@ -114,10 +122,8 @@ /** * @param string $json - * - * @return string */ -function indent($json) +function indent($json): string { $result = ''; $pos = 0; @@ -132,12 +138,12 @@ function indent($json) $char = substr($json, $i, 1); // Are we inside a quoted string? - if ($char == '"' && $prevChar != '\\') { + if ($char === '"' && $prevChar !== '\\') { $outOfQuotes = !$outOfQuotes; // If this character is the end of an element, // output a new line and indent the next line. - } elseif (($char == '}' || $char == ']') && $outOfQuotes) { + } elseif (($char === '}' || $char === ']') && $outOfQuotes) { $result .= $newLine; $pos--; for ($j = 0; $j < $pos; $j++) { @@ -150,9 +156,9 @@ function indent($json) // If the last character was the beginning of an element, // output a new line and indent the next line. - if (($char == ',' || $char == '{' || $char == '[') && $outOfQuotes) { + if ((in_array($char, [',', '{', '['])) && $outOfQuotes) { $result .= $newLine; - if ($char == '{' || $char == '[') { + if ($char === '{' || $char === '[') { $pos++; } diff --git a/scripts/mongo/discoverUnnamespacedUris.php b/scripts/mongo/discoverUnnamespacedUris.php index 86c71458..04dccf8d 100644 --- a/scripts/mongo/discoverUnnamespacedUris.php +++ b/scripts/mongo/discoverUnnamespacedUris.php @@ -6,7 +6,7 @@ require_once __DIR__ . '/common.inc.php'; // Detects un-namespaced subjects or object uris in CBD collections of the target database. Optionally supply a base uri to match against that rather than all uris -if ($argc != 4 && $argc != 3) { +if ($argc !== 4 && $argc !== 3) { echo 'usage: php discoverUnnamespacedUris.php connStr database [baseUri]'; exit; @@ -27,10 +27,8 @@ /** * @param string $uri * @param string|null $baseUri - * - * @return bool */ -function isUnNamespaced($uri, $baseUri = null) +function isUnNamespaced($uri, $baseUri = null): bool { if ($baseUri == null) { return strpos($uri, 'http://') === 0 || strpos($uri, 'https://') === 0; @@ -44,17 +42,16 @@ function isUnNamespaced($uri, $baseUri = null) // @var \MongoDB\Collection $collection if (strpos($collectionInfo->getName(), 'CBD_') === 0) { // only process CBD_collections $collection = $db->selectCollection($collectionInfo->getName()); - echo "Checking out {$collectionInfo->getName()}\n"; + echo sprintf('Checking out %s%s', $collectionInfo->getName(), PHP_EOL); $count = 0; foreach ($collection->find() as $doc) { if (!isset($doc['_id']) || !isset($doc['_id']['r'])) { echo ' Illegal doc: no _id or missing _id.r'; - } else { - if (isUnNamespaced($doc['_id']['r'], $argv[2] ?? null)) { - echo " Un-namespaced subject: {$doc['_id']['r']}\n"; - $count++; - } + } elseif (isUnNamespaced($doc['_id']['r'], $argv[2] ?? null)) { + echo sprintf(' Un-namespaced subject: %s%s', $doc['_id']['r'], PHP_EOL); + $count++; } + foreach ($doc as $property => $value) { if (strpos($property, '_') === 0) { // ignore meta fields, _id, _version, _uts etc. continue; @@ -64,25 +61,30 @@ function isUnNamespaced($uri, $baseUri = null) // ignore, is a literal continue; } + if (isset($value['u'])) { if (isUnNamespaced($value['u'], $argv[2] ?? null)) { - echo " Un-namespaced object uri (single value): {$value['u']}\n"; + echo sprintf(' Un-namespaced object uri (single value): %s%s', $value['u'], PHP_EOL); $count++; } } else { foreach ($value as $v) { - if (isset($v['u'])) { - if (isUnNamespaced($v['u'], $argv[2] ?? null)) { - echo " Un-namespaced object uri (multiple value): {$v['u']}\n"; - $count++; - } + if (!isset($v['u'])) { + continue; + } + if (!isUnNamespaced($v['u'], $argv[2] ?? null)) { + continue; } + echo sprintf(' Un-namespaced object uri (multiple value): %s%s', $v['u'], PHP_EOL); + $count++; } } } } - $results[] = "{$collectionInfo->getName()} has {$count} un-namespaced uris"; - echo "Done with {$collectionInfo->getName()}\n"; + + $results[] = sprintf('%s has %d un-namespaced uris', $collectionInfo->getName(), $count); + echo sprintf('Done with %s%s', $collectionInfo->getName(), PHP_EOL); } } + echo "\n" . implode("\n", $results) . "\n"; diff --git a/scripts/mongo/ensureIndexes.php b/scripts/mongo/ensureIndexes.php index 2f9548a5..a4c57b97 100644 --- a/scripts/mongo/ensureIndexes.php +++ b/scripts/mongo/ensureIndexes.php @@ -8,17 +8,18 @@ require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; -if ($argc != 2 && $argc != 3 && $argc != 4) { +if (!in_array($argc, [2, 3, 4])) { echo "usage: php ensureIndexes.php tripodConfig.json [storeName] [forceReindex (default is false)] [background (default is true)]\n"; exit; } + array_shift($argv); Config::setConfig(json_decode(file_get_contents($argv[0]), true)); $storeName = $argv[1] ?? null; -$forceReindex = (isset($argv[2]) && ($argv[2] == 'true')) ? true : false; +$forceReindex = isset($argv[2]) && ($argv[2] == 'true'); $background = (isset($argv[3]) && ($argv[3] == 'false')) ? false : true; Config::getInstance()->setMongoCursorTimeout(-1); diff --git a/scripts/mongo/loadTriples.php b/scripts/mongo/loadTriples.php index 23563012..6d384191 100644 --- a/scripts/mongo/loadTriples.php +++ b/scripts/mongo/loadTriples.php @@ -9,16 +9,15 @@ require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; /** - * @param string $subject * @param string $podName * @param string $storeName */ -function load(TriplesUtil $loader, $subject, array $triples, array &$errors, $podName, $storeName) +function load(TriplesUtil $loader, string $subject, array $triples, array &$errors, $podName, $storeName): void { try { $loader->loadTriplesAbout($subject, $triples, $storeName, $podName); } catch (Exception $e) { - echo "Exception for subject {$subject} failed with message: " . $e->getMessage() . "\n"; + echo sprintf('Exception for subject %s failed with message: ', $subject) . $e->getMessage() . "\n"; $errors[] = $subject; } } @@ -26,11 +25,12 @@ function load(TriplesUtil $loader, $subject, array $triples, array &$errors, $po $timer = new Timer(); $timer->start(); -if ($argc != 4) { +if ($argc !== 4) { echo "usage: ./loadTriples.php storename podname tripodConfig.json < ntriplesdata\n"; exit; } + array_shift($argv); $storeName = $argv[0]; @@ -46,7 +46,7 @@ function load(TriplesUtil $loader, $subject, array $triples, array &$errors, $po while (($line = fgets(STDIN)) !== false) { $i++; - if (($i % 250000) == 0) { + if ($i % 250000 === 0) { echo 'Memory: ' . memory_get_usage() . "\n"; } @@ -54,13 +54,14 @@ function load(TriplesUtil $loader, $subject, array $triples, array &$errors, $po $parts = preg_split('/\s/', $line); $subject = trim($parts[0], '><'); - if (empty($currentSubject)) { // set for first iteration + if ($currentSubject === '' || $currentSubject === '0') { // set for first iteration $currentSubject = $subject; - } elseif ($currentSubject != $subject) { // once subject changes, we have all triples for that subject, flush to Mongo + } elseif ($currentSubject !== $subject) { // once subject changes, we have all triples for that subject, flush to Mongo load($loader, $currentSubject, $triples, $errors, $podName, $storeName); $currentSubject = $subject; // reset current subject to next subject $triples = []; // reset triples } + $triples[] = $line; } @@ -71,7 +72,7 @@ function load(TriplesUtil $loader, $subject, array $triples, array &$errors, $po echo 'This script ran in ' . $timer->result() . " milliseconds\n"; echo 'Processed ' . $i . ' triples'; -if (count($errors) > 0) { +if ($errors !== []) { echo 'Insert errors on ' . count($errors) . " subjects\n"; var_dump($errors); // todo: decide what to do with errors... } diff --git a/scripts/mongo/triplesToBSON.php b/scripts/mongo/triplesToBSON.php index 9c71d554..8f5ecd6e 100644 --- a/scripts/mongo/triplesToBSON.php +++ b/scripts/mongo/triplesToBSON.php @@ -7,7 +7,7 @@ require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; -if ($argc != 2) { +if ($argc !== 2) { echo "usage: ./triplesToBSON.php tripodconfig.json < ntriplesdata\n"; exit; @@ -29,11 +29,11 @@ $parts = preg_split('/\s/', $line); $subject = trim($parts[0], '><'); - if (empty($currentSubject)) { // set for first iteration + if ($currentSubject === '' || $currentSubject === '0') { // set for first iteration $currentSubject = $subject; } - if ($currentSubject != $subject) { // once subject changes, we have all triples for that subject, flush to Mongo + if ($currentSubject !== $subject) { // once subject changes, we have all triples for that subject, flush to Mongo echo json_encode($tu->getTArrayAbout($currentSubject, $triples, Config::getInstance()->getDefaultContextAlias())) . "\n"; $currentSubject = $subject; // reset current subject to next subject $triples = []; // reset triples diff --git a/scripts/mongo/validateConfig.php b/scripts/mongo/validateConfig.php index d378b1c6..d8561e43 100644 --- a/scripts/mongo/validateConfig.php +++ b/scripts/mongo/validateConfig.php @@ -12,7 +12,7 @@ ] ); -function showUsage() +function showUsage(): void { $help = <<<'END' validateConfig.php @@ -28,11 +28,12 @@ function showUsage() echo $help; } -if (empty($options) || isset($options['h']) || isset($options['help']) || (!isset($options['c']) && !isset($options['config']))) { +if ($options === [] || $options === false || isset($options['h']) || isset($options['help']) || (!isset($options['c']) && !isset($options['config']))) { showUsage(); exit; } + $configLocation = $options['c'] ?? $options['config']; require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; diff --git a/src/Config.php b/src/Config.php index ce54a47b..fa608afc 100644 --- a/src/Config.php +++ b/src/Config.php @@ -1,5 +1,7 @@ $config The Tripod config or serialized ITripodConfigSerializer array * * @return IConfigInstance */ @@ -19,12 +21,11 @@ public static function create(array $config) if (Config::getConfig() !== $config) { Config::setConfig($config); } + if (isset($config['class']) && class_exists($config['class'])) { - $tripodConfig = call_user_func([$config['class'], 'deserialize'], $config); - } else { - $tripodConfig = Mongo\Config::deserialize($config); + return call_user_func([$config['class'], 'deserialize'], $config); } - return $tripodConfig; + return Mongo\Config::deserialize($config); } } diff --git a/src/TripodStatFactory.php b/src/TripodStatFactory.php index d713cfc5..5a9a53db 100644 --- a/src/TripodStatFactory.php +++ b/src/TripodStatFactory.php @@ -1,5 +1,7 @@ $config */ public static function create(array $config = []) { diff --git a/src/classes/ChangeSet.php b/src/classes/ChangeSet.php index cde34d0b..c26cfafd 100644 --- a/src/classes/ChangeSet.php +++ b/src/classes/ChangeSet.php @@ -1,5 +1,7 @@ parse(false, $a[$rdf]); $a[$rdf] = $parser->getSimpleIndex(0); } elseif ( - is_array($a[$rdf]) - and isset($a[$rdf][0]) - and isset($a[$rdf][0]['s']) + is_array($a[$rdf]) && isset($a[$rdf][0]) && isset($a[$rdf][0]['s']) ) { // triples array /** @var \ARC2_RDFSerializer $ser */ $ser = \ARC2::getTurtleSerializer(); @@ -80,10 +91,12 @@ public function __construct(array $a) $parser->parse(false, $turtle); $a[$rdf] = $parser->getSimpleIndex(0); } + $nrdf = str_replace('_rdfxml', '', $rdf); $this->{$nrdf} = $a[$rdf]; } } + $this->__init(); } @@ -91,26 +104,18 @@ protected function __init() { $csIndex = []; $CSNS = 'http://purl.org/vocab/changeset/schema#'; - // Get the triples to be added - if (empty($this->before)) { - $additions = $this->after; - } else { - $additions = ExtendedGraph::diff($this->after, $this->before); - } + $additions = empty($this->before) ? $this->after : ExtendedGraph::diff($this->after, $this->before); + // Get the triples to be removed - if (empty($this->after)) { - $removals = $this->before; - } else { - $removals = ExtendedGraph::diff($this->before, $this->after); - } + $removals = empty($this->after) ? $this->before : ExtendedGraph::diff($this->before, $this->after); // remove etag triples foreach (['removals' => $removals, 'additions' => $additions] as $name => $graph) { foreach ($graph as $uri => $properties) { if (isset($properties['http://schemas.talis.com/2005/dir/schema#etag'])) { unset(${$name}[$uri]['http://schemas.talis.com/2005/dir/schema#etag']); - if (count(${$name}[$uri]) == 0) { + if (count(${$name}[$uri]) === 0) { unset(${$name}[$uri]); } } @@ -118,12 +123,12 @@ protected function __init() } // Get an array of all the subject uris - $subjectIndex = !empty($this->a['subjectOfChange']) ? [$this->a['subjectOfChange']] : array_unique(array_merge(array_keys($additions), array_keys($removals))); + $subjectIndex = empty($this->a['subjectOfChange']) ? array_unique(array_merge(array_keys($additions), array_keys($removals))) : [$this->a['subjectOfChange']]; // Get the metadata for all the changesets - $date = (!empty($this->a['createdDate'])) ? $this->a['createdDate'] : date(DATE_ATOM); - $creator = (!empty($this->a['creatorName'])) ? $this->a['creatorName'] : 'Moriarty ChangeSet Builder'; - $reason = (!empty($this->a['changeReason'])) ? $this->a['changeReason'] : 'Change using Moriarty ChangeSet Builder'; + $date = (empty($this->a['createdDate'])) ? date(DATE_ATOM) : $this->a['createdDate']; + $creator = (empty($this->a['creatorName'])) ? 'Moriarty ChangeSet Builder' : $this->a['creatorName']; + $reason = (empty($this->a['changeReason'])) ? 'Change using Moriarty ChangeSet Builder' : $this->a['changeReason']; $csCount = 0; foreach ($subjectIndex as $subjectOfChange) { @@ -142,8 +147,10 @@ protected function __init() $this->addT($csID, $p, $objs); } } + $csCount++; } + /*iterate through the triples to be added, reifying them, and linking to the Statements from the appropriate changeset @@ -191,14 +198,14 @@ protected function __init() * * @author Keith */ - public function addT($s, $p, $o, $o_type = 'bnode') + public function addT($s, $p, $o, $o_type = 'bnode'): void { - if (is_array($o) and isset($o[0]['type'])) { + if (is_array($o) && isset($o[0]['type'])) { foreach ($o as $obj) { $this->addT($s, $p, $obj); } } else { - $obj = !is_array($o) ? ['value' => $o, 'type' => $o_type] : $o; + $obj = is_array($o) ? $o : ['value' => $o, 'type' => $o_type]; $this->_index[$s][$p][] = $obj; } } @@ -222,15 +229,11 @@ public function to_rdfxml() return $this->toRDFXML(); } - /** - * @return bool - */ - public function has_changes() + public function has_changes(): bool { foreach ($this->_index as $properties) { if ( - isset($properties['http://purl.org/vocab/changeset/schema#addition']) - or isset($properties['http://purl.org/vocab/changeset/schema#removal']) + isset($properties['http://purl.org/vocab/changeset/schema#addition']) || isset($properties['http://purl.org/vocab/changeset/schema#removal']) ) { return true; } @@ -241,10 +244,8 @@ public function has_changes() /** * Returns a unique array of the subjects of change in this changeset. - * - * @return array */ - public function get_subjects_of_change() + public function get_subjects_of_change(): array { $subjects = []; diff --git a/src/classes/ExtendedGraph.php b/src/classes/ExtendedGraph.php index 562b07f6..63015bc0 100644 --- a/src/classes/ExtendedGraph.php +++ b/src/classes/ExtendedGraph.php @@ -1,5 +1,7 @@ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', @@ -95,7 +104,7 @@ public function __destruct() * @param string $prefix the namespace prefix to associate with the URI * @param string $uri the URI to associate with the prefix */ - public function set_namespace_mapping($prefix, $uri) + public function set_namespace_mapping($prefix, $uri): void { $this->_labeller->set_namespace_mapping($prefix, $uri); } @@ -137,7 +146,7 @@ public function get_prefix($ns) /** * @param string $p */ - public function add_labelling_property($p) + public function add_labelling_property($p): void { $this->_labeller->add_labelling_property($p); } @@ -147,9 +156,9 @@ public function add_labelling_property($p) * * @param string $resource a URI or blank node identifier (prefixed with _: e.g. _:name) * - * @return array an associative array with two keys: 'type' and 'value'. Type is either bnode or uri + * @return array an associative array with two keys: 'type' and 'value'. Type is either bnode or uri */ - public function make_resource_array($resource) + public function make_resource_array($resource): array { $resource_type = strpos($resource, '_:') === 0 ? 'bnode' : 'uri'; @@ -192,6 +201,7 @@ public function add_literal_triple($s, $p, $o, $lang = null, $dt = null) if ($lang != null) { $o_info['lang'] = $lang; } + if ($dt != null) { $o_info['datatype'] = $dt; } @@ -291,22 +301,20 @@ public function to_json() * * @return string a HTML version of the graph */ - public function to_html($s = null, $guess_labels = true) + public function to_html($s = null, $guess_labels = true): string { $h = ''; if ($s) { if (is_array($s)) { $subjects = array_intersect($s, $this->get_subjects()); - if (count($subjects) == 0) { + if ($subjects === []) { return ''; } + } elseif (array_key_exists($s, $this->_index)) { + $subjects = [$s]; } else { - if (array_key_exists($s, $this->_index)) { - $subjects = [$s]; - } else { - return ''; - } + return ''; } } else { $subjects = $this->get_subjects(); @@ -317,6 +325,7 @@ public function to_html($s = null, $guess_labels = true) if (count($subjects) > 1) { $h .= '

' . htmlspecialchars($this->get_label($subject)) . '

' . "\n"; } + $h .= '' . "\n"; $properties = $this->get_subject_properties($subject, true); @@ -326,10 +335,12 @@ public function to_html($s = null, $guess_labels = true) foreach ($properties as $p) { $h .= ''; $h .= ''; $h .= '' . "\n"; } @@ -355,6 +367,7 @@ public function to_html($s = null, $guess_labels = true) if (!isset($backlinks[$rev_subj_p])) { $backlinks[$rev_subj_p] = []; } + $backlinks[$rev_subj_p][] = $rev_subj; } } @@ -364,7 +377,8 @@ public function to_html($s = null, $guess_labels = true) foreach ($backlinks as $backlink_p => $backlink_values) { $h .= ''; $h .= ''; $h .= '' . "\n"; } @@ -470,7 +485,7 @@ public function get_first_resource($s, $p, $default = null) * @param string $p the predicate URI of the triple * @param string $o the object of the triple, either a URI or a blank node in the format _:name */ - public function remove_resource_triple($s, $p, $o) + public function remove_resource_triple($s, $p, $o): void { // Already removed if (!isset($this->_index[$s]) || !isset($this->_index[$s][$p])) { @@ -483,11 +498,11 @@ public function remove_resource_triple($s, $p, $o) } } - if (count($this->_index[$s][$p]) == 0) { + if (count($this->_index[$s][$p]) === 0) { unset($this->_index[$s][$p]); } - if (count($this->_index[$s]) == 0) { + if (count($this->_index[$s]) === 0) { unset($this->_index[$s]); } } @@ -497,7 +512,7 @@ public function remove_resource_triple($s, $p, $o) * @param string $p * @param string $o */ - public function remove_literal_triple($s, $p, $o) + public function remove_literal_triple($s, $p, $o): void { // Already removed if (!isset($this->_index[$s]) || !isset($this->_index[$s][$p])) { @@ -510,11 +525,11 @@ public function remove_literal_triple($s, $p, $o) } } - if (count($this->_index[$s][$p]) == 0) { + if (count($this->_index[$s][$p]) === 0) { unset($this->_index[$s][$p]); } - if (count($this->_index[$s]) == 0) { + if (count($this->_index[$s]) === 0) { unset($this->_index[$s]); } } @@ -524,7 +539,7 @@ public function remove_literal_triple($s, $p, $o) * * @param string $s the subject of the triple, either a URI or a blank node in the format _:name */ - public function remove_triples_about($s) + public function remove_triples_about($s): void { unset($this->_index[$s]); } @@ -535,7 +550,7 @@ public function remove_triples_about($s) * @param string $rdfxml the RDF/XML to parse * @param string $base the base URI against which relative URIs in the RDF/XML document will be resolved */ - public function from_rdfxml($rdfxml, $base = '') + public function from_rdfxml($rdfxml, $base = ''): void { if ($rdfxml) { $this->remove_all_triples(); @@ -550,7 +565,7 @@ public function from_rdfxml($rdfxml, $base = '') * * @param string $json the JSON to parse */ - public function from_json($json) + public function from_json($json): void { if ($json) { $this->remove_all_triples(); @@ -568,7 +583,7 @@ public function from_json($json) * * @param string $json the JSON to parse */ - public function add_json($json) + public function add_json($json): void { if ($json) { $json_index = json_decode($json, true); @@ -594,7 +609,7 @@ public function get_parser_errors() * * @author Keith Alexander */ - public function add_rdf($rdf, $base = '') + public function add_rdf($rdf, $base = ''): void { $trimRdf = trim($rdf); if ($trimRdf[0] == '{') { // lazy is-this-json assessment - might be better to try json_decode - but more costly @@ -608,6 +623,7 @@ public function add_rdf($rdf, $base = '') if (!empty($errors)) { $this->parser_errors[] = $errors; } + $triples = $parser->getTriples(); $this->_add_arc2_triple_list($triples); unset($parser); @@ -620,7 +636,7 @@ public function add_rdf($rdf, $base = '') * @param string $rdfxml the RDF/XML to parse * @param string $base the base URI against which relative URIs in the RDF/XML document will be resolved */ - public function add_rdfxml($rdfxml, $base = '') + public function add_rdfxml($rdfxml, $base = ''): void { if ($rdfxml) { /** @var \ARC2_RDFXMLParser $parser */ @@ -640,7 +656,7 @@ public function add_rdfxml($rdfxml, $base = '') * @param string $turtle the Turtle to parse * @param string $base the base URI against which relative URIs in the Turtle document will be resolved */ - public function from_turtle($turtle, $base = '') + public function from_turtle($turtle, $base = ''): void { if ($turtle) { $this->remove_all_triples(); @@ -656,7 +672,7 @@ public function from_turtle($turtle, $base = '') * @param string $turtle the Turtle to parse * @param string $base the base URI against which relative URIs in the Turtle document will be resolved */ - public function add_turtle($turtle, $base = '') + public function add_turtle($turtle, $base = ''): void { if ($turtle) { /** @var \ARC2_TurtleParser $parser */ @@ -674,7 +690,7 @@ public function add_turtle($turtle, $base = '') * @param string $html the HTML containing RDFa to parse * @param string $base the base URI against which relative URIs in the Turtle document will be resolved */ - public function from_rdfa($html, $base = '') + public function from_rdfa($html, $base = ''): void { if ($html) { $this->remove_all_triples(); @@ -688,7 +704,7 @@ public function from_rdfa($html, $base = '') * @param string $html the HTML containing RDFa to parse * @param string $base the base URI against which relative URIs in the Turtle document will be resolved */ - public function add_rdfa($html, $base = '') + public function add_rdfa($html, $base = ''): void { if ($html) { /** @var \ARC2_SemHTMLParser $parser */ @@ -734,14 +750,12 @@ public function add_graph(ExtendedGraph $g) * * @return bool true if the triple exists in the graph, false otherwise */ - public function has_resource_triple($s, $p, $o) + public function has_resource_triple($s, $p, $o): bool { - if (array_key_exists($s, $this->_index)) { - if (array_key_exists($p, $this->_index[$s])) { - foreach ($this->_index[$s][$p] as $value) { - if (($value['type'] == 'uri' || $value['type'] == 'bnode') && $value['value'] === $o) { - return true; - } + if (array_key_exists($s, $this->_index) && array_key_exists($p, $this->_index[$s])) { + foreach ($this->_index[$s][$p] as $value) { + if (($value['type'] == 'uri' || $value['type'] == 'bnode') && $value['value'] === $o) { + return true; } } } @@ -762,20 +776,18 @@ public function has_resource_triple($s, $p, $o) */ public function has_literal_triple($s, $p, $o, $lang = null, $dt = null) { - if (array_key_exists($s, $this->_index)) { - if (array_key_exists($p, $this->_index[$s])) { - foreach ($this->_index[$s][$p] as $value) { - if (($value['type'] == 'literal') && $value['value'] === $o) { - if ($lang !== null) { - return array_key_exists('lang', $value) && $value['lang'] === $lang; - } - - if ($dt !== null) { - return array_key_exists('datatype', $value) && $value['datatype'] === $dt; - } + if (array_key_exists($s, $this->_index) && array_key_exists($p, $this->_index[$s])) { + foreach ($this->_index[$s][$p] as $value) { + if (($value['type'] == 'literal') && $value['value'] === $o) { + if ($lang !== null) { + return array_key_exists('lang', $value) && $value['lang'] === $lang; + } - return true; + if ($dt !== null) { + return array_key_exists('datatype', $value) && $value['datatype'] === $dt; } + + return true; } } } @@ -791,15 +803,13 @@ public function has_literal_triple($s, $p, $o, $lang = null, $dt = null) * * @return array list of URIs and blank nodes that are the objects of triples with the supplied subject and predicate */ - public function get_resource_triple_values($s, $p) + public function get_resource_triple_values($s, $p): array { $values = []; - if (array_key_exists($s, $this->_index)) { - if (array_key_exists($p, $this->_index[$s])) { - foreach ($this->_index[$s][$p] as $value) { - if ($value['type'] == 'uri' || $value['type'] == 'bnode') { - $values[] = $value['value']; - } + if (array_key_exists($s, $this->_index) && array_key_exists($p, $this->_index[$s])) { + foreach ($this->_index[$s][$p] as $value) { + if ($value['type'] == 'uri' || $value['type'] == 'bnode') { + $values[] = $value['value']; } } } @@ -815,7 +825,7 @@ public function get_resource_triple_values($s, $p) * * @return array list of literals that are the objects of triples with the supplied subject and predicate */ - public function get_literal_triple_values($s, $p) + public function get_literal_triple_values($s, $p): array { $values = []; if (array_key_exists($s, $this->_index)) { @@ -849,12 +859,13 @@ public function get_literal_triple_values($s, $p) * * @return array list of values of triples with the supplied subject and predicate */ - public function get_subject_property_values($s, $p) + public function get_subject_property_values($s, $p): array { $values = []; if (!is_array($p)) { $p = [$p]; } + if (array_key_exists($s, $this->_index)) { foreach ($p as $pinst) { if (array_key_exists($pinst, $this->_index[$s])) { @@ -875,7 +886,7 @@ public function get_subject_property_values($s, $p) * * @return ExtendedGraph triples with the supplied subject */ - public function get_subject_subgraph($s) + public function get_subject_subgraph($s): \Tripod\ExtendedGraph { $sub = new ExtendedGraph(); if (array_key_exists($s, $this->_index)) { @@ -887,10 +898,8 @@ public function get_subject_subgraph($s) /** * Fetch an array of all the subjects. - * - * @return array */ - public function get_subjects() + public function get_subjects(): array { return array_keys($this->_index); } @@ -912,10 +921,8 @@ public function get_subjects_of_type($t) * * @param string $p the predicate to match * @param string $o the resource object to match - * - * @return array */ - public function get_subjects_where_resource($p, $o) + public function get_subjects_where_resource($p, $o): array { return array_merge($this->get_subjects_where($p, $o, 'uri'), $this->get_subjects_where($p, $o, 'bnode')); } @@ -941,7 +948,7 @@ public function get_subjects_where_literal($p, $o) * * @return array list of property URIs */ - public function get_subject_properties($s, $distinct = true) + public function get_subject_properties($s, $distinct = true): array { $values = []; if (array_key_exists($s, $this->_index)) { @@ -949,7 +956,8 @@ public function get_subject_properties($s, $distinct = true) if ($distinct) { $values[] = $prop; } else { - for ($i = 0; $i < count($prop_values); $i++) { + $counter = count($prop_values); + for ($i = 0; $i < $counter; $i++) { $values[] = $prop; } } @@ -983,7 +991,7 @@ public function subject_has_property($s, $p) * * @return bool true if the graph contains any triples with the specified subject, false otherwise */ - public function has_triples_about($s) + public function has_triples_about($s): bool { return array_key_exists($s, $this->_index); } @@ -994,7 +1002,7 @@ public function has_triples_about($s) * @param string $s the subject of the triple, either a URI or a blank node in the format _:name * @param string $p the predicate URI of the triple */ - public function remove_property_values($s, $p) + public function remove_property_values($s, $p): void { unset($this->_index[$s][$p]); } @@ -1002,7 +1010,7 @@ public function remove_property_values($s, $p) /** * Clears all triples out of the graph. */ - public function remove_all_triples() + public function remove_all_triples(): void { $this->_index = []; } @@ -1012,9 +1020,9 @@ public function remove_all_triples() * * @return bool true if the graph contains no triples, false otherwise */ - public function is_empty() + public function is_empty(): bool { - return count($this->_index) == 0; + return count($this->_index) === 0; } /** @@ -1042,11 +1050,9 @@ public function get_inverse_label($resource_uri, $capitalize = false, $use_qname } /** - * @param string $nodeID_prefix - * - * @return array + * @param array $resources */ - public function reify(array $resources, $nodeID_prefix = 'Statement') + public function reify(array $resources, string $nodeID_prefix = 'Statement'): array { $RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; $reified = []; @@ -1054,9 +1060,10 @@ public function reify(array $resources, $nodeID_prefix = 'Statement') foreach ($resources as $uri => $properties) { foreach ($properties as $property => $objects) { foreach ($objects as $object) { - while (!isset($statement_nodeID) or isset($resources[$statement_nodeID]) or isset($reified[$statement_nodeID])) { + while (!isset($statement_nodeID) || isset($resources[$statement_nodeID]) || isset($reified[$statement_nodeID])) { $statement_nodeID = '_:' . $nodeID_prefix . ($statement_no++); } + $reified[$statement_nodeID] = [ $RDF . 'type' => [ ['type' => 'uri', 'value' => $RDF . 'Statement'], @@ -1078,20 +1085,20 @@ public function reify(array $resources, $nodeID_prefix = 'Statement') * * @param array1, array2, [array3, ...] * - * @return array * * @author Keith */ - public function diff() + public function diff(...$indices): array { - $indices = func_get_args(); - if (count($indices) == 1) { + if (count($indices) === 1) { array_unshift($indices, $this->_index); } + $base = array_shift($indices); if (count($base) === 0) { return []; } + $diff = []; foreach ($base as $base_uri => $base_ps) { @@ -1112,6 +1119,7 @@ public function diff() foreach ($base_p_values as &$v) { ksort($v); } + if (!in_array($base_o, $base_p_values, true)) { $diff[$base_uri][$base_p][] = $base_o; } @@ -1135,11 +1143,10 @@ public function diff() * * @author Keith */ - public function merge() + public function merge(...$indices) { $old_bnodeids = []; - $indices = func_get_args(); - if (count($indices) == 1) { + if (count($indices) === 1) { array_unshift($indices, $this->_index); } @@ -1153,9 +1160,7 @@ public function merge() $old_id = $uri; $count = 1; - while (isset($current[$uri]) - or ($old_id != $uri and isset($newGraph[$uri])) - or isset($old_bnodeids[$uri]) + while (isset($current[$uri]) || $old_id != $uri && isset($newGraph[$uri]) || isset($old_bnodeids[$uri]) ) { $uri .= $count++; } @@ -1177,9 +1182,7 @@ public function merge() } else { // bnode hasn't been transposed $old_bnode_id = $bnode; $count = 1; - while (isset($current[$bnode]) - or ($object['value'] != $bnode and isset($newGraph[$bnode])) - or isset($old_bnodeids[$uri]) + while (isset($current[$bnode]) || $object['value'] != $bnode && isset($newGraph[$bnode]) || isset($old_bnodeids[$uri]) ) { $bnode .= $count++; } @@ -1187,11 +1190,12 @@ public function merge() if ($old_bnode_id != $bnode) { $old_bnodeids[$old_bnode_id] = $bnode; } + $object['value'] = $bnode; } } - if (!isset($current[$uri][$property]) or !in_array($object, $current[$uri][$property])) { + if (!isset($current[$uri][$property]) || !in_array($object, $current[$uri][$property])) { $current[$uri][$property][] = $object; } } @@ -1207,7 +1211,7 @@ public function merge() * @param string $look_for * @param string $replace_with */ - public function replace_resource($look_for, $replace_with) + public function replace_resource($look_for, $replace_with): void { $remove_list_resources = []; $remove_list_literals = []; @@ -1219,37 +1223,31 @@ public function replace_resource($look_for, $replace_with) if ($p == $look_for) { foreach ($o_list as $o_info) { if ($o_info['type'] == 'literal') { - $lang = array_key_exists('lang', $o_info) ? $o_info['lang'] : null; - $dt = array_key_exists('datatype', $o_info) ? $o_info['datatype'] : null; - + $lang = $o_info['lang'] ?? null; + $dt = $o_info['datatype'] ?? null; $remove_list_literals[] = [$look_for, $look_for, $o_info['value']]; $add_list_literals[] = [$replace_with, $replace_with, $o_info['value'], $lang, $dt]; + } elseif ($o_info['value'] == $look_for) { + $remove_list_resources[] = [$look_for, $look_for, $look_for]; + $add_list_resources[] = [$replace_with, $replace_with, $replace_with]; } else { - if ($o_info['value'] == $look_for) { - $remove_list_resources[] = [$look_for, $look_for, $look_for]; - $add_list_resources[] = [$replace_with, $replace_with, $replace_with]; - } else { - $remove_list_resources[] = [$look_for, $look_for, $o_info['value']]; - $add_list_resources[] = [$replace_with, $replace_with, $o_info['value']]; - } + $remove_list_resources[] = [$look_for, $look_for, $o_info['value']]; + $add_list_resources[] = [$replace_with, $replace_with, $o_info['value']]; } } } else { foreach ($o_list as $o_info) { if ($o_info['type'] == 'literal') { - $lang = array_key_exists('lang', $o_info) ? $o_info['lang'] : null; - $dt = array_key_exists('datatype', $o_info) ? $o_info['datatype'] : null; - + $lang = $o_info['lang'] ?? null; + $dt = $o_info['datatype'] ?? null; $remove_list_literals[] = [$look_for, $p, $o_info['value']]; $add_list_literals[] = [$replace_with, $p, $o_info['value'], $lang, $dt]; + } elseif ($o_info['value'] == $look_for) { + $remove_list_resources[] = [$look_for, $p, $look_for]; + $add_list_resources[] = [$replace_with, $p, $replace_with]; } else { - if ($o_info['value'] == $look_for) { - $remove_list_resources[] = [$look_for, $p, $look_for]; - $add_list_resources[] = [$replace_with, $p, $replace_with]; - } else { - $remove_list_resources[] = [$look_for, $p, $o_info['value']]; - $add_list_resources[] = [$replace_with, $p, $o_info['value']]; - } + $remove_list_resources[] = [$look_for, $p, $o_info['value']]; + $add_list_resources[] = [$replace_with, $p, $o_info['value']]; } } } @@ -1259,19 +1257,16 @@ public function replace_resource($look_for, $replace_with) if ($p == $look_for) { foreach ($o_list as $o_info) { if ($o_info['type'] == 'literal') { - $lang = array_key_exists('lang', $o_info) ? $o_info['lang'] : null; - $dt = array_key_exists('datatype', $o_info) ? $o_info['datatype'] : null; - + $lang = $o_info['lang'] ?? null; + $dt = $o_info['datatype'] ?? null; $remove_list_literals[] = [$s, $look_for, $o_info['value']]; $add_list_literals[] = [$s, $replace_with, $o_info['value'], $lang, $dt]; + } elseif ($o_info['value'] == $look_for) { + $remove_list_resources[] = [$s, $look_for, $look_for]; + $add_list_resources[] = [$s, $replace_with, $replace_with]; } else { - if ($o_info['value'] == $look_for) { - $remove_list_resources[] = [$s, $look_for, $look_for]; - $add_list_resources[] = [$s, $replace_with, $replace_with]; - } else { - $remove_list_resources[] = [$s, $look_for, $o_info['value']]; - $add_list_resources[] = [$s, $replace_with, $o_info['value']]; - } + $remove_list_resources[] = [$s, $look_for, $o_info['value']]; + $add_list_resources[] = [$s, $replace_with, $o_info['value']]; } } } else { @@ -1289,6 +1284,7 @@ public function replace_resource($look_for, $replace_with) foreach ($remove_list_resources as $t) { $this->remove_resource_triple($t[0], $t[1], $t[2]); } + foreach ($add_list_resources as $t) { $this->add_resource_triple($t[0], $t[1], $t[2]); } @@ -1296,6 +1292,7 @@ public function replace_resource($look_for, $replace_with) foreach ($remove_list_literals as $t) { $this->remove_literal_triple($t[0], $t[1], $t[2]); } + foreach ($add_list_literals as $t) { $this->add_literal_triple($t[0], $t[1], $t[2], $t[3], $t[4]); } @@ -1303,13 +1300,11 @@ public function replace_resource($look_for, $replace_with) /** * @param string $listUri - * - * @return array */ - public function get_list_values($listUri) + public function get_list_values($listUri): array { $array = []; - while (!empty($listUri) and $listUri != RDF_NIL) { + while (!empty($listUri) && $listUri != RDF_NIL) { $array[] = $this->get_first_resource($listUri, RDF_FIRST); $listUri = $this->get_first_resource($listUri, RDF_REST); } @@ -1317,7 +1312,10 @@ public function get_list_values($listUri) return $array; } - public static function initProperties(array $properties) + /** + * @param array $properties + */ + public static function initProperties(array $properties): void { if (array_key_exists('labelProperties', $properties)) { self::$labelProperties = $properties['labelProperties']; @@ -1330,7 +1328,7 @@ public static function initProperties(array $properties) * @param string $uri1 * @param string $uri2 */ - public function replace_uris($uri1, $uri2) + public function replace_uris($uri1, $uri2): void { $index = $this->get_index(); if (isset($index[$uri1])) { @@ -1345,13 +1343,15 @@ public function replace_uris($uri1, $uri2) $property = $uri2; unset($index[$uri][$uri1]); } + foreach ($objects as $i => $object) { - if ($object['value'] == $uri1 and $object['type'] !== 'literal') { + if ($object['value'] == $uri1 && $object['type'] !== 'literal') { $index[$uri][$property][$i]['value'] = $uri2; } } } } + $this->_index = $index; } @@ -1359,10 +1359,8 @@ public function replace_uris($uri1, $uri2) * @param string|null $s * @param string|null $p * @param string|null $o - * - * @return int */ - public function get_triple_count($s = null, $p = null, $o = null) + public function get_triple_count($s = null, $p = null, $o = null): int { $index = $this->get_index(); @@ -1394,7 +1392,7 @@ public function get_triple_count($s = null, $p = null, $o = null) * * @return array the resource values found */ - public function get_resources() + public function get_resources(): array { $resources = []; $subjects = $this->get_subjects(); @@ -1413,7 +1411,7 @@ public function get_resources() * * @return array the resource values found */ - public function get_resources_for_subject($s) + public function get_resources_for_subject($s): array { $resources = []; if (array_key_exists($s, $this->_index)) { @@ -1432,7 +1430,7 @@ public function get_resources_for_subject($s) /** * @param string $p */ - public function remove_properties($p) + public function remove_properties($p): void { foreach ($this->get_subjects() as $s) { $this->remove_property_values($s, $p); @@ -1441,10 +1439,8 @@ public function remove_properties($p) /** * @param string $p - * - * @return array */ - public function get_resource_properties($p) + public function get_resource_properties($p): array { $resources = []; foreach ($this->get_subjects() as $s) { @@ -1458,10 +1454,8 @@ public function get_resource_properties($p) /** * @param string $p * @param string $o - * - * @return array */ - public function get_subjects_with_property_value($p, $o) + public function get_subjects_with_property_value($p, $o): array { $subjects = []; foreach ($this->get_subjects() as $s) { @@ -1475,10 +1469,8 @@ public function get_subjects_with_property_value($p, $o) /** * @param string $sequenceUri - * - * @return array */ - public function get_sequence_values($sequenceUri) + public function get_sequence_values($sequenceUri): array { $triples = $this->get_index(); $properties = []; @@ -1511,10 +1503,8 @@ public function get_sequence_values($sequenceUri) /** * @param string $sequenceUri - * - * @return int */ - public function get_next_sequence($sequenceUri) + public function get_next_sequence($sequenceUri): int { $values = $this->get_sequence_values($sequenceUri); @@ -1525,7 +1515,7 @@ public function get_next_sequence($sequenceUri) * @param string $s * @param string $o */ - public function add_literal_to_sequence($s, $o) + public function add_literal_to_sequence($s, $o): void { $this->add_to_sequence($s, $o, 'literal'); } @@ -1536,7 +1526,7 @@ public function add_literal_to_sequence($s, $o) * @param string $sequenceUri * @param string $resourceValue */ - public function remove_resource_from_sequence($sequenceUri, $resourceValue) + public function remove_resource_from_sequence($sequenceUri, $resourceValue): void { $sequenceProperties = $this->get_subject_properties($sequenceUri); $sequenceValues = $this->get_sequence_values($sequenceUri); @@ -1561,7 +1551,7 @@ public function remove_resource_from_sequence($sequenceUri, $resourceValue) * @param string $s * @param string $o */ - public function add_resource_to_sequence($s, $o) + public function add_resource_to_sequence($s, $o): void { $this->add_to_sequence($s, $o); } @@ -1571,7 +1561,7 @@ public function add_resource_to_sequence($s, $o) * @param string $o * @param int $position */ - public function add_resource_to_sequence_in_position($s, $o, $position) + public function add_resource_to_sequence_in_position($s, $o, $position): void { $sequenceValues = $this->get_sequence_values($s); @@ -1598,10 +1588,8 @@ public function add_resource_to_sequence_in_position($s, $o, $position) * @param string $p * @param string $oOldValue * @param string $oNewValue - * - * @return bool */ - public function replace_literal_triple($s, $p, $oOldValue, $oNewValue) + public function replace_literal_triple($s, $p, $oOldValue, $oNewValue): bool { if ($this->has_literal_triple($s, $p, $oOldValue)) { $this->remove_literal_triple($s, $p, $oOldValue); @@ -1618,11 +1606,12 @@ public function replace_literal_triple($s, $p, $oOldValue, $oNewValue) * @param string $p * @param string $o */ - public function replace_resource_triples($s, $p, $o) + public function replace_resource_triples($s, $p, $o): void { if ($this->subject_has_property($s, $p)) { $this->remove_property_values($s, $p); } + if (!empty($o)) { $this->add_resource_triple($s, $p, $o); } @@ -1633,11 +1622,12 @@ public function replace_resource_triples($s, $p, $o) * @param string $p * @param string $o */ - public function replace_literal_triples($s, $p, $o) + public function replace_literal_triples($s, $p, $o): void { if ($this->subject_has_property($s, $p)) { $this->remove_property_values($s, $p); } + if (!empty($o)) { $this->add_literal_triple($s, $p, $o); } @@ -1655,9 +1645,11 @@ public function get_label_for_uri($uri) if (!isset($this->_index[$uri])) { return ''; } + if (!isset(self::$labelProperties)) { throw new Exception('Please initialise ExtendedGraph::$labelProperties'); } + foreach (self::$labelProperties as $p) { if (isset($this->_index[$uri][$p])) { return $this->_index[$uri][$p][0]['value']; @@ -1667,10 +1659,7 @@ public function get_label_for_uri($uri) return ''; } - /** - * @return bool - */ - public function is_equal_to(ExtendedGraph $otherGraph) + public function is_equal_to(ExtendedGraph $otherGraph): bool { $diffThisAndThat = $this->diff($this->get_index(), $otherGraph->get_index()); $diffThatAndThis = $this->diff($otherGraph->get_index(), $this->get_index()); @@ -1681,7 +1670,7 @@ public function is_equal_to(ExtendedGraph $otherGraph) /** * @param string $type */ - public function remove_subjects_of_type($type) + public function remove_subjects_of_type($type): void { $subjects = $this->get_subjects_of_type($type); foreach ($subjects as $s) { @@ -1689,7 +1678,7 @@ public function remove_subjects_of_type($type) } } - public function from_graph(ExtendedGraph $graph) + public function from_graph(ExtendedGraph $graph): void { if ($graph) { $this->remove_all_triples(); @@ -1705,43 +1694,30 @@ public function from_graph(ExtendedGraph $graph) * which was not type-checked. * * @param string $value - * - * @return bool */ - protected function isValidLiteral($value) + protected function isValidLiteral($value): bool { - if (!is_scalar($value)) { - return false; - } - - return true; + return is_scalar($value); } /** * Check if a triple value is valid. * * @param string $value - * - * @return bool */ - protected function isValidResource($value) + protected function isValidResource($value): bool { - if (!is_string($value) || empty($value)) { - return false; - } - - return true; + return is_string($value) && ($value !== '' && $value !== '0'); } /** * @param string $s * @param string $p * - * @return bool * * @throws Exception */ - private function _add_triple($s, $p, array $o_info) + private function _add_triple($s, $p, array $o_info): bool { // The value $o should already have been validated by this point // It's validation differs depending on whether it is a literal or resource @@ -1749,20 +1725,24 @@ private function _add_triple($s, $p, array $o_info) if (!$this->isValidResource($s)) { throw new Exception('The subject is invalid'); } + if (!$this->isValidResource($p)) { throw new Exception('The predicate is invalid'); } + if (!isset($this->_index[$s])) { $this->_index[$s] = []; $this->_index[$s][$p] = [$o_info]; return true; } + if (!isset($this->_index[$s][$p])) { $this->_index[$s][$p] = [$o_info]; return true; } + if (!in_array($o_info, $this->_index[$s][$p])) { $this->_index[$s][$p][] = $o_info; @@ -1775,12 +1755,12 @@ private function _add_triple($s, $p, array $o_info) /** * @param array $triples */ - private function _add_arc2_triple_list(&$triples) + private function _add_arc2_triple_list(&$triples): void { $bnode_index = []; // We can safely preserve bnode labels if the graph is empty, otherwise we need to rewrite them - $rewrite_bnode_labels = $this->is_empty() ? false : true; + $rewrite_bnode_labels = !$this->is_empty(); foreach ($triples as $t) { $obj = []; @@ -1789,6 +1769,7 @@ private function _add_arc2_triple_list(&$triples) if (!array_key_exists($t['o'], $bnode_index)) { $bnode_index[$t['o']] = uniqid('_:mor'); } + $obj['value'] = $bnode_index[$t['o']]; } else { $obj['value'] = $t['o']; @@ -1798,15 +1779,13 @@ private function _add_arc2_triple_list(&$triples) if (!array_key_exists($t['s'], $bnode_index)) { $bnode_index[$t['s']] = uniqid('_:mor'); } + $t['s'] = $bnode_index[$t['s']]; } if ($t['o_type'] === 'iri') { $obj['type'] = 'uri'; - } elseif ($t['o_type'] === 'literal1' - || $t['o_type'] === 'literal2' - || $t['o_type'] === 'long_literal1' - || $t['o_type'] === 'long_literal2' + } elseif (in_array($t['o_type'], ['literal1', 'literal2', 'long_literal1', 'long_literal2'], true) ) { $obj['type'] = 'literal'; } else { @@ -1819,6 +1798,7 @@ private function _add_arc2_triple_list(&$triples) } elseif (isset($t['o_datatype']) && $t['o_datatype']) { $obj['datatype'] = $t['o_datatype']; } + if (isset($t['o_lang']) && $t['o_lang']) { $obj['lang'] = $t['o_lang']; } @@ -1829,10 +1809,8 @@ private function _add_arc2_triple_list(&$triples) $this->_index[$t['s']][$t['p']] = [$obj]; } elseif (!isset($this->_index[$t['s']][$t['p']])) { $this->_index[$t['s']][$t['p']] = [$obj]; - } else { - if (!in_array($obj, $this->_index[$t['s']][$t['p']])) { - $this->_index[$t['s']][$t['p']][] = $obj; - } + } elseif (!in_array($obj, $this->_index[$t['s']][$t['p']])) { + $this->_index[$t['s']][$t['p']][] = $obj; } } } @@ -1840,10 +1818,8 @@ private function _add_arc2_triple_list(&$triples) // until ARC2 upgrades to support RDF/PHP we need to rename all types of "uri" to "iri" /** * @param array $index - * - * @return array */ - private function _to_arc_index(&$index) + private function _to_arc_index(&$index): array { $ret = []; @@ -1860,6 +1836,7 @@ private function _to_arc_index(&$index) $o_new[$key] = $value; } } + $ret[$s][$p][] = $o_new; } } @@ -1871,11 +1848,9 @@ private function _to_arc_index(&$index) /** * @param string $p * @param string $o - * @param string $type * - * @return array */ - private function get_subjects_where($p, $o, $type) + private function get_subjects_where($p, $o, string $type): array { $subjects = []; foreach ($this->_index as $subject => $properties) { @@ -1896,17 +1871,16 @@ private function get_subjects_where($p, $o, $type) /** * @param string $s * @param string $o - * @param string $type */ - private function add_to_sequence($s, $o, $type = 'resource') + private function add_to_sequence($s, $o, string $type = 'resource'): void { $sequenceValue = $this->get_next_sequence($s); $this->add_resource_triple($s, self::rdf_type, self::rdf_seq); - if ($type == 'literal') { - $this->add_literal_triple($s, self::rdf . "_{$sequenceValue}", $o); + if ($type === 'literal') { + $this->add_literal_triple($s, self::rdf . ('_' . $sequenceValue), $o); } else { - $this->add_resource_triple($s, self::rdf . "_{$sequenceValue}", $o); + $this->add_resource_triple($s, self::rdf . ('_' . $sequenceValue), $o); } } } diff --git a/src/classes/Labeller.php b/src/classes/Labeller.php index 14883cd6..2cbc5578 100644 --- a/src/classes/Labeller.php +++ b/src/classes/Labeller.php @@ -1,5 +1,7 @@ ['nickname', 'nickname', 'is nickname of'], 'http://xmlns.com/foaf/0.1/phone' => ['phone number'], 'http://xmlns.com/foaf/0.1/mbox' => ['email address'], - 'http://xmlns.com/foaf/0.1/workplaceHomepage' => ['workplace\'s homepage'], - 'http://xmlns.com/foaf/0.1/schoolHomepage' => ['school\'s homepage'], + 'http://xmlns.com/foaf/0.1/workplaceHomepage' => ["workplace's homepage"], + 'http://xmlns.com/foaf/0.1/schoolHomepage' => ["school's homepage"], 'http://xmlns.com/foaf/0.1/openid' => ['OpenID'], 'http://xmlns.com/foaf/0.1/mbox_sha1sum' => ['email address hashcode'], 'http://xmlns.com/foaf/0.1/made' => ['made', 'made', 'maker'], @@ -294,7 +296,7 @@ class Labeller * @param string $prefix the namespace prefix to associate with the URI * @param string $uri the URI to associate with the prefix */ - public function set_namespace_mapping($prefix, $uri) + public function set_namespace_mapping($prefix, $uri): void { $this->_ns[$prefix] = $uri; } @@ -306,12 +308,13 @@ public function set_namespace_mapping($prefix, $uri) * * @return string the URI corresponding to the QName if a suitable prefix exists, null otherwise */ - public function qname_to_uri($qname) + public function qname_to_uri($qname): ?string { - if (preg_match('~^(.+):(.+)$~', $qname, $m)) { - if (isset($this->_ns[$m[1]])) { - return $this->_ns[$m[1]] . $m[2]; - } + if (!preg_match('~^(.+):(.+)$~', $qname, $m)) { + return null; + } + if (isset($this->_ns[$m[1]])) { + return $this->_ns[$m[1]] . $m[2]; } return null; @@ -324,7 +327,7 @@ public function qname_to_uri($qname) * * @return string the QName corresponding to the URI if a suitable prefix exists, null otherwise */ - public function uri_to_qname($uri) + public function uri_to_qname($uri): ?string { if (preg_match('~^(.*[\/\#])([a-z0-9\-\_\:]+)$~i', $uri, $m)) { $ns = $m[1]; @@ -345,7 +348,7 @@ public function uri_to_qname($uri) */ public function get_prefix($ns) { - $prefix = array_search($ns, $this->_ns); + $prefix = array_search($ns, $this->_ns, true); if ($prefix != null && $prefix !== false) { return $prefix; } @@ -364,6 +367,7 @@ public function get_prefix($ns) while (array_key_exists('ns' . $index, $this->_ns)) { $index++; } + $prefix = 'msg' . $index; $this->_ns[$prefix] = $ns; @@ -373,7 +377,7 @@ public function get_prefix($ns) /** * @param string $p */ - public function add_labelling_property($p) + public function add_labelling_property($p): void { $this->_label_properties[] = $p; } @@ -398,48 +402,48 @@ public function get_label($uri, $g = null, $capitalize = false, $use_qnames = fa { if ($g) { $label = $g->get_first_literal($uri, 'http://www.w3.org/2004/02/skos/core#prefLabel', '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } $label = $g->get_first_literal($uri, RDFS_LABEL, '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } $label = $g->get_first_literal($uri, 'http://purl.org/dc/terms/title', '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } $label = $g->get_first_literal($uri, DC_TITLE, '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } $label = $g->get_first_literal($uri, FOAF_NAME, '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } $label = $g->get_first_literal($uri, 'http://www.geonames.org/ontology#name', '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } $label = $g->get_first_literal($uri, RDF_VALUE, '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } $label = $g->get_first_literal($uri, 'http://purl.org/rss/1.0/title', '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } foreach ($this->_label_properties as $p) { $label = $g->get_first_literal($uri, $p, '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } } @@ -452,6 +456,7 @@ public function get_label($uri, $g = null, $capitalize = false, $use_qnames = fa return $this->_labels[$uri][0]; } + if (preg_match('~^http://www.w3.org/1999/02/22-rdf-syntax-ns#_(.+)$~', $uri, $m)) { if ($capitalize) { return 'Item ' . $m[1]; @@ -465,29 +470,26 @@ public function get_label($uri, $g = null, $capitalize = false, $use_qnames = fa if ($label) { return $label; } - } else { - if (preg_match('~^.*[\/\#]([^\/\#]+)$~', $uri, $m)) { - $localname = $m[1]; - if (preg_match('~[^A-Z][A-Z][^A-Z]~', $localname)) { - $parts = preg_split('/([A-Z][^A-Z]*)/', $localname, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); - $parts = array_map('strtolower', $parts); - if ($parts[0] == 'has') { - array_shift($parts); - } - $label = implode(' ', $parts); - if ($capitalize) { - return ucfirst($label); - } - - return $label; + } elseif (preg_match('~^.*[\/\#]([^\/\#]+)$~', $uri, $m)) { + $localname = $m[1]; + if (preg_match('~[^A-Z][A-Z][^A-Z]~', $localname)) { + $parts = preg_split('/([A-Z][^A-Z]*)/', $localname, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); + $parts = array_map('strtolower', $parts); + if ($parts[0] == 'has') { + array_shift($parts); } - if ($capitalize && preg_match('~^[a-z]~', $localname)) { - return ucfirst($localname); + $label = implode(' ', $parts); + if ($capitalize) { + return ucfirst($label); } - return $localname; + return $label; } + if ($capitalize && preg_match('~^[a-z]~', $localname)) { + return ucfirst($localname); + } + return $localname; } return $uri; @@ -505,23 +507,21 @@ public function get_plural_label($uri, $g = null, $capitalize = false, $use_qnam { if ($g) { $label = $g->get_first_literal($uri, 'http://purl.org/net/vocab/2004/03/label#plural', '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } } if (array_key_exists($uri, $this->_labels)) { - if (count($this->_labels[$uri]) > 1) { - $label = $this->_labels[$uri][1]; - } else { - $label = $this->_labels[$uri][0] . 's'; - } + $label = count($this->_labels[$uri]) > 1 ? $this->_labels[$uri][1] : $this->_labels[$uri][0] . 's'; + if ($capitalize) { return ucfirst($label); } return $label; } + if ($use_qnames == false && preg_match('~^.*[\/\#]([a-z]+)$~', $uri, $m)) { return $m[1] . 's'; } @@ -546,17 +546,14 @@ public function get_inverse_label($uri, $g = null, $capitalize = false, $use_qna { if ($g) { $label = $g->get_first_literal($uri, 'http://purl.org/net/vocab/2004/03/label#inverseSingular', '', 'en'); - if (strlen($label) != 0) { + if (strlen($label) !== 0) { return $label; } } if (array_key_exists($uri, $this->_labels)) { - if (count($this->_labels[$uri]) > 2) { - $label = $this->_labels[$uri][2]; - } else { - $label = 'is ' . $this->_labels[$uri][0] . ' of'; - } + $label = count($this->_labels[$uri]) > 2 ? $this->_labels[$uri][2] : 'is ' . $this->_labels[$uri][0] . ' of'; + if ($capitalize) { return ucfirst($label); } @@ -572,7 +569,7 @@ public function get_inverse_label($uri, $g = null, $capitalize = false, $use_qna return $label; } - public function label_graph(ExtendedGraph &$graph) + public function label_graph(ExtendedGraph &$graph): void { $labelled_properties = []; $index = $graph->get_index(); @@ -583,6 +580,7 @@ public function label_graph(ExtendedGraph &$graph) if (!$graph->subject_has_property($p, RDFS_LABEL)) { $graph->add_literal_triple($p, RDFS_LABEL, $this->_labels[$p][0]); } + if (!$graph->subject_has_property($p, 'http://purl.org/net/vocab/2004/03/label#plural')) { if (count($this->_labels[$p]) > 1) { $graph->add_literal_triple($p, 'http://purl.org/net/vocab/2004/03/label#plural', $this->_labels[$p][1]); @@ -590,6 +588,7 @@ public function label_graph(ExtendedGraph &$graph) $graph->add_literal_triple($p, 'http://purl.org/net/vocab/2004/03/label#plural', $this->_labels[$p][0] . 's'); } } + if (!$graph->subject_has_property($p, 'http://purl.org/net/vocab/2004/03/label#inverseSingular')) { if (count($this->_labels[$p]) > 2) { $graph->add_literal_triple($p, 'http://purl.org/net/vocab/2004/03/label#inverseSingular', $this->_labels[$p][2]); @@ -597,6 +596,7 @@ public function label_graph(ExtendedGraph &$graph) $graph->add_literal_triple($p, 'http://purl.org/net/vocab/2004/03/label#inverseSingular', 'is ' . $this->_labels[$p][0] . ' of'); } } + $labelled_properties[$p] = 1; } elseif (preg_match('~^http://www.w3.org/1999/02/22-rdf-syntax-ns#_(.+)$~', $p, $m)) { $graph->add_literal_triple($p, RDFS_LABEL, 'Item ' . $m[1]); diff --git a/src/classes/StatsD.php b/src/classes/StatsD.php index 28a39005..60ca9048 100644 --- a/src/classes/StatsD.php +++ b/src/classes/StatsD.php @@ -1,5 +1,7 @@ send( - $this->generateStatData($operation, ['1|c', "{$duration}|ms"]) + $this->generateStatData($operation, ['1|c', $duration . '|ms']) ); } @@ -56,9 +60,8 @@ public function timer($operation, $duration) * Record an arbitrary value. * * @param string $operation - * @param string $value */ - public function gauge($operation, $value) + public function gauge($operation, string $value): void { $this->send( $this->generateStatData($operation, $value . '|g') @@ -66,7 +69,7 @@ public function gauge($operation, $value) } /** - * @return array + * @return array|array> */ public function getConfig() { @@ -80,9 +83,6 @@ public function getConfig() ]; } - /** - * @return StatsD - */ public static function createFromConfig(array $config) { if (isset($config['config'])) { @@ -109,7 +109,7 @@ public function getPrefix() * * @throws \InvalidArgumentException */ - public function setPrefix($prefix) + public function setPrefix($prefix): void { if ($this->isValidPathValue($prefix)) { $this->prefix = $prefix; @@ -129,7 +129,7 @@ public function getPort() /** * @param int|string $port */ - public function setPort($port) + public function setPort($port): void { $this->port = $port; } @@ -145,7 +145,7 @@ public function getHost() /** * @param string $host */ - public function setHost($host) + public function setHost($host): void { $this->host = $host; } @@ -163,7 +163,7 @@ public function getPivotValue() * * @throws \InvalidArgumentException */ - public function setPivotValue($pivotValue) + public function setPivotValue($pivotValue): void { if ($this->isValidPathValue($pivotValue)) { $this->pivotValue = $pivotValue; @@ -177,42 +177,49 @@ public function setPivotValue($pivotValue) * * @param array $data * @param int $sampleRate + * + * @return void */ protected function send($data, $sampleRate = 1) { + if (empty($this->host)) { + return; + } + $sampledData = []; if ($sampleRate < 1) { foreach ($data as $stat => $value) { if ((mt_rand() / mt_getrandmax()) <= $sampleRate) { - $sampledData[$stat] = "{$value}|@{$sampleRate}"; + $sampledData[$stat] = sprintf('%s|@%d', $value, $sampleRate); } } } else { $sampledData = $data; } + if (empty($sampledData)) { return; } try { - if (!empty($this->host)) { // if host is configured, send.. - $fp = fsockopen("udp://{$this->host}", $this->port); - if (!$fp) { - return; - } - // make this a non blocking stream - stream_set_blocking($fp, false); - foreach ($sampledData as $stat => $value) { - if (is_array($value)) { - foreach ($value as $v) { - fwrite($fp, "{$stat}:{$v}"); - } - } else { - fwrite($fp, "{$stat}:{$value}"); + $fp = fsockopen('udp://' . $this->host, $this->port); + if (!$fp) { + return; + } + + // make this a non blocking stream + stream_set_blocking($fp, false); + foreach ($sampledData as $stat => $value) { + if (is_array($value)) { + foreach ($value as $v) { + fwrite($fp, sprintf('%s:%s', $stat, $v)); } + } else { + fwrite($fp, sprintf('%s:%s', $stat, $value)); } - fclose($fp); } + + fclose($fp); } catch (\Exception $e) { } } @@ -224,33 +231,25 @@ protected function send($data, $sampleRate = 1) * "{prefix}.tripod.{stat}"=>"1|c" * } * - * @param string $operation * @param array|string $value - * * @return array An associative array of the grouped_by_database and aggregate stats */ - protected function generateStatData($operation, $value) + protected function generateStatData(string $operation, $value): array { $data = []; foreach ($this->getStatsPaths() as $path) { - $data[$path . ".{$operation}"] = $value; + $data[$path . ('.' . $operation)] = $value; } return $data; } - /** - * @return array - */ - protected function getStatsPaths() + protected function getStatsPaths(): array { return array_values(array_filter([$this->getAggregateStatPath()])); } - /** - * @return string - */ - protected function getAggregateStatPath() + protected function getAggregateStatPath(): string { return empty($this->prefix) ? STAT_CLASS : $this->prefix . '.' . STAT_CLASS; } @@ -259,10 +258,8 @@ protected function getAggregateStatPath() * StatsD paths cannot start with, end with, or have more than one consecutive '.'. * * @param string $value - * - * @return bool */ - protected function isValidPathValue($value) + protected function isValidPathValue($value): bool { return preg_match('/(^\.)|(\.\.+)|(\.$)/', $value) === 0; } diff --git a/src/classes/Timer.php b/src/classes/Timer.php index 53149904..3b498268 100644 --- a/src/classes/Timer.php +++ b/src/classes/Timer.php @@ -1,5 +1,7 @@ start_time = $this->getMicrotime(); } @@ -37,7 +39,7 @@ public function start() /** * Captures current microtime as end time. Call this as soon as event execution is complete. */ - public function stop() + public function stop(): void { $this->end_time = $this->getMicrotime(); } @@ -54,6 +56,7 @@ public function result() if (is_null($this->start_time)) { throw new \Exception('Timer: start method not called !'); } + if (is_null($this->end_time)) { throw new \Exception('Timer: stop method not called !'); } @@ -82,6 +85,7 @@ public function microResult() if (is_null($this->start_time)) { throw new TimerException('Timer: start method not called !'); } + if (is_null($this->end_time)) { throw new TimerException('Timer: stop method not called !'); } @@ -101,7 +105,7 @@ public function microResult() /** * @return string current system time in pair of seconds microseconds */ - private function getMicrotime() + private function getMicrotime(): string { return microtime(); } diff --git a/src/exceptions/CardinalityException.php b/src/exceptions/CardinalityException.php index 99eecbca..1b939e5a 100644 --- a/src/exceptions/CardinalityException.php +++ b/src/exceptions/CardinalityException.php @@ -1,5 +1,7 @@ target = $target; - parent::__construct("Could not label: {$target}"); + parent::__construct('Could not label: ' . $target); } /** diff --git a/src/exceptions/SearchException.php b/src/exceptions/SearchException.php index 1f22738d..5accc8bf 100644 --- a/src/exceptions/SearchException.php +++ b/src/exceptions/SearchException.php @@ -1,5 +1,7 @@ mongoCursorTimeout = $mongoCursorTimeout; } /** * @throws ConfigException + * @param array $spec */ - public function validateTableSpec(array $spec) + public function validateTableSpec(array $spec): void { if (!isset($spec[_ID_KEY])) { throw new ConfigException('Table spec does not contain ' . _ID_KEY); @@ -214,7 +219,7 @@ public function getValidationLevel() /** * @param string $validationLevel */ - public static function setValidationLevel($validationLevel) + public static function setValidationLevel($validationLevel): void { self::$validationLevel = $validationLevel; } @@ -245,7 +250,7 @@ public function getDefinedPredicatesInSpec($storename, $specId) * * @throws ConfigException */ - public function checkModifierFunctions(array $array, $parent, $parentKey = null) + public function checkModifierFunctions(array $array, $parent, $parentKey = null): void { foreach ($array as $k => $v) { // You can have recursive modifiers so we check if the value is an array. @@ -293,10 +298,10 @@ public function getDefaultContextAlias() * * @throws ConfigException */ - public static function getInstance() + public static function getInstance(): \Tripod\Mongo\IConfigInstance { self::getLogger()->warning( - '\Tripod\Mongo\Config::getInstance deprecated, use \Tripod\Config::getInstance instead' + \Tripod\Mongo\Config::class . '::getInstance deprecated, use ' . \Tripod\Config::class . '::getInstance instead' ); return \Tripod\Config::getInstance(); @@ -307,10 +312,10 @@ public static function getInstance() * * @deprecated */ - public static function setConfig(array $config) + public static function setConfig(array $config): void { self::getLogger()->warning( - '\Tripod\Mongo\Config::setConfig deprecated, use \Tripod\Config::setConfig instead' + \Tripod\Mongo\Config::class . '::setConfig deprecated, use ' . \Tripod\Config::class . '::setConfig instead' ); \Tripod\Config::setConfig($config); } @@ -319,13 +324,11 @@ public static function setConfig(array $config) * Returns configuration array. * * @deprecated - * - * @return array */ - public static function getConfig() + public static function getConfig(): array { self::getLogger()->warning( - '\Tripod\Mongo\Config::getConfig deprecated, use \Tripod\Config::getConfig instead' + \Tripod\Mongo\Config::class . '::getConfig deprecated, use ' . \Tripod\Config::class . '::getConfig instead' ); return \Tripod\Config::getConfig(); @@ -356,11 +359,13 @@ public function getIndexesGroupedByCollection($storeName) if (!isset($tableIndexes[$tspec['to_data_source']])) { $tableIndexes[$tspec['to_data_source']] = []; } + foreach ($tspec['ensureIndexes'] as $index) { $tableIndexes[$tspec['to_data_source']][] = $index; } } } + $indexes[TABLE_ROWS_COLLECTION] = $tableIndexes; $viewIndexes = []; @@ -370,11 +375,13 @@ public function getIndexesGroupedByCollection($storeName) if (!isset($viewIndexes[$vspec['to_data_source']])) { $viewIndexes[$vspec['to_data_source']] = []; } + foreach ($vspec['ensureIndexes'] as $index) { $viewIndexes[$vspec['to_data_source']][] = $index; } } } + $indexes[VIEWS_COLLECTION] = $viewIndexes; return $indexes; @@ -410,12 +417,10 @@ public function getCardinality($storeName, $collName, $qName = null) * * @param string $storeName * @param string $pod - * - * @return bool */ - public function isPodWithinStore($storeName, $pod) + public function isPodWithinStore($storeName, $pod): bool { - return (array_key_exists($storeName, $this->podConnections)) ? array_key_exists($pod, $this->podConnections[$storeName]) : false; + return array_key_exists($storeName, $this->podConnections) && array_key_exists($pod, $this->podConnections[$storeName]); } /** @@ -447,7 +452,7 @@ public function getDataSourceForPod($storeName, $podName) return $this->podConnections[$storeName][$podName]; } - throw new ConfigException("'{$podName}' not configured for store '{$storeName}'"); + throw new ConfigException(sprintf("'%s' not configured for store '%s'", $podName, $storeName)); } /** @@ -467,7 +472,7 @@ public function getReplicaSetName($datasource) $query = parse_url($this->dataSources[$datasource]['connection'], PHP_URL_QUERY); $params = []; parse_str($query, $params); - if (!empty($params['replicaSet'])) { + if (isset($params['replicaSet']) && ($params['replicaSet'] !== [] && ($params['replicaSet'] !== '' && $params['replicaSet'] !== '0'))) { return $params['replicaSet']; } } @@ -479,10 +484,8 @@ public function getReplicaSetName($datasource) * Returns a boolean reflecting whether or not a replica set has been defined for the supplied database name. * * @param string $datasource - * - * @return bool */ - public function isReplicaSet($datasource) + public function isReplicaSet($datasource): bool { return $this->getReplicaSetName($datasource) !== null; } @@ -547,6 +550,7 @@ public function getSearchDocumentSpecifications($storeName, $type = null, $justR if (!isset($this->searchDocSpecs[$storeName]) || empty($this->searchDocSpecs[$storeName])) { return []; } + $specs = []; if (empty($type)) { @@ -569,20 +573,10 @@ public function getSearchDocumentSpecifications($storeName, $type = null, $justR foreach ($this->searchDocSpecs[$storeName] as $spec) { if (is_array($spec[_ID_TYPE])) { if (in_array($typeAsUri, $spec[_ID_TYPE]) || in_array($typeAsQName, $spec[_ID_TYPE])) { - if ($justReturnSpecId) { - $specs[] = $spec[_ID_KEY]; - } else { - $specs[] = $spec; - } - } - } else { - if ($spec[_ID_TYPE] == $typeAsUri || $spec[_ID_TYPE] == $typeAsQName) { - if ($justReturnSpecId) { - $specs[] = $spec[_ID_KEY]; - } else { - $specs[] = $spec; - } + $specs[] = $justReturnSpecId ? $spec[_ID_KEY] : $spec; } + } elseif ($spec[_ID_TYPE] == $typeAsUri || $spec[_ID_TYPE] == $typeAsQName) { + $specs[] = $justReturnSpecId ? $spec[_ID_KEY] : $spec; } } @@ -641,7 +635,7 @@ public function getViewSpecifications($storeName) * * @return array of types */ - public function getAllTypesInSpecifications($storeName) + public function getAllTypesInSpecifications($storeName): array { $viewTypes = $this->getTypesInViewSpecifications($storeName); $tableTypes = $this->getTypesInTableSpecifications($storeName); @@ -656,10 +650,8 @@ public function getAllTypesInSpecifications($storeName) * * @param string $storeName * @param string|null $pod - * - * @return array */ - public function getTypesInViewSpecifications($storeName, $pod = null) + public function getTypesInViewSpecifications($storeName, $pod = null): array { return array_unique($this->getSpecificationTypes($this->getViewSpecifications($storeName), $pod)); } @@ -669,10 +661,8 @@ public function getTypesInViewSpecifications($storeName, $pod = null) * * @param string $storeName * @param string|null $pod - * - * @return array */ - public function getTypesInTableSpecifications($storeName, $pod = null) + public function getTypesInTableSpecifications($storeName, $pod = null): array { return array_unique($this->getSpecificationTypes($this->getTableSpecifications($storeName), $pod)); } @@ -682,20 +672,16 @@ public function getTypesInTableSpecifications($storeName, $pod = null) * * @param string $storeName * @param string|null $pod - * - * @return array */ - public function getTypesInSearchSpecifications($storeName, $pod = null) + public function getTypesInSearchSpecifications($storeName, $pod = null): array { return array_unique($this->getSpecificationTypes($this->getSearchDocumentSpecifications($storeName), $pod)); } /** * Returns an array of database names. - * - * @return array */ - public function getDbs() + public function getDbs(): array { return array_keys($this->dbConfig); } @@ -742,7 +728,7 @@ public function getSearchProviderClassName($storeName) public function getDatabase($storeName, $dataSource = null, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) { if (!isset($this->dbConfig[$storeName])) { - throw new ConfigException("Store name '{$storeName}' not in configuration"); + throw new ConfigException(sprintf("Store name '%s' not in configuration", $storeName)); } if (!$dataSource) { @@ -774,7 +760,7 @@ public function getCollectionForCBD($storeName, $podName, $readPreference = Read ); } - throw new ConfigException("Collection name '{$podName}' not in configuration for store '{$storeName}'"); + throw new ConfigException(sprintf("Collection name '%s' not in configuration for store '%s'", $podName, $storeName)); } /** @@ -795,7 +781,7 @@ public function getCollectionForView($storeName, $viewId, $readPreference = Read ); } - throw new ConfigException("View id '{$viewId}' not in configuration for store '{$storeName}'"); + throw new ConfigException(sprintf("View id '%s' not in configuration for store '%s'", $viewId, $storeName)); } /** @@ -816,7 +802,7 @@ public function getCollectionForSearchDocument($storeName, $searchDocumentId, $r ); } - throw new ConfigException("Search document id '{$searchDocumentId}' not in configuration for store '{$storeName}'"); + throw new ConfigException(sprintf("Search document id '%s' not in configuration for store '%s'", $searchDocumentId, $storeName)); } /** @@ -837,7 +823,7 @@ public function getCollectionForTable($storeName, $tableId, $readPreference = Re ); } - throw new ConfigException("Table id '{$tableId}' not in configuration for store '{$storeName}'"); + throw new ConfigException(sprintf("Table id '%s' not in configuration for store '%s'", $tableId, $storeName)); } /** @@ -848,20 +834,22 @@ public function getCollectionForTable($storeName, $tableId, $readPreference = Re * * @throws ConfigException */ - public function getCollectionsForTables($storeName, array $tables = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionsForTables($storeName, array $tables = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): array { if (!isset($this->tableSpecs[$storeName])) { return []; } - if (empty($tables)) { + + if ($tables === []) { $tables = array_keys($this->tableSpecs[$storeName]); } + $dataSources = []; foreach ($tables as $table) { if (isset($this->tableSpecs[$storeName][$table])) { $dataSources[] = $this->tableSpecs[$storeName][$table]['to_data_source']; } else { - throw new ConfigException("Table id '{$table}' not in configuration for store '{$storeName}'"); + throw new ConfigException(sprintf("Table id '%s' not in configuration for store '%s'", $table, $storeName)); } } @@ -884,20 +872,22 @@ public function getCollectionsForTables($storeName, array $tables = [], $readPre * * @throws ConfigException */ - public function getCollectionsForViews($storeName, array $views = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionsForViews($storeName, array $views = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): array { if (!isset($this->viewSpecs[$storeName])) { return []; } - if (empty($views)) { + + if ($views === []) { $views = array_keys($this->viewSpecs[$storeName]); } + $dataSources = []; foreach ($views as $view) { if (isset($this->viewSpecs[$storeName][$view])) { $dataSources[] = $this->viewSpecs[$storeName][$view]['to_data_source']; } else { - throw new ConfigException("View id '{$view}' not in configuration for store '{$storeName}'"); + throw new ConfigException(sprintf("View id '%s' not in configuration for store '%s'", $view, $storeName)); } } @@ -920,20 +910,22 @@ public function getCollectionsForViews($storeName, array $views = [], $readPrefe * * @throws ConfigException */ - public function getCollectionsForSearch($storeName, array $searchSpecIds = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionsForSearch($storeName, array $searchSpecIds = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): array { if (!isset($this->searchDocSpecs[$storeName])) { return []; } - if (empty($searchSpecIds)) { + + if ($searchSpecIds === []) { $searchSpecIds = array_keys($this->searchDocSpecs[$storeName]); } + $dataSources = []; foreach ($searchSpecIds as $searchSpec) { if (isset($this->searchDocSpecs[$storeName][$searchSpec])) { $dataSources[] = $this->searchDocSpecs[$storeName][$searchSpec]['to_data_source']; } else { - throw new ConfigException("Search document spec id '{$searchSpec}' not in configuration for store '{$storeName}'"); + throw new ConfigException(sprintf("Search document spec id '%s' not in configuration for store '%s'", $searchSpec, $storeName)); } } @@ -1055,6 +1047,7 @@ public static function getResqueServer() self::getLogger()->notice('Use of MONGO_TRIPOD_RESQUE_SERVER is deprecated - use RESQUE_SERVER instead'); } } + if (empty($resqueServer)) { self::getLogger()->warning('RESQUE_SERVER is missing from environment - using localhost:6379 instead'); $resqueServer = 'localhost:6379'; @@ -1080,14 +1073,13 @@ public static function getLogger() /** * Sets the Tripod config. - * - * @return Config */ - public static function deserialize(array $config) + public static function deserialize(array $config): self { if (isset($config['class'], $config['config'])) { $config = $config['config']; } + $instance = new self(); $instance->loadConfig($config); @@ -1120,6 +1112,7 @@ public function getBatchSize($operation) * Used to load the config from self::config when new instance is generated. * * @throws ConfigException + * @param array $config */ protected function loadConfig(array $config) { @@ -1132,11 +1125,13 @@ protected function loadConfig(array $config) foreach ($this->getMandatoryKey('data_sources', $config) as $source => $c) { if (!array_key_exists('type', $c)) { - throw new ConfigException("No 'type' set for data source {$source}"); + throw new ConfigException('No \'type\' set for data source ' . $source); } + if (!array_key_exists('connection', $c)) { - throw new ConfigException("No connection information set for data source {$source}"); + throw new ConfigException('No connection information set for data source ' . $source); } + $this->dataSources[$source] = $c; } @@ -1145,12 +1140,12 @@ protected function loadConfig(array $config) if (!isset($this->dataSources[$this->tConfig['data_source']])) { throw new ConfigException('Transaction log data source, ' . $this->tConfig['data_source'] . ', was not defined'); } + $this->tConfig['database'] = $this->getMandatoryKey('database', $transactionConfig, 'transaction_log'); $this->tConfig['collection'] = $this->getMandatoryKey('collection', $transactionConfig, 'transaction_log'); // A 'pod' corresponds to a logical database $this->databases = $this->getMandatoryKey('stores', $config); - $defaultDB = null; foreach ($this->databases as $storeName => $storeConfig) { $this->dbConfig[$storeName] = ['data_source' => $this->getMandatoryKey('data_source', $storeConfig)]; if (isset($storeConfig['database']) && !empty($storeConfig['database'])) { @@ -1179,7 +1174,7 @@ protected function loadConfig(array $config) if (array_key_exists($namespace, $this->ns)) { $this->cardinality[$storeName][$podName][] = $cardinality; } else { - throw new ConfigException("Cardinality '{$qname}' does not have the namespace defined"); + throw new ConfigException(sprintf("Cardinality '%s' does not have the namespace defined", $qname)); } } } else { @@ -1213,8 +1208,9 @@ protected function loadConfig(array $config) || $this->cardinality[$storeName][$podName][$cardinalityField] != 1) { $fieldsThatAreArrays++; } + if ($fieldsThatAreArrays > 1) { - throw new ConfigException("Compound index {$indexName} has more than one field with cardinality > 1 - mongo will not be able to build this index"); + throw new ConfigException(sprintf('Compound index %s has more than one field with cardinality > 1 - mongo will not be able to build this index', $indexName)); } } } @@ -1222,6 +1218,7 @@ protected function loadConfig(array $config) } } } + if (isset($storeConfig['batch_sizes'])) { foreach ([OP_TABLES, OP_SEARCH, OP_VIEWS] as $op) { if (isset($storeConfig['batch_sizes'][$op]) && is_numeric($storeConfig['batch_sizes'][$op])) { @@ -1229,6 +1226,7 @@ protected function loadConfig(array $config) } } } + $searchConfig = array_key_exists('search_config', $storeConfig) ? $storeConfig['search_config'] : []; $this->searchDocSpecs[$storeName] = []; if (!empty($searchConfig)) { @@ -1239,9 +1237,11 @@ protected function loadConfig(array $config) if (!isset($spec[_ID_KEY])) { throw new ConfigException('Search document spec does not contain ' . _ID_KEY); } + if (!isset($spec['from']) || !in_array($spec['from'], $this->getPods($storeName))) { throw new ConfigException("'" . $spec[_ID_KEY] . "[\"from\"]' property not set or references an undefined pod"); } + if (!isset($spec['filter'])) { throw new ConfigException("'" . $spec[_ID_KEY] . "[\"filter\"]' property not set"); } @@ -1259,6 +1259,7 @@ protected function loadConfig(array $config) $spec['to_data_source'] = $storeConfig['data_source']; } } + $this->searchDocSpecs[$storeName][$spec[_ID_KEY]] = $spec; } } @@ -1270,12 +1271,15 @@ protected function loadConfig(array $config) if (!isset($spec[_ID_KEY])) { throw new ConfigException('View spec does not contain ' . _ID_KEY); } + if (!isset($spec['from']) || !in_array($spec['from'], $this->getPods($storeName))) { throw new ConfigException("'" . $spec[_ID_KEY] . "[\"from\"]' property not set or references an undefined pod"); } + if (!isset($spec['joins'])) { throw new ConfigException('Could not find any joins in view specification - usecase better served with select()'); } + $this->ifCountExistsWithoutTTLThrowException($spec); if (isset($spec['to_data_source'])) { if (!isset($this->dataSources[$spec['to_data_source']])) { @@ -1284,6 +1288,7 @@ protected function loadConfig(array $config) } else { $spec['to_data_source'] = $storeConfig['data_source']; } + $this->viewSpecs[$storeName][$spec[_ID_KEY]] = $spec; } @@ -1310,6 +1315,7 @@ protected function loadConfig(array $config) * @param int $depth * * @throws ConfigException + * @param array $spec */ protected function validateTableSpecPart(array $spec, $depth = 0) { @@ -1317,6 +1323,7 @@ protected function validateTableSpecPart(array $spec, $depth = 0) if (!isset($spec['fields']) && !isset($spec['joins']) && !isset($spec['counts']) && !isset($spec['computed_fields'])) { throw new ConfigException('Table spec part does not contain fields, joins, counts, or computed_fields'); } + if (isset($spec['fields'])) { foreach ($spec['fields'] as $field) { if (!isset($field['fieldName'])) { @@ -1368,12 +1375,14 @@ protected function validateTableSpecPart(array $spec, $depth = 0) $validComputingFieldFunctions = Tables::$computedFieldFunctions; if ($validationLevel == self::VALIDATE_MAX) { $availableFields = $this->getFieldNamesInSpec($spec); - $availableFields = array_map(function ($field) { return '$' . $field; }, $availableFields); + $availableFields = array_map(function (string $field): string { return '$' . $field; }, $availableFields); } + foreach ($spec['computed_fields'] as $field) { if (!isset($field['fieldName'])) { throw new ConfigException('Computed field spec does not contain fieldName'); } + if (!isset($field['value'])) { throw new ConfigException('Computed field spec does not contain value'); } @@ -1384,13 +1393,14 @@ protected function validateTableSpecPart(array $spec, $depth = 0) $functions = array_intersect(array_keys($field['value']), $validComputingFieldFunctions); - if (empty($functions)) { + if ($functions === []) { throw new ConfigException('Computed field spec does not contain valid function'); } if (count($functions) > 1) { throw new ConfigException('Computed field spec contains more than one function'); } + if ($validationLevel == self::VALIDATE_MAX) { $this->validateComputedFieldSpec($functions[0], $field['value'], $availableFields); } @@ -1406,9 +1416,10 @@ protected function validateTableSpecPart(array $spec, $depth = 0) } /** - * @param string $type + * @param string[] $availableFields + * @param array $spec */ - protected function validateComputedFieldSpec($type, array $spec, array $availableFields) + protected function validateComputedFieldSpec(string $type, array $spec, array $availableFields) { switch ($type) { case 'conditional': @@ -1430,6 +1441,8 @@ protected function validateComputedFieldSpec($type, array $spec, array $availabl /** * @throws ConfigException + * @param array $spec + * @param string[] $availableFields */ protected function validateComputedConditionalSpec(array $spec, array $availableFields) { @@ -1475,11 +1488,10 @@ protected function validateComputedConditionalSpec(array $spec, array $available default: throw new ConfigException("Computed conditional field 'then' value has more than one function"); - - break; } } } + if (isset($spec['else'])) { if (is_string($spec['else'])) { $this->validateSpecVariableReplacement($spec['else'], $availableFields); @@ -1497,8 +1509,6 @@ protected function validateComputedConditionalSpec(array $spec, array $available default: throw new ConfigException("Computed conditional field 'else' value has more than one function"); - - break; } } } @@ -1512,10 +1522,8 @@ protected function validateComputedConditionalSpec(array $spec, array $available protected function validateSpecVariableReplacement($value, array $availableFields) { if (is_string($value)) { - if (strpos($value, '$') === 0) { - if (!in_array($value, $availableFields)) { - throw new ConfigException("Computed spec variable '{$value}' is not defined in table spec"); - } + if (strpos($value, '$') === 0 && !in_array($value, $availableFields)) { + throw new ConfigException(sprintf("Computed spec variable '%s' is not defined in table spec", $value)); } } elseif (is_array($value)) { foreach ($value as $v) { @@ -1526,31 +1534,39 @@ protected function validateSpecVariableReplacement($value, array $availableField /** * @throws ConfigException + * @param array $spec + * @param string[] $availableFields */ protected function validateComputedReplaceSpec(array $spec, array $availableFields) { if (!isset($spec['search'])) { throw new ConfigException("Computed replace spec does not contain 'search' value"); } + $this->validateSpecVariableReplacement($spec['search'], $availableFields); if (!isset($spec['replace'])) { throw new ConfigException("Computed replace spec does not contain 'replace' value"); } + $this->validateSpecVariableReplacement($spec['replace'], $availableFields); if (!isset($spec['subject'])) { throw new ConfigException("Computed replace spec does not contain 'subject' value"); } + $this->validateSpecVariableReplacement($spec['subject'], $availableFields); } /** * @throws ConfigException + * @param array $spec + * @param string[] $availableFields */ protected function validateComputedArithmeticSpec(array $spec, array $availableFields) { if (count($spec) !== 3) { throw new ConfigException('Computed arithmetic spec must contain 3 values'); } + if (is_array($spec[0])) { if (count(array_keys($spec[0])) === 1 && count(array_intersect(array_keys($spec[0]), Tables::$computedFieldFunctions)) === 1) { $function = array_keys($spec[0]); @@ -1561,6 +1577,7 @@ protected function validateComputedArithmeticSpec(array $spec, array $availableF } else { $this->validateSpecVariableReplacement($spec[0], $availableFields); } + if (is_array($spec[2])) { if (count(array_keys($spec[2])) === 1 && count(array_intersect(array_keys($spec[2]), Tables::$computedFieldFunctions)) === 1) { $function = array_keys($spec[2]); @@ -1571,15 +1588,16 @@ protected function validateComputedArithmeticSpec(array $spec, array $availableF } else { $this->validateSpecVariableReplacement($spec[2], $availableFields); } + if (!in_array($spec[1], Tables::$arithmeticOperators)) { throw new ConfigException("Invalid arithmetic operator '" . $spec[1] . "' in computed arithmetic spec"); } } /** - * @return array + * @param array $spec */ - protected function getFieldNamesInSpec(array $spec) + protected function getFieldNamesInSpec(array $spec): array { $fieldNames = []; if (isset($spec['fields'])) { @@ -1589,6 +1607,7 @@ protected function getFieldNamesInSpec(array $spec) } } } + if (isset($spec['counts'])) { foreach ($spec['counts'] as $count) { if (isset($count['fieldName'])) { @@ -1618,10 +1637,8 @@ protected function getFieldNamesInSpec(array $spec) * Creates an associative array of all predicates/properties associated with all table and search document specifications. * * @param string $storename - * - * @return array */ - protected function getDefinedPredicatesInSpecs($storename) + protected function getDefinedPredicatesInSpecs($storename): array { $predicates = []; $specs = array_merge($this->getTableSpecifications($storename), $this->getSearchDocumentSpecifications($storename)); @@ -1629,6 +1646,7 @@ protected function getDefinedPredicatesInSpecs($storename) if (!isset($spec[_ID_KEY])) { continue; } + $predicates[$spec[_ID_KEY]] = array_unique($this->getDefinedPredicatesInSpecBlock($spec)); } @@ -1638,15 +1656,16 @@ protected function getDefinedPredicatesInSpecs($storename) /** * Recursively crawls a configuration document array (or part of one) and returns any associated predicates/properties. * - * @return array + * @param array $block */ - protected function getDefinedPredicatesInSpecBlock(array $block) + protected function getDefinedPredicatesInSpecBlock(array $block): array { $predicates = []; // If the spec has a "type" property, include rdf:type if (isset($block['type'])) { $predicates[] = $this->getLabeller()->uri_to_alias(RDF_TYPE); } + if (isset($block['filter'])) { foreach ($block['filter'] as $filter) { if (isset($filter['condition'])) { @@ -1654,6 +1673,7 @@ protected function getDefinedPredicatesInSpecBlock(array $block) } } } + // Get the predicates out of the defined fields if (isset($block['fields'])) { foreach ($block['fields'] as $field) { @@ -1717,13 +1737,11 @@ protected function getDefinedPredicatesInSpecBlock(array $block) * Rewrites any predicate uris to alias curies. * * @param array|string $predicate - * - * @return array */ - protected function getPredicateAliasesFromPredicateProperty($predicate) + protected function getPredicateAliasesFromPredicateProperty($predicate): array { $predicates = []; - if (is_string($predicate) && !empty($predicate)) { + if (is_string($predicate) && ($predicate !== '' && $predicate !== '0')) { $predicates[] = $this->getLabeller()->uri_to_alias($predicate); } elseif (is_array($predicate)) { foreach ($this->getPredicatesFromPredicateFunctions($predicate) as $p) { @@ -1760,9 +1778,9 @@ protected function getPredicatesFromPredicateFunctions($array) * * @param array $filter * - * @return array + * @return string[] */ - protected function getPredicatesFromFilterCondition($filter) + protected function getPredicatesFromFilterCondition($filter): array { $predicates = []; $regex = '/(^|\b)(\w+\:\w+)\.(l|u)(\b|$)/'; @@ -1775,6 +1793,7 @@ protected function getPredicatesFromFilterCondition($filter) } } } + if (is_string($condition)) { $numMatches = preg_match_all($regex, $condition, $matches); for ($i = 0; $i < $numMatches; $i++) { @@ -1813,8 +1832,9 @@ protected function getLabeller() protected function getConnectionForDataSource($dataSource) { if (!isset($this->dataSources[$dataSource])) { - throw new ConfigException("Data source '{$dataSource}' not in configuration"); + throw new ConfigException(sprintf("Data source '%s' not in configuration", $dataSource)); } + if (!isset($this->connections[$dataSource])) { $ds = $this->dataSources[$dataSource]; $connectionString = $ds['connection']; @@ -1858,10 +1878,8 @@ protected function getConnectionForDataSource($dataSource) * Create a Mongo Client - used for mocking. * * @param string $connectionString - * - * @return Client */ - protected function getMongoClient($connectionString, array $connectionOptions = []) + protected function getMongoClient($connectionString, array $connectionOptions = []): \MongoDB\Client { return new Client( $connectionString, @@ -1871,11 +1889,9 @@ protected function getMongoClient($connectionString, array $connectionOptions = } /** - * @param string $collectionName - * * @return Collection */ - protected function getMongoCollection(Database $db, $collectionName) + protected function getMongoCollection(Database $db, string $collectionName) { return $db->selectCollection($collectionName); } @@ -1885,17 +1901,14 @@ protected function getMongoCollection(Database $db, $collectionName) * Returns a unique list of every rdf type configured in the supplied specs' ['type'] restriction. * * @param string|null $podName - * - * @return array */ - private function getSpecificationTypes(array $specifications, $podName = null) + private function getSpecificationTypes(array $specifications, $podName = null): array { $types = []; foreach ($specifications as $spec) { - if (!empty($podName)) { - if ($spec['from'] !== $podName) { - continue; // skip this view spec if it isnt for the collection - } + if (!empty($podName) && $spec['from'] !== $podName) { + continue; + // skip this view spec if it isnt for the collection } if (is_array($spec[_ID_TYPE])) { @@ -1912,11 +1925,11 @@ private function getSpecificationTypes(array $specifications, $podName = null) * If we have 'counts' in a view spec, a 'ttl' must be defined. * Note: this does not apply to tables or search docs. * - * @param array $spec + * @param array $spec * * @throws ConfigException */ - private function ifCountExistsWithoutTTLThrowException($spec) + private function ifCountExistsWithoutTTLThrowException(array $spec): void { if (array_key_exists('ttl', $spec)) { return; // ttl exists @@ -1928,6 +1941,7 @@ private function ifCountExistsWithoutTTLThrowException($spec) $this->ifCountExistsWithoutTTLThrowException($join); } } + if (array_key_exists('counts', $spec)) { throw new ConfigException('Aggregate function counts exists in spec, but no TTL defined'); } @@ -1936,17 +1950,15 @@ private function ifCountExistsWithoutTTLThrowException($spec) /** * Returns the value of the supplied key or throws an error, if missing. * - * @param string $key - * @param string $configName * * @return mixed - * * @throws ConfigException + * @param array $a */ - private function getMandatoryKey($key, array $a, $configName = 'config') + private function getMandatoryKey(string $key, array $a, string $configName = 'config') { if (!array_key_exists($key, $a)) { - throw new ConfigException("Mandatory config key [{$key}] is missing from {$configName}"); + throw new ConfigException(sprintf('Mandatory config key [%s] is missing from %s', $key, $configName)); } return $a[$key]; @@ -1963,7 +1975,7 @@ private function getMandatoryKey($key, array $a, $configName = 'config') private function findFieldsInTableSpec($fieldName, $spec) { $fields = []; - if (is_array($spec) && !empty($spec)) { + if (is_array($spec) && $spec !== []) { if (array_key_exists($fieldName, $spec)) { $fields = $spec[$fieldName]; } @@ -1979,36 +1991,33 @@ private function findFieldsInTableSpec($fieldName, $spec) } /** - * @param string $envVar - * @param string $type * * @return string */ - private static function getQueueName($envVar, $type) + private static function getQueueName(string $envVar, string $type) { - $default = (defined('APP_ENV')) ? 'tripod::' . constant('APP_ENV') . "::{$type}" : "tripod::{$type}"; + $default = (defined('APP_ENV')) ? 'tripod::' . constant('APP_ENV') . ('::' . $type) : 'tripod::' . $type; return self::getenv($envVar, $default); } /** - * @param string $env * @param bool $default * * @return bool|string - * * @throws ConfigException */ - private static function getenv($env, $default = false) + private static function getenv(string $env, $default = false) { $var = getenv($env); if (isset($var) && $var != '') { return $var; } + if ($default !== false) { return $default; } - throw new ConfigException("Missing value for environmental variable {$env}"); + throw new ConfigException('Missing value for environmental variable ' . $env); } } diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index 468b68f6..a834189e 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -1,5 +1,7 @@ $this->getContextAlias($context), ]; } + $query = ['_id' => ['$in' => $ids]]; return $this->fetchGraph($query, MONGO_MULTIDESCRIBE); @@ -223,7 +227,7 @@ public function getTableRows( * @param string|null $resource * @param string|null $context */ - public function generateTableRows($tableType, $resource = null, $context = null) + public function generateTableRows($tableType, $resource = null, $context = null): void { $this->getTripodTables()->generateTableRows($tableType, $resource, $context); } @@ -330,7 +334,7 @@ public function search(array $params) return $results; } - throw new Exception("Unknown Search Provider: {$provider}"); + throw new Exception('Unknown Search Provider: ' . $provider); } /** @@ -368,6 +372,7 @@ public function getCount(array $query, $groupBy = null, $ttl = null) } } } + if (empty($results)) { if ($groupBy) { $ops = [ @@ -403,7 +408,7 @@ public function getCount(array $query, $groupBy = null, $ttl = null) $t->stop(); $op = ($groupBy) ? MONGO_GROUP : MONGO_COUNT; $this->timingLog($op, ['duration' => $t->result(), 'query' => $query]); - $this->getStat()->timer("{$op}.{$this->podName}", $t->result()); + $this->getStat()->timer(sprintf('%s.%s', $op, $this->podName), $t->result()); return $results; } @@ -417,9 +422,9 @@ public function getCount(array $query, $groupBy = null, $ttl = null) * @param int $offset * @param string|null $context * - * @return array + * @return array> */ - public function select(array $query, array $fields, ?array $sortBy = null, $limit = null, $offset = 0, $context = null) + public function select(array $query, array $fields, ?array $sortBy = null, $limit = null, $offset = 0, $context = null): array { $t = new Timer(); $t->start(); @@ -456,14 +461,16 @@ public function select(array $query, array $fields, ?array $sortBy = null, $limi $findOptions['skip'] = (int) $offset; $findOptions['limit'] = (int) $limit; } + if (isset($sortBy)) { $findOptions['sort'] = $sortBy; } + $results = $this->collection->find($query, $findOptions); $t->stop(); $this->timingLog(MONGO_SELECT, ['duration' => $t->result(), 'query' => $query]); - $this->getStat()->timer(MONGO_SELECT . ".{$this->podName}", $t->result()); + $this->getStat()->timer(MONGO_SELECT . ('.' . $this->podName), $t->result()); $rows = []; $count = $this->collection->count($query); @@ -491,6 +498,7 @@ public function select(array $query, array $fields, ?array $sortBy = null, $limi } } } + $rows[] = $row; } @@ -539,10 +547,8 @@ public function graph(array $filter, array $includeProperties = []) * * @param string $resource * @param string|null $context - * - * @return string */ - public function getETag($resource, $context = null) + public function getETag($resource, $context = null): string { $this->getStat()->increment(MONGO_GET_ETAG); $resource = $this->labeller->uri_to_alias($resource); @@ -556,20 +562,17 @@ public function getETag($resource, $context = null) /** @var UTCDateTime|null $lastUpdatedDate */ $lastUpdatedDate = $doc[_UPDATED_TS] ?? null; - if ($lastUpdatedDate === null) { - $eTag = ''; - } else { - // PHP 5.3 used MongoDate::__toString() to generate the etag. - // This is incompatible with UTCDate::__toString() so we convert it into a microtime representation. - // This ensures that if it is required to dual run 2 PHP versions, there are no etag compatibility issues. - // Note that MongoDate doesn't go to 8 decimal place precision but still returns it so we go to 6 and pad - // with an extra 2 - $seconds = $lastUpdatedDate->__toString() / 1000; - $eTag = str_pad(number_format($seconds - floor($seconds), 6), 10, '0', STR_PAD_RIGHT) . ' ' . floor($seconds); + return ''; } - - return $eTag; + // PHP 5.3 used MongoDate::__toString() to generate the etag. + // This is incompatible with UTCDate::__toString() so we convert it into a microtime representation. + // This ensures that if it is required to dual run 2 PHP versions, there are no etag compatibility issues. + // Note that MongoDate doesn't go to 8 decimal place precision but still returns it so we go to 6 and pad + // with an extra 2 + $seconds = $lastUpdatedDate->__toString() / 1000; + + return str_pad(number_format($seconds - floor($seconds), 6), 10, '0', STR_PAD_RIGHT) . ' ' . floor($seconds); } /** @@ -613,14 +616,14 @@ public function getTripodTables() */ public function getSearchIndexer() { - if ($this->search_indexer == null) { - $this->search_indexer = new SearchIndexer($this, $this->readPreference); + if ($this->searchIndexer == null) { + $this->searchIndexer = new SearchIndexer($this, $this->readPreference); } - return $this->search_indexer; + return $this->searchIndexer; } - public function setTransactionLog(TransactionLog $transactionLog) + public function setTransactionLog(TransactionLog $transactionLog): void { $this->getDataUpdater()->setTransactionLog($transactionLog); } @@ -646,7 +649,7 @@ public function replayTransactionLog($fromDate = null, $toDate = null) * * @throws Exception when an unrecognised event type is given */ - public function registerHook($eventType, IEventHook $hook) + public function registerHook($eventType, IEventHook $hook): void { switch ($eventType) { case IEventHook::EVENT_SAVE_CHANGES: @@ -655,7 +658,7 @@ public function registerHook($eventType, IEventHook $hook) break; default: - throw new Exception("Unrecognised type {$eventType} whilst registering event hook"); + throw new Exception(sprintf('Unrecognised type %s whilst registering event hook', $eventType)); } } @@ -668,7 +671,7 @@ public function registerHook($eventType, IEventHook $hook) * * @throws Exception when an unsupported operation is requested */ - public function getComposite($operation) + public function getComposite(string $operation) { switch ($operation) { case OP_VIEWS: @@ -681,16 +684,14 @@ public function getComposite($operation) return $this->getSearchIndexer(); default: - throw new Exception("Undefined operation '{$operation}' requested"); + throw new Exception(sprintf("Undefined operation '%s' requested", $operation)); } } /** * For mocking. - * - * @return Labeller */ - protected function getLabeller() + protected function getLabeller(): \Tripod\Mongo\Labeller { return new Labeller(); } @@ -702,7 +703,7 @@ protected function getLabeller() */ protected function getDataUpdater() { - if (!isset($this->dataUpdater)) { + if (!property_exists($this, 'updates') || $this->updates === null) { $readPreference = $this->collection->__debugInfo()['readPreference']->getMode(); $opts = [ @@ -714,9 +715,9 @@ protected function getDataUpdater() 'statsConfig' => $this->statsConfig, ]; - $this->dataUpdater = new Updates($this, $opts); + $this->updates = new Updates($this, $opts); } - return $this->dataUpdater; + return $this->updates; } } diff --git a/src/mongo/IComposite.php b/src/mongo/IComposite.php index 453c258a..7cf629ee 100644 --- a/src/mongo/IComposite.php +++ b/src/mongo/IComposite.php @@ -1,5 +1,7 @@ operation = $operation; } else { - throw new Exception("Invalid operation: {$operation}"); + throw new Exception('Invalid operation: ' . $operation); } $this->storeName = $storeName; $this->podName = $podName; $this->specTypes = $specTypes; - if ($stat) { - $this->stat = $stat; + if ($stat instanceof \Tripod\ITripodStat) { + $this->tripodStat = $stat; } } @@ -115,9 +117,9 @@ public function getStoreName() /** * Serialises the data as an array. * - * @return array + * @return array */ - public function toArray() + public function toArray(): array { return [ 'resourceId' => $this->resourceId, @@ -131,21 +133,20 @@ public function toArray() /** * Perform the update on the composite defined by the operation. */ - public function update() + public function update(): void { $tripod = $this->getTripod(); - if (isset($this->stat)) { - $tripod->setStat($this->stat); + if (property_exists($this, 'tripodStat') && $this->tripodStat !== null) { + $tripod->setStat($this->tripodStat); } + $tripod->getComposite($this->operation)->update($this); } /** * For mocking. - * - * @return Driver */ - protected function getTripod() + protected function getTripod(): \Tripod\Mongo\Driver { return new Driver($this->getPodName(), $this->getStoreName(), [ 'readPreference' => ReadPreference::RP_PRIMARY, diff --git a/src/mongo/JobGroup.php b/src/mongo/JobGroup.php index 81b1ade8..1af612a6 100644 --- a/src/mongo/JobGroup.php +++ b/src/mongo/JobGroup.php @@ -1,5 +1,7 @@ id = $groupId; } @@ -35,7 +40,7 @@ public function __construct($storeName, $groupId = null) * * @param int $count Number of jobs in group */ - public function setJobCount($count) + public function setJobCount($count): void { $this->getMongoCollection()->updateOne( ['_id' => $this->getId()], @@ -61,6 +66,7 @@ public function incrementJobCount($inc = 1) if (\is_array($updateResult)) { return $updateResult['count']; } + if (isset($updateResult->count)) { return $updateResult->count; } @@ -81,7 +87,7 @@ public function getId() */ protected function getMongoCollection() { - if (!isset($this->collection)) { + if ($this->collection === null) { $config = Config::getInstance(); $this->collection = $config->getCollectionForJobGroups($this->storeName); diff --git a/src/mongo/Labeller.php b/src/mongo/Labeller.php index 1fd4a679..639e4387 100644 --- a/src/mongo/Labeller.php +++ b/src/mongo/Labeller.php @@ -1,5 +1,7 @@ _ns); + $prefix = array_search($ns, $this->_ns, true); if ($prefix != null && $prefix !== false) { return $prefix; } diff --git a/src/mongo/MongoGraph.php b/src/mongo/MongoGraph.php index 1c3d8f69..a8b9a924 100644 --- a/src/mongo/MongoGraph.php +++ b/src/mongo/MongoGraph.php @@ -1,5 +1,7 @@ |array> */ - public function to_tripod_view_array($docId, $context) + public function to_tripod_view_array($docId, $context): array { $subjects = $this->get_subjects(); $contextAlias = $this->_labeller->uri_to_alias($context); @@ -122,11 +125,11 @@ public function to_tripod_view_array($docId, $context) } /** - * @param array $tarray + * @param array $tarray * * @throws Exception */ - private function add_tarray_to_index($tarray) + private function add_tarray_to_index(array $tarray): void { $_i = []; $predObjects = []; @@ -134,6 +137,7 @@ private function add_tarray_to_index($tarray) if (empty($key)) { throw new Exception('The predicate cannot be an empty string'); } + if ($key[0] != '_') { $predicate = $this->qname_to_uri($key); $graphValueObject = $this->toGraphValueObject($value); @@ -148,6 +152,7 @@ private function add_tarray_to_index($tarray) } } } + $_i[$this->_labeller->qname_to_alias($tarray['_id'][_ID_RESOURCE])] = $predObjects; $this->add_json(json_encode($_i)); } @@ -155,11 +160,9 @@ private function add_tarray_to_index($tarray) /** * Convert from Tripod value object format (comapct) to ExtendedGraph format (verbose). * - * @param array $mongoValueObject - * - * @return array + * @param array $mongoValueObject */ - private function toGraphValueObject($mongoValueObject) + private function toGraphValueObject(array $mongoValueObject): array { $simpleGraphValueObject = []; @@ -188,13 +191,16 @@ private function toGraphValueObject($mongoValueObject) if (!$this->isValidLiteral($value)) { continue; } + $valueTypeLabel = 'literal'; } else { if (!$this->isValidResource($value)) { continue; } + $valueTypeLabel = 'uri'; } + $simpleGraphValueObject[] = [ 'type' => $valueTypeLabel, 'value' => ($type == VALUE_URI) ? $this->_labeller->qname_to_alias($value) : $value]; @@ -209,11 +215,9 @@ private function toGraphValueObject($mongoValueObject) /** * Convert from ExtendedGraph value object format (verbose) to Tripod format (compact). * - * @param array $simpleGraphValueObject - * - * @return array + * @param array $simpleGraphValueObject */ - private function toMongoTripodValueObject($simpleGraphValueObject) + private function toMongoTripodValueObject(array $simpleGraphValueObject): array { $valueTypeProp = ($simpleGraphValueObject['type'] == 'literal') ? VALUE_LITERAL : VALUE_URI; @@ -224,14 +228,13 @@ private function toMongoTripodValueObject($simpleGraphValueObject) /** * @param ExtendedGraph|null $graph * @param string $contextAlias - * - * @return array|null */ - private function index_to_tarray($graph = null, $contextAlias) + private function index_to_tarray($graph = null, $contextAlias = null): ?array { if ($graph == null) { $graph = $this; } + $_i = $graph->_index; foreach ($_i as $resource => $predObjects) { @@ -243,13 +246,14 @@ private function index_to_tarray($graph = null, $contextAlias) $doc['_id'] = $id; foreach ($predObjects as $predicate => $objects) { $pQName = $this->uri_to_qname($predicate); - if (count($objects) == 1) { + if (count($objects) === 1) { $doc[$pQName] = $this->toMongoTripodValueObject($objects[0]); } else { $values = []; foreach ($objects as $obj) { $values[] = $this->toMongoTripodValueObject($obj); } + $doc[$pQName] = $values; } } diff --git a/src/mongo/base/CompositeBase.php b/src/mongo/base/CompositeBase.php index e15bef12..6655feab 100644 --- a/src/mongo/base/CompositeBase.php +++ b/src/mongo/base/CompositeBase.php @@ -1,5 +1,7 @@ $resourceAlias, _ID_CONTEXT => $contextAlias]; } + $query = [_ID_KEY => ['$in' => $filter]]; $docs = $this->getCollection()->find( $query, @@ -67,11 +70,13 @@ public function getImpactedSubjects(array $subjectsAndPredicatesOfChange, $conte ) { $currentSubjectProperties = $subjectsAndPredicatesOfChange[$subjectsToAlias[$docResource]]; } + foreach ($docTypes as $type) { if ($this->checkIfTypeShouldTriggerOperation($type, $types, $currentSubjectProperties)) { if (!array_key_exists($this->getPodName(), $candidates)) { $candidates[$this->getPodName()] = []; } + if (!array_key_exists($docHash, $candidates[$this->getPodName()])) { $candidates[$this->getPodName()][$docHash] = ['id' => $doc[_ID_KEY]]; } @@ -87,6 +92,7 @@ public function getImpactedSubjects(array $subjectsAndPredicatesOfChange, $conte if (!array_key_exists($spec['from'], $candidates)) { $candidates[$spec['from']] = []; } + $docHash = md5($doc[_ID_KEY][_ID_RESOURCE] . $doc[_ID_KEY][_ID_CONTEXT]); if (!array_key_exists($docHash, $candidates[$spec['from']])) { @@ -97,9 +103,11 @@ public function getImpactedSubjects(array $subjectsAndPredicatesOfChange, $conte ], ]; } + if (!array_key_exists('specTypes', $candidates[$spec['from']][$docHash])) { $candidates[$spec['from']][$docHash]['specTypes'] = []; } + // Save the specification type so we only have to regen resources in that table type if (!in_array($doc[_ID_KEY][_ID_TYPE], $candidates[$spec['from']][$docHash]['specTypes'])) { $candidates[$spec['from']][$docHash]['specTypes'][] = $doc[_ID_KEY][_ID_TYPE]; @@ -171,7 +179,7 @@ protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes $intersectingTypes = array_unique(array_intersect($types, $validTypes)); // If views have a matching type *at all*, the operation is triggered - return !empty($intersectingTypes); + return $intersectingTypes !== []; } /** @@ -181,7 +189,7 @@ protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes */ protected function getApplyOperation() { - if (!isset($this->applyOperation)) { + if ($this->applyOperation === null) { $this->applyOperation = new ApplyOperation(); } diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index 8d2bac49..ab09a7a1 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -1,5 +1,7 @@ stat; } - public function setStat(ITripodStat $stat) + public function setStat(ITripodStat $stat): void { // TODO: how do we decouple this and still allow StatsD to know which db we're using? if ($stat instanceof StatsD) { $stat->setPivotValue($this->getStoreName()); } + $this->stat = $stat; } @@ -110,12 +115,10 @@ public function getStatsConfig() { $stat = $this->getStat(); if ($stat) { - $statConfig = $stat->getConfig(); - } else { - $statConfig = $this->statsConfig; + return $stat->getConfig(); } - return $statConfig; + return $this->statsConfig; } /** @@ -140,7 +143,7 @@ public function getPodName() * * @codeCoverageIgnore */ - public function timingLog($type, $params = null) + public function timingLog($type, $params = null): void { $type = '[PID ' . getmypid() . '] ' . $type; $this->log(LogLevel::DEBUG, $type, $params); @@ -152,7 +155,7 @@ public function timingLog($type, $params = null) * * @codeCoverageIgnore */ - public function infoLog($message, $params = null) + public function infoLog($message, $params = null): void { $message = '[PID ' . getmypid() . '] ' . $message; $this->log(LogLevel::INFO, $message, $params); @@ -164,7 +167,7 @@ public function infoLog($message, $params = null) * * @codeCoverageIgnore */ - public function debugLog($message, $params = null) + public function debugLog($message, $params = null): void { $message = '[PID ' . getmypid() . '] ' . $message; $this->log(LogLevel::DEBUG, $message, $params); @@ -176,7 +179,7 @@ public function debugLog($message, $params = null) * * @codeCoverageIgnore */ - public function errorLog($message, $params = null) + public function errorLog($message, $params = null): void { $message = '[PID ' . getmypid() . '] ' . $message; $this->log(LogLevel::ERROR, $message, $params); @@ -188,7 +191,7 @@ public function errorLog($message, $params = null) * * @codeCoverageIgnore */ - public function warningLog($message, $params = null) + public function warningLog($message, $params = null): void { $message = '[PID ' . getmypid() . '] ' . $message; $this->log(LogLevel::WARNING, $message, $params); @@ -244,7 +247,7 @@ protected function getContextAlias($context = null) } /** - * @param array $query + * @param array $query * @param string $type * @param Collection|null $collection * @param array $includeProperties @@ -252,7 +255,7 @@ protected function getContextAlias($context = null) * * @return MongoGraph */ - protected function fetchGraph($query, $type, $collection = null, $includeProperties = [], $cursorSize = 101) + protected function fetchGraph(array $query, $type, $collection = null, $includeProperties = [], $cursorSize = 101) { $graph = new MongoGraph(); @@ -273,6 +276,7 @@ protected function fetchGraph($query, $type, $collection = null, $includePropert foreach ($includeProperties as $property) { $fields[$this->labeller->uri_to_alias($property)] = true; } + $cursor = $collection->find($query, [ 'projection' => $fields, 'batchSize' => $cursorSize, @@ -298,8 +302,10 @@ protected function fetchGraph($query, $type, $collection = null, $includePropert $this->generateView($result['_id']['type'], $result['_id']['r']); } } + $graph->add_tripod_array($result); } + $cursorSuccess = true; } catch (\Exception $e) { self::getLogger()->error('CursorException attempt ' . $retries . '. Retrying...:' . $e->getMessage()); @@ -325,12 +331,12 @@ protected function fetchGraph($query, $type, $collection = null, $includePropert $this->timingLog($type, ['duration' => $t->result(), 'query' => $query, 'collection' => $collectionName]); if ($type == MONGO_VIEW) { if (array_key_exists('_id.type', $query)) { - $this->getStat()->timer("{$type}.{$query['_id.type']}", $t->result()); + $this->getStat()->timer(sprintf('%s.%s', $type, $query['_id.type']), $t->result()); } elseif (array_key_exists('_id', $query) && array_key_exists('type', $query['_id'])) { - $this->getStat()->timer("{$type}.{$query['_id']['type']}", $t->result()); + $this->getStat()->timer(sprintf('%s.%s', $type, $query['_id']['type']), $t->result()); } } else { - $this->getStat()->timer("{$type}.{$collectionName}", $t->result()); + $this->getStat()->timer(sprintf('%s.%s', $type, $collectionName), $t->result()); } return $graph; @@ -340,9 +346,9 @@ protected function fetchGraph($query, $type, $collection = null, $includePropert * Expands an RDF sequence into proper tripod join clauses. * * @param array $joins - * @param array $source + * @param array $source */ - protected function expandSequence(&$joins, $source) + protected function expandSequence(&$joins, array $source) { if (!empty($joins) && isset($joins['followSequence'])) { // add any rdf:_x style properties in the source to the joins array, @@ -362,6 +368,7 @@ protected function expandSequence(&$joins, $source) } } } + unset($joins['followSequence']); } } @@ -369,12 +376,13 @@ protected function expandSequence(&$joins, $source) /** * Adds an _id object (or array of _id objects) to the target document's impact index. * - * @param array &$target + * @param array &$target * @param mixed $buildImpactIndex * * @throws \InvalidArgumentException + * @param array $id */ - protected function addIdToImpactIndex(array $id, &$target, $buildImpactIndex = true) + protected function addIdToImpactIndex(array $id, array &$target, $buildImpactIndex = true) { if ($buildImpactIndex) { if (isset($id[_ID_RESOURCE])) { @@ -383,6 +391,7 @@ protected function addIdToImpactIndex(array $id, &$target, $buildImpactIndex = t if (!isset($target[_IMPACT_INDEX])) { $target[_IMPACT_INDEX] = []; } + if (!in_array($id, $target[_IMPACT_INDEX])) { $target[_IMPACT_INDEX][] = $id; } @@ -391,6 +400,7 @@ protected function addIdToImpactIndex(array $id, &$target, $buildImpactIndex = t if (!isset($i[_ID_RESOURCE])) { throw new \InvalidArgumentException('Invalid id format'); } + $this->addIdToImpactIndex($i, $target); } } @@ -412,7 +422,7 @@ protected function getConfigInstance() */ protected function getDatabase() { - if (!isset($this->db)) { + if ($this->db === null) { $this->db = $this->config->getDatabase( $this->storeName, $this->config->getDataSourceForPod($this->storeName, $this->podName), @@ -428,7 +438,7 @@ protected function getDatabase() */ protected function getCollection() { - if (!isset($this->collection)) { + if ($this->collection === null) { $this->collection = $this->getDatabase()->selectCollection($this->podName); } @@ -444,27 +454,26 @@ protected function applyHooks($fn, $hooks, $args = []) break; default: - throw new Exception("Invalid hook function {$fn} requested"); + throw new Exception(sprintf('Invalid hook function %s requested', $fn)); } + foreach ($hooks as $hook) { try { // @var $hook IEventHook $hook->{$fn}($args); } catch (\Exception $e) { // don't let rabid hooks stop tripod - static::getLogger()->error('Hook ' . get_class($hook) . " threw exception {$e->getMessage()}, continuing"); + static::getLogger()->error('Hook ' . get_class($hook) . sprintf(' threw exception %s, continuing', $e->getMessage())); } } } /** - * @param string $level - * @param string $message * @param array|null $params * * @codeCoverageIgnore */ - private function log($level, $message, $params) + private function log(string $level, string $message, $params): void { ($params == null) ? self::getLogger()->log($level, $message) : self::getLogger()->log($level, $message, $params); } @@ -480,6 +489,8 @@ final class NoStat implements ITripodStat /** * @param string $operation * @param int|number $inc + * + * @return void */ public function increment($operation, $inc = 1) { @@ -489,6 +500,8 @@ public function increment($operation, $inc = 1) /** * @param string $operation * @param number $duration + * + * @return void */ public function timer($operation, $duration) { @@ -496,9 +509,9 @@ public function timer($operation, $duration) } /** - * @return array + * @return array{} */ - public function getConfig() + public function getConfig(): array { return []; } diff --git a/src/mongo/base/JobBase.php b/src/mongo/base/JobBase.php index 4cda81c4..8b82ea4b 100644 --- a/src/mongo/base/JobBase.php +++ b/src/mongo/base/JobBase.php @@ -1,5 +1,7 @@ debugLog( '[JOBID ' . $this->job->payload['id'] . '] ' . get_class($this) . '::perform() start' @@ -67,13 +72,13 @@ public function setUp() } } - public function tearDown() + public function tearDown(): void { // stat time taken to process item, from time it was created (queued) $this->timer->stop(); $this->debugLog( '[JOBID ' . $this->job->payload['id'] . '] ' . get_class($this) - . "::perform() done in {$this->timer->result()}ms" + . sprintf('::perform() done in %sms', $this->timer->result()) ); $this->getStat()->timer($this->getStatTimerSuccessKey(), $this->timer->result()); } @@ -88,7 +93,7 @@ abstract public function perform(); * * @param \Resque_Job The queued job */ - public static function beforePerform(\Resque_Job $job) + public static function beforePerform(\Resque_Job $job): void { $instance = $job->getInstance(); if (!$instance instanceof self) { @@ -104,7 +109,7 @@ public static function beforePerform(\Resque_Job $job) * @param \Exception|\Throwable $e Exception or Error * @param \Resque_Job $job The failed job */ - public static function onFailure($e, \Resque_Job $job) + public static function onFailure($e, \Resque_Job $job): void { $failedJob = $job->getInstance(); if (!$failedJob instanceof self) { @@ -119,7 +124,7 @@ public static function onFailure($e, \Resque_Job $job) * @param string $message Log message * @param mixed $params Log params */ - public function debugLog($message, $params = null) + public function debugLog($message, $params = null): void { parent::debugLog($message, $params); } @@ -128,7 +133,7 @@ public function debugLog($message, $params = null) * @param string $message Log message * @param mixed $params Log params */ - public function errorLog($message, $params = null) + public function errorLog($message, $params = null): void { parent::errorLog($message, $params); } @@ -138,7 +143,7 @@ public function errorLog($message, $params = null) */ public function getStat() { - if (!isset($this->statsConfig)) { + if ($this->statsConfig === null) { $this->getStatsConfig(); } @@ -152,7 +157,7 @@ public function getStat() */ public function getStatsConfig() { - if (empty($this->statsConfig)) { + if ($this->statsConfig === []) { $this->setStatsConfig(); } @@ -224,12 +229,13 @@ protected function validateArgs() $message = null; foreach ($this->getMandatoryArgs() as $arg) { if (!isset($this->args[$arg])) { - $message = "Argument {$arg} was not present in supplied job args for job " . get_class($this); + $message = sprintf('Argument %s was not present in supplied job args for job ', $arg) . get_class($this); $this->errorLog($message); throw new \Exception($message); } } + if ($this->configRequired) { $this->ensureConfig(); } @@ -249,7 +255,7 @@ protected function ensureConfig() /** * @param string $queueName Queue name * @param string $class Class name - * @param array $data Job arguments + * @param array $data Job arguments * @param int $retryAttempts If queue fails, retry x times before throwing an exception * * @return string A tracking token for the submitted job @@ -263,25 +269,28 @@ protected function submitJob($queueName, $class, array $data, $retryAttempts = 5 if (isset($data[self::TRIPOD_CONFIG_GENERATOR]) && $data[self::TRIPOD_CONFIG_GENERATOR]) { $data[self::TRIPOD_CONFIG_GENERATOR] = $this->serializeConfig($data[self::TRIPOD_CONFIG_GENERATOR]); } + $token = $this->enqueue($queueName, $class, $data); if (!$this->getJobStatus($token)) { - $this->errorLog("Could not retrieve status for queued {$class} job - job {$token} failed to {$queueName}"); + $this->errorLog(sprintf('Could not retrieve status for queued %s job - job %s failed to %s', $class, $token, $queueName)); - throw new \Exception("Could not retrieve status for queued job - job {$token} failed to {$queueName}"); + throw new \Exception(sprintf('Could not retrieve status for queued job - job %s failed to %s', $token, $queueName)); } - $this->debugLog("Queued {$class} job with {$token} to {$queueName}"); + + $this->debugLog(sprintf('Queued %s job with %s to %s', $class, $token, $queueName)); return $token; } catch (\Exception $e) { if ($retryAttempts > 0) { sleep(1); // back off for 1 sec - $this->warningLog("Exception queuing {$class} job - {$e->getMessage()}, retrying {$retryAttempts} times"); + $this->warningLog(sprintf('Exception queuing %s job - %s, retrying %d times', $class, $e->getMessage(), $retryAttempts)); return $this->submitJob($queueName, $class, $data, --$retryAttempts); } - $this->errorLog("Exception queuing {$class} job - {$e->getMessage()}"); - throw new JobException("Exception queuing job - {$e->getMessage()}", $e->getCode(), $e); + $this->errorLog(sprintf('Exception queuing %s job - %s', $class, $e->getMessage())); + + throw new JobException('Exception queuing job - ' . $e->getMessage(), $e->getCode(), $e); } } @@ -327,6 +336,7 @@ protected function serializeConfig($configSerializer) if ($configSerializer instanceof ITripodConfigSerializer) { return $configSerializer->serialize(); } + if (is_array($configSerializer)) { return $configSerializer; } @@ -360,6 +370,7 @@ protected function setTripodConfig() } else { $config = $this->args[self::TRIPOD_CONFIG_KEY]; } + $this->tripodConfig = $this->deserializeConfig($config); } @@ -370,7 +381,7 @@ protected function setTripodConfig() */ protected function getTripodConfig() { - if (!isset($this->tripodConfig)) { + if ($this->tripodConfig === null) { $this->ensureConfig(); $this->setTripodConfig(); } @@ -391,7 +402,7 @@ protected function setStatsConfig() /** * Tripod options to pass between jobs. * - * @return array + * @return array */ protected function getTripodOptions() { @@ -407,7 +418,7 @@ protected function getTripodOptions() /** * Convenience method to pass config to job data. * - * @return array + * @return array */ protected function generateConfigJobArgs() { @@ -418,6 +429,7 @@ protected function generateConfigJobArgs() } else { $config = Config::getConfig(); } + if (isset($config['class'])) { $args[self::TRIPOD_CONFIG_GENERATOR] = $config; } else { diff --git a/src/mongo/delegates/SearchDocuments.php b/src/mongo/delegates/SearchDocuments.php index 68b3d451..e39674f6 100644 --- a/src/mongo/delegates/SearchDocuments.php +++ b/src/mongo/delegates/SearchDocuments.php @@ -1,5 +1,7 @@ getSearchDocumentSpecification($specId); if (empty($searchSpec)) { - $this->debugLog("Could not find Search Document Specification for {$specId}"); + $this->debugLog('Could not find Search Document Specification for ' . $specId); return null; } - if (isset($searchSpec['from'])) { - $from = $searchSpec['from']; - } else { - $from = $this->podName; - } + $from = $searchSpec['from'] ?? $this->podName; // work out whether or not to index at all $proceedWithGeneration = false; @@ -66,7 +63,7 @@ public function generateSearchDocumentBasedOnSpecId($specId, $resource, $context foreach ($searchSpec['filter'] as $indexRules) { // run a query to work out if (!empty($indexRules['condition'])) { - $irFrom = (!empty($indexRules['from'])) ? $indexRules['from'] : $this->podName; + $irFrom = (empty($indexRules['from'])) ? $this->podName : $indexRules['from']; // add id of current record to rules.. $indexRules['condition']['_id'] = [ 'r' => $this->labeller->uri_to_alias($resource), @@ -82,8 +79,8 @@ public function generateSearchDocumentBasedOnSpecId($specId, $resource, $context } } - if ($proceedWithGeneration == false) { - $this->debugLog("Unable to proceed with generating {$specId} search document for {$resource}, does not satisfy rules"); + if ($proceedWithGeneration === false) { + $this->debugLog(sprintf('Unable to proceed with generating %s search document for %s, does not satisfy rules', $specId, $resource)); return null; } @@ -96,12 +93,12 @@ public function generateSearchDocumentBasedOnSpecId($specId, $resource, $context $sourceDocument = $this->getConfigInstance()->getCollectionForCBD($this->storeName, $from)->findOne(['_id' => $_id]); if (empty($sourceDocument)) { - $this->debugLog("Source document not found for {$resource}, cannot proceed generating {$specId} search document"); + $this->debugLog(sprintf('Source document not found for %s, cannot proceed generating %s search document', $resource, $specId)); return null; } - $this->debugLog("Processing {$specId}"); + $this->debugLog('Processing ' . $specId); // build the document $generatedDocument = [\_CREATED_TS => DateUtil::getMongoDate()]; @@ -113,9 +110,11 @@ public function generateSearchDocumentBasedOnSpecId($specId, $resource, $context if (isset($searchSpec['fields'])) { $this->addFields($sourceDocument, $searchSpec['fields'], $generatedDocument); } + if (isset($searchSpec['indices'])) { $this->addFields($sourceDocument, $searchSpec['indices'], $generatedDocument, true); } + if (isset($searchSpec['joins'])) { $this->doJoin($sourceDocument, $searchSpec['joins'], $generatedDocument, $from); } @@ -127,15 +126,15 @@ public function generateSearchDocumentBasedOnSpecId($specId, $resource, $context * @param string $resource * @param string $context * - * @return array * * @throws \Exception */ - public function generateSearchDocumentsBasedOnRdfTypes(array $rdfTypes, $resource, $context) + public function generateSearchDocumentsBasedOnRdfTypes(array $rdfTypes, $resource, $context): array { if (empty($resource)) { throw new \Exception('Resource must be specified'); } + if (empty($context)) { throw new \Exception('Context must be specified'); } @@ -157,27 +156,24 @@ public function generateSearchDocumentsBasedOnRdfTypes(array $rdfTypes, $resourc $generatedSearchDocuments[] = $this->generateSearchDocumentBasedOnSpecId($searchSpec['_id'], $resource, $context); } } + $timer->stop(); // echo "\n\tTook " . $timer->result() . " ms to generate search documents\n"; return $generatedSearchDocuments; } - /** - * @return string - */ - public function getSearchCollectionName() + public function getSearchCollectionName(): string { return SEARCH_INDEX_COLLECTION; } /** - * @param array $source * @param array $joins * @param array $target * @param string $from */ - protected function doJoin($source, $joins, &$target, $from) + protected function doJoin(array $source, $joins, &$target, $from) { // expand sequences before proceeding $this->expandSequence($joins, $source); @@ -257,6 +253,7 @@ protected function addFields(array $source, array $fieldsOrIndices, array &$targ } } } + // now add the values $this->addValuesToTarget($values, $f, $target); } @@ -269,6 +266,7 @@ protected function addFields(array $source, array $fieldsOrIndices, array &$targ if ($f['value'] == '_link_') { $this->warningLog("Search spec value '_link_' is deprecated", $f); } + $values[] = $this->labeller->qname_to_alias($source['_id']['r']); } @@ -288,11 +286,10 @@ protected function getSearchDocumentSpecification($specId) } /** - * @param array $values - * @param array $field - * @param array $target + * @param array $field + * @param array $values */ - private function addValuesToTarget($values, $field, &$target) + private function addValuesToTarget(array $values, array $field, array &$target): void { $objName = null; $name = $field['fieldName']; @@ -301,19 +298,13 @@ private function addValuesToTarget($values, $field, &$target) $parts = explode('.', $name); $objName = $parts[0]; $name = $parts[1]; - } // todo: if theres more than 2 parts throw error - - $limit = null; - if (isset($field['limit'])) { - $limit = $field['limit']; - } else { - $limit = count($values); } + $limit = $field['limit'] ?? count($values); - if (count($values) > 0) { + if ($values !== []) { for ($i = 0; $i < $limit; $i++) { $v = $values[$i]; - if (empty($objName)) { + if (in_array($objName, [null, '', '0'], true)) { if (!isset($target[$name])) { $target[$name] = $v; } elseif (is_array($target[$name])) { @@ -324,17 +315,15 @@ private function addValuesToTarget($values, $field, &$target) $target[$name][] = $existingVal; $target[$name][] = $v; } + } elseif (!isset($target[$objName][$name])) { + $target[$objName][$name] = $v; + } elseif (is_array($target[$objName][$name])) { + $target[$objName][$name][] = $v; } else { - if (!isset($target[$objName][$name])) { - $target[$objName][$name] = $v; - } elseif (is_array($target[$objName][$name])) { - $target[$objName][$name][] = $v; - } else { - $existingVal = $target[$objName][$name]; - $target[$objName][$name] = []; - $target[$objName][$name][] = $existingVal; - $target[$objName][$name][] = $v; - } + $existingVal = $target[$objName][$name]; + $target[$objName][$name] = []; + $target[$objName][$name][] = $existingVal; + $target[$objName][$name][] = $v; } } } diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 8e9709fd..6a6d11b8 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -1,5 +1,7 @@ getResourceId(); $resourceUri = $resource[_ID_RESOURCE]; @@ -70,10 +73,8 @@ public function getTypesInSpecifications() /** * Returns the operation this composite can satisfy. - * - * @return string */ - public function getOperationType() + public function getOperationType(): string { return OP_SEARCH; } @@ -97,7 +98,7 @@ public function getSpecification($storeName, $specId) * @param string $podName * @param array|string|null $specType */ - public function generateAndIndexSearchDocuments($resourceUri, $context, $podName, $specType = []) + public function generateAndIndexSearchDocuments($resourceUri, $context, $podName, $specType = []): void { $mongoCollection = $this->config->getCollectionForCBD($this->storeName, $podName); @@ -152,19 +153,17 @@ public function generateAndIndexSearchDocuments($resourceUri, $context, $podName } /** - * @param string $searchDocumentType * @param string|null $resourceUri * @param string|null $context * @param string|null $queueName - * * @return array|null Will return an array with a count and group id, if $queueName is sent and $resourceUri is null */ public function generateSearchDocuments( - $searchDocumentType, + string $searchDocumentType, $resourceUri = null, $context = null, $queueName = null - ) { + ): ?array { $t = new Timer(); $t->start(); // default the context @@ -174,7 +173,7 @@ public function generateSearchDocuments( if ($resourceUri) { $this->generateAndIndexSearchDocuments($resourceUri, $contextAlias, $spec['from'], $searchDocumentType); - return; + return null; } // default collection @@ -190,6 +189,7 @@ public function generateSearchDocuments( $types[] = ['rdf:type.u' => $this->labeller->qname_to_alias($spec['type'])]; $types[] = ['rdf:type.u' => $this->labeller->uri_to_alias($spec['type'])]; } + $filter = ['$or' => $types]; if (isset($resource)) { $filter['_id'] = [_ID_RESOURCE => $this->labeller->uri_to_alias($resource), _ID_CONTEXT => $contextAlias]; @@ -211,6 +211,7 @@ public function generateSearchDocuments( $jobOptions[ApplyOperation::TRACKING_KEY] = $jobGroup->getId()->__toString(); $jobGroup->setJobCount($count); } + foreach ($docs as $doc) { if ($queueName && !$resourceUri) { $subject = new ImpactedSubject( @@ -237,7 +238,7 @@ public function generateSearchDocuments( } } - if (!empty($subjects)) { + if ($subjects !== []) { $this->queueApplyJob($subjects, $queueName, $jobOptions); } @@ -247,7 +248,7 @@ public function generateSearchDocuments( 'duration' => $t->result(), 'filter' => $filter, 'from' => $from]); - $this->getStat()->timer(MONGO_CREATE_SEARCH_DOC . ".{$searchDocumentType}", $t->result()); + $this->getStat()->timer(MONGO_CREATE_SEARCH_DOC . ('.' . $searchDocumentType), $t->result()); $stat = ['count' => $count]; if (isset($jobOptions[ApplyOperation::TRACKING_KEY])) { @@ -282,23 +283,18 @@ public function deleteSearchDocumentsByTypeId($typeId) */ protected function getSearchProvider() { - return $this->configuredProvider; + return $this->searchProvider; } /** * @param string $context - * - * @return SearchDocuments */ - protected function getSearchDocumentGenerator(Collection $collection, $context) + protected function getSearchDocumentGenerator(Collection $collection, $context): \Tripod\Mongo\SearchDocuments { return new SearchDocuments($this->storeName, $collection, $context, $this->tripod->getStat()); } - /** - * @return array - */ - protected function deDupe(array $input) + protected function deDupe(array $input): array { $output = []; foreach ($input as $i) { @@ -326,10 +322,10 @@ protected function setSearchProvider(Driver $tripod, ?IConfigInstance $config = $provider = $config->getSearchProviderClassName($tripod->getStoreName()); if (class_exists($provider)) { - $this->configuredProvider = new $provider($tripod); + $this->searchProvider = new $provider($tripod); } else { throw new SearchException( - "Did not recognise Search Provider, or could not find class: {$provider}" + 'Did not recognise Search Provider, or could not find class: ' . $provider ); } } diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index ec57c828..6182ff95 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -1,5 +1,7 @@ getResourceId(); $resourceUri = $resource[_ID_RESOURCE]; @@ -126,10 +128,8 @@ public function getTypesInSpecifications() * Returns an array of table rows that are impacted by the changes. * * @param string $contextAlias - * - * @return array */ - public function findImpactedComposites(array $resourcesAndPredicates, $contextAlias) + public function findImpactedComposites(array $resourcesAndPredicates, $contextAlias): array { $contextAlias = $this->getContextAlias($contextAlias); // belt and braces @@ -150,7 +150,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl $id = [_ID_RESOURCE => $resourceAlias, _ID_CONTEXT => $contextAlias]; // If we don't have a working config or there are no predicates listed, remove all // rows associated with the resource in all tables - if (empty($tablePredicates) || empty($resourcePredicates)) { + if ($tablePredicates === [] || empty($resourcePredicates)) { // build $filter for queries to impact index $resourceFilters[] = $id; } else { @@ -160,6 +160,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl if (!isset($tableFilters[$tableType])) { $tableFilters[$tableType] = []; } + // build $filter for queries to impact index $tableFilters[$tableType][] = $id; } @@ -167,7 +168,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl } } - if (empty($tableFilters) && !empty($resourceFilters)) { + if ($tableFilters === [] && $resourceFilters !== []) { $query = ['value.' . _IMPACT_INDEX => ['$in' => $resourceFilters]]; } else { $query = []; @@ -176,7 +177,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl $query[] = ['value.' . _IMPACT_INDEX => ['$in' => $filters], '_id.' . _ID_TYPE => $tableType]; } - if (!empty($resourceFilters)) { + if ($resourceFilters !== []) { $query[] = ['value.' . _IMPACT_INDEX => ['$in' => $resourceFilters]]; } @@ -187,7 +188,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl } } - if (empty($query)) { + if ($query === []) { return []; } @@ -220,10 +221,8 @@ public function getSpecification($storeName, $tableSpecId) /** * Returns the operation this composite can satisfy. - * - * @return string */ - public function getOperationType() + public function getOperationType(): string { return OP_TABLES; } @@ -231,21 +230,21 @@ public function getOperationType() /** * Query the tables collection and return the results. * - * @param string $tableSpecId * @param int $offset * @param int $limit - * @param array $options Table query options + * @param array $options Table query options * - * @return array + * @return array + * @param array $filter */ public function getTableRows( - $tableSpecId, + string $tableSpecId, array $filter = [], array $sortBy = [], $offset = 0, $limit = 10, array $options = [] - ) { + ): array { $t = new Timer(); $t->start(); @@ -271,17 +270,12 @@ public function getTableRows( $findOptions['skip'] = (int) $offset; $findOptions['limit'] = (int) $limit; } - if (isset($sortBy)) { - $findOptions['sort'] = $sortBy; - } + + $findOptions['sort'] = $sortBy; $results = $collection->find($filter, $findOptions); - if ($options['includeCount']) { - $count = $collection->count($filter); - } else { - $count = -1; - } + $count = $options['includeCount'] ? $collection->count($filter) : -1; $results->setTypeMap(['root' => $options['documentType'], 'document' => 'array', 'array' => 'array']); @@ -290,7 +284,7 @@ public function getTableRows( MONGO_TABLE_ROWS, ['duration' => $t->result(), 'query' => $filter, 'collection' => TABLE_ROWS_COLLECTION] ); - $this->getStat()->timer(MONGO_TABLE_ROWS . ".{$tableSpecId}", $t->result()); + $this->getStat()->timer(MONGO_TABLE_ROWS . ('.' . $tableSpecId), $t->result()); return [ 'head' => [ @@ -305,12 +299,11 @@ public function getTableRows( /** * Returns the distinct values for a table column, optionally filtered by query. * - * @param string $tableSpecId - * @param string $fieldName * - * @return array + * @return array + * @param array $filter */ - public function distinct($tableSpecId, $fieldName, array $filter = []) + public function distinct(string $tableSpecId, string $fieldName, array $filter = []): array { $t = new Timer(); $t->start(); @@ -323,7 +316,7 @@ public function distinct($tableSpecId, $fieldName, array $filter = []) $t->stop(); $query = ['distinct' => $fieldName, 'filter' => $filter]; $this->timingLog(MONGO_TABLE_ROWS_DISTINCT, ['duration' => $t->result(), 'query' => $query, 'collection' => TABLE_ROWS_COLLECTION]); - $this->getStat()->timer(MONGO_TABLE_ROWS_DISTINCT . ".{$tableSpecId}", $t->result()); + $this->getStat()->timer(MONGO_TABLE_ROWS_DISTINCT . ('.' . $tableSpecId), $t->result()); return [ 'head' => [ @@ -341,13 +334,14 @@ public function distinct($tableSpecId, $fieldName, array $filter = []) * * @return int The number of table rows deleted */ - public function deleteTableRowsByTableId($tableId, $timestamp = null) + public function deleteTableRowsByTableId(string $tableId, $timestamp = null) { $t = new Timer(); $t->start(); + $tableSpec = $this->getConfigInstance()->getTableSpecification($this->storeName, $tableId); if ($tableSpec == null) { - $this->debugLog("Could not find a table specification for {$tableId}"); + $this->debugLog('Could not find a table specification for ' . $tableId); return; } @@ -357,11 +351,13 @@ public function deleteTableRowsByTableId($tableId, $timestamp = null) if (!$timestamp instanceof UTCDateTime) { $timestamp = DateUtil::getMongoDate($timestamp); } + $query['$or'] = [ [\_CREATED_TS => ['$lt' => $timestamp]], [\_CREATED_TS => ['$exists' => false]], ]; } + $deleteResult = $this->getCollectionForTableSpec($tableId) ->deleteMany($query); @@ -378,10 +374,8 @@ public function deleteTableRowsByTableId($tableId, $timestamp = null) * @param string|null $subject * @param string|null $context * @param array $specTypes - * - * @return mixed */ - public function generateTableRowsForType($rdfType, $subject = null, $context = null, $specTypes = []) + public function generateTableRowsForType($rdfType, $subject = null, $context = null, $specTypes = []): void { $rdfType = $this->labeller->qname_to_alias($rdfType); $rdfTypeAlias = $this->labeller->uri_to_alias($rdfType); @@ -405,38 +399,39 @@ public function generateTableRowsForType($rdfType, $subject = null, $context = n if (!is_array($types)) { $types = [$types]; } + if (in_array($rdfType, $types) || in_array($rdfTypeAlias, $types)) { $foundSpec = true; - $this->debugLog("Processing {$tableSpec[_ID_KEY]}"); + $this->debugLog('Processing ' . $tableSpec[_ID_KEY]); $this->generateTableRows($key, $subject, $context); } } } + if (!$foundSpec) { - $this->debugLog("Could not find any table specifications for {$subject} with resource type '{$rdfType}'"); + $this->debugLog(sprintf("Could not find any table specifications for %s with resource type '%s'", $subject, $rdfType)); return; } } /** - * @param string $tableType * @param string|null $resource * @param string|null $context * @param string|null $queueName Queue for background bulk generation - * * @return array */ - public function generateTableRows($tableType, $resource = null, $context = null, $queueName = null) + public function generateTableRows(string $tableType, $resource = null, $context = null, $queueName = null): ?array { $t = new Timer(); $t->start(); + $this->temporaryFields = []; $tableSpec = $this->getConfigInstance()->getTableSpecification($this->storeName, $tableType); $collection = $this->getConfigInstance()->getCollectionForTable($this->storeName, $tableType); if (empty($tableSpec)) { - $this->debugLog("Could not find a table specification for {$tableType}"); + $this->debugLog('Could not find a table specification for ' . $tableType); return null; } @@ -457,6 +452,7 @@ public function generateTableRows($tableType, $resource = null, $context = null, $types[] = ['rdf:type.u' => $this->labeller->qname_to_alias($tableSpec['type'])]; $types[] = ['rdf:type.u' => $this->labeller->uri_to_alias($tableSpec['type'])]; } + $filter = ['$or' => $types]; if (isset($resource)) { $filter['_id'] = [ @@ -473,7 +469,7 @@ public function generateTableRows($tableType, $resource = null, $context = null, $jobOptions = []; $subjects = []; - if ($queueName && !$resource && ($this->stat || !empty($this->statsConfig))) { + if ($queueName && !$resource && ($this->stat || $this->statsConfig !== [])) { $jobOptions['statsConfig'] = $this->getStatsConfig(); $jobGroup = $this->getJobGroup($this->storeName); $jobOptions[ApplyOperation::TRACKING_KEY] = $jobGroup->getId()->__toString(); @@ -511,6 +507,7 @@ public function generateTableRows($tableType, $resource = null, $context = null, if (isset($tableSpec['joins'])) { $this->doJoins($doc, $tableSpec['joins'], $value, $from, $contextAlias); } + if (isset($tableSpec['counts'])) { $this->doCounts($doc, $tableSpec['counts'], $value); } @@ -526,7 +523,7 @@ public function generateTableRows($tableType, $resource = null, $context = null, } } - if (!empty($subjects)) { + if ($subjects !== []) { $this->queueApplyJob($subjects, $queueName, $jobOptions); } @@ -536,7 +533,7 @@ public function generateTableRows($tableType, $resource = null, $context = null, 'duration' => $t->result(), 'filter' => $filter, 'from' => $from]); - $this->getStat()->timer(MONGO_CREATE_TABLE . ".{$tableType}", $t->result()); + $this->getStat()->timer(MONGO_CREATE_TABLE . ('.' . $tableType), $t->result()); $stat = ['count' => $count]; if (isset($jobOptions[ApplyOperation::TRACKING_KEY])) { @@ -550,7 +547,7 @@ public function generateTableRows($tableType, $resource = null, $context = null, * Count the number of documents in the spec that match $filters. * * @param string $tableSpec Table spec ID - * @param array $filters Query filters to get count on + * @param array $filters Query filters to get count on * * @return int */ @@ -578,15 +575,14 @@ protected function deleteTableRowsForResource($resource, $context = null, $specT $specTypes = $this->config->getTableSpecifications($this->storeName); if (empty($specType)) { $specNames = array_keys($specTypes); - } else { - if (is_string($specType)) { - $query[_ID_KEY][_ID_TYPE] = $specType; - $specNames = [$specType]; - } elseif (is_array($specType)) { - $query[_ID_KEY . '.' . _ID_TYPE] = ['$in' => $specType]; - $specNames = $specType; - } + } elseif (is_string($specType)) { + $query[_ID_KEY][_ID_TYPE] = $specType; + $specNames = [$specType]; + } elseif (is_array($specType)) { + $query[_ID_KEY . '.' . _ID_TYPE] = ['$in' => $specType]; + $specNames = $specType; } + foreach ($specNames as $specName) { // Ignore any other types of specs that might have been passed in here if (isset($specTypes[$specName])) { @@ -646,7 +642,7 @@ protected function generateTableRowsForResource($resource, $context = null, $spe * If an exception in thrown because a field is too large to index, the field is * truncated and the save is retried. * - * @param array $generatedRow the rows to save + * @param array|array $generatedRow the rows to save * * @throws \Exception */ @@ -668,7 +664,7 @@ protected function truncatingSave(Collection $collection, array $generatedRow) /** * Truncate any indexed fields in the generated rows which are too large to index. * - * @param array $generatedRow - Pass by reference so that the contents is truncated + * @param array $generatedRow - Pass by reference so that the contents is truncated */ protected function truncateFields(Collection $collection, array &$generatedRow) { @@ -690,7 +686,7 @@ protected function truncateFields(Collection $collection, array &$generatedRow) } } - if (count($indexedFields) > 0 && isset($generatedRow['value']) && is_array($generatedRow['value'])) { + if ($indexedFields !== [] && isset($generatedRow['value']) && is_array($generatedRow['value'])) { // Iterate over generated rows BY REFERENCE (&) - we are going to modify the contents of $field foreach ($generatedRow as &$field) { foreach ($indexedFields as $indexedFieldname) { @@ -698,21 +694,18 @@ protected function truncateFields(Collection $collection, array &$generatedRow) // Adjust the max key size allowed to take it into account. $maxKeySize = 1020 - strlen('value_' . $indexedFieldname . '_1'); - if (array_key_exists($indexedFieldname, $field)) { - // It's important that we count the number of bytes - // in the field - not just the number of characters. - // UTF-8 characters can be between 1 and 4 bytes. - // - // From the strlen documentation: - // Attention with utf8: - // $foo = "bär"; - // strlen($foo) will return 4 and not 3 as expected.. - // - // So strlen does count the bytes - not the characters. - - if (is_string($field[$indexedFieldname]) && strlen($field[$indexedFieldname]) > $maxKeySize) { - $field[$indexedFieldname] = substr($field[$indexedFieldname], 0, $maxKeySize); - } + // It's important that we count the number of bytes + // in the field - not just the number of characters. + // UTF-8 characters can be between 1 and 4 bytes. + // + // From the strlen documentation: + // Attention with utf8: + // $foo = "bär"; + // strlen($foo) will return 4 and not 3 as expected.. + // + // So strlen does count the bytes - not the characters. + if (array_key_exists($indexedFieldname, $field) && (is_string($field[$indexedFieldname]) && strlen($field[$indexedFieldname]) > $maxKeySize)) { + $field[$indexedFieldname] = substr($field[$indexedFieldname], 0, $maxKeySize); } } } @@ -720,19 +713,18 @@ protected function truncateFields(Collection $collection, array &$generatedRow) } /** - * @param array $spec The table spec - * @param array $dest The table row document to save + * @param array $spec The table spec + * @param mixed[] $dest The table row document to save */ protected function doComputedFields(array $spec, array &$dest) { if (isset($spec['computed_fields'])) { foreach ($spec['computed_fields'] as $f) { if (isset($f['fieldName'], $f['value']) && is_array($f['value'])) { - if (isset($f['temporary']) && $f['temporary'] === true) { - if (!in_array($f['fieldName'], $this->temporaryFields)) { - $this->temporaryFields[] = $f['fieldName']; - } + if (isset($f['temporary']) && $f['temporary'] === true && !in_array($f['fieldName'], $this->temporaryFields)) { + $this->temporaryFields[] = $f['fieldName']; } + $computedFunctions = array_values(array_intersect(self::$computedFieldFunctions, array_keys($f['value']))); $dest[$f['fieldName']] = $this->getComputedValue($computedFunctions[0], $f['value'], $dest); } @@ -742,12 +734,12 @@ protected function doComputedFields(array $spec, array &$dest) /** * @param string $function A defined computed value function - * @param array $spec The computed field spec - * @param array $dest The table row document to save + * @param array $spec The computed field spec + * @param array $dest The table row document to save * * @return mixed The computed value */ - protected function getComputedValue($function, array $spec, array &$dest) + protected function getComputedValue(string $function, array $spec, array &$dest) { $value = null; @@ -775,12 +767,14 @@ protected function getComputedValue($function, array $spec, array &$dest) * @return float|int|null * * @throws \InvalidArgumentException + * @param array $equation */ protected function computeArithmeticValue(array $equation, array &$dest) { if (count($equation) < 3) { throw new \InvalidArgumentException('Equations must consist of an array with 3 values'); } + if (!in_array($equation[1], self::$arithmeticOperators)) { throw new \InvalidArgumentException('Invalid arithmetic operator'); } @@ -790,6 +784,7 @@ protected function computeArithmeticValue(array $equation, array &$dest) if (is_array($left)) { $left = $this->computeArithmeticValue($left, $dest); } + if (is_array($right)) { $right = $this->computeArithmeticValue($right, $dest); } @@ -828,7 +823,7 @@ protected function computeArithmeticValue(array $equation, array &$dest) } /** - * @param array $replaceSpec The replace value spec + * @param array $replaceSpec The replace value spec * @param array $dest The table row document to save * * @return mixed @@ -841,9 +836,11 @@ protected function generateReplaceValue(array $replaceSpec, array &$dest) if (isset($replaceSpec['search'])) { $search = $this->rewriteVariableValue($replaceSpec['search'], $dest); } + if (isset($replaceSpec['replace'])) { $replace = $this->rewriteVariableValue($replaceSpec['replace'], $dest); } + if (isset($replaceSpec['subject'])) { $subject = $this->rewriteVariableValue($replaceSpec['subject'], $dest); } @@ -852,7 +849,7 @@ protected function generateReplaceValue(array $replaceSpec, array &$dest) } /** - * @param array $conditionalSpec The conditional spec + * @param array $conditionalSpec The conditional spec * @param array $dest The table row document to save * * @return mixed The computed value @@ -867,9 +864,11 @@ protected function generateConditionalValue(array $conditionalSpec, array &$dest if (isset($conditionalSpec['if'][0])) { $left = $this->rewriteVariableValue($conditionalSpec['if'][0], $dest); } + if (isset($conditionalSpec['if'][1])) { $operator = $conditionalSpec['if'][1]; } + if (isset($conditionalSpec['if'][2])) { $right = $this->rewriteVariableValue($conditionalSpec['if'][2], $dest); } @@ -882,7 +881,7 @@ protected function generateConditionalValue(array $conditionalSpec, array &$dest if (is_array($conditionalSpec[$path])) { $nestedComputedFunctions = array_intersect(self::$computedFieldFunctions, array_keys($conditionalSpec[$path])); // This is 'just a regular old array' - if (empty($nestedComputedFunctions)) { + if ($nestedComputedFunctions === []) { return $this->rewriteVariableValue($conditionalSpec[$path], $dest); } @@ -898,7 +897,7 @@ protected function generateConditionalValue(array $conditionalSpec, array &$dest /** * @param mixed $value The value to replace, if it contains a variable - * @param array $dest The table row document to save + * @param array $dest The table row document to save * @param string|null $setType Force the return to be set to specified type * * @return mixed @@ -917,12 +916,14 @@ protected function rewriteVariableValue($value, array &$dest, $setType = null) return $this->castValueType($value, $setType); } + if (is_array($value)) { if ($this->isFunction($value)) { $function = array_keys($value); return $this->getComputedValue($function[0], $value, $dest); } + $aryValue = []; foreach ($value as $v) { $aryValue[] = $this->rewriteVariableValue($v, $dest); @@ -936,10 +937,8 @@ protected function rewriteVariableValue($value, array &$dest, $setType = null) /** * @param mixed $value - * - * @return bool */ - protected function isFunction($value) + protected function isFunction($value): bool { return is_array($value) && count(array_keys($value)) === 1 && count(array_intersect(array_keys($value), self::$computedFieldFunctions)) === 1; } @@ -971,11 +970,7 @@ protected function castValueType($value, $type = null) case 'numeric': if ((!is_int($value)) && !is_float($value)) { - if ($value == (string) (int) $value) { - $value = (int) $value; - } else { - $value = (float) $value; - } + $value = $value == (string) (int) $value ? (int) $value : (float) $value; } break; @@ -998,9 +993,11 @@ protected function doConditional($left, $operator, $right) if ((!empty($operator)) && !in_array($operator, self::$conditionalOperators)) { throw new \InvalidArgumentException('Invalid conditional operator'); } + if (!$operator) { - return $left ? true : false; + return (bool) $left; } + $result = false; switch ($operator) { @@ -1036,19 +1033,16 @@ protected function doConditional($left, $operator, $right) case 'contains': case 'not contains': - if (is_array($left)) { - $bool = in_array($right, $left); - } else { - $bool = (strpos((string) $left, (string) $right) !== false); - } - $result = ($bool && $operator != 'not contains'); + $bool = is_array($left) ? in_array($right, $left) : strpos((string) $left, (string) $right) !== false; + + $result = ($bool && $operator !== 'not contains'); break; case '~=': case '!~': $match = preg_match($right, $left); - $result = ($match > 0 && $operator != '!~'); + $result = ($match > 0 && $operator !== '!~'); break; } @@ -1059,19 +1053,17 @@ protected function doConditional($left, $operator, $right) /** * Add fields to a table row. * - * @param array $source - * @param array $spec - * @param array $dest + * @param array $source + * @param array $spec */ - protected function addFields($source, $spec, &$dest) + protected function addFields(array $source, array $spec, array &$dest) { if (isset($spec['fields'])) { foreach ($spec['fields'] as $f) { - if (isset($f['temporary']) && $f['temporary'] === true) { - if (!in_array($f['fieldName'], $this->temporaryFields)) { - $this->temporaryFields[] = $f['fieldName']; - } + if (isset($f['temporary']) && $f['temporary'] === true && !in_array($f['fieldName'], $this->temporaryFields)) { + $this->temporaryFields[] = $f['fieldName']; } + if (isset($f['predicates'])) { foreach ($f['predicates'] as $p) { if (is_string($p) && isset($source[$p])) { @@ -1091,11 +1083,10 @@ protected function addFields($source, $spec, &$dest) $this->generateValues($source, $f, $v, $dest); } } - // Otherwise apply a modifier - } else { - if (isset($dest[$f['fieldName']])) { - $dest[$f['fieldName']] = $this->applyModifier($function, $dest[$f['fieldName']], $functionOptions); - } + + // Otherwise apply a modifier + } elseif (isset($dest[$f['fieldName']])) { + $dest[$f['fieldName']] = $this->applyModifier($function, $dest[$f['fieldName']], $functionOptions); } } } @@ -1103,20 +1094,20 @@ protected function addFields($source, $spec, &$dest) } // Allow URI linking to the ID - if (isset($f['value'])) { - if ($f['value'] == '_link_' || $f['value'] == 'link') { - if ($f['value'] == '_link_') { - $this->warningLog("Table spec value '_link_' is deprecated", $f); - } - // If value exists, set as array - if (isset($dest[$f['fieldName']])) { - if (!is_array($dest[$f['fieldName']])) { - $dest[$f['fieldName']] = [$dest[$f['fieldName']]]; - } - $dest[$f['fieldName']][] = $this->labeller->qname_to_alias($source['_id']['r']); - } else { - $dest[$f['fieldName']] = $this->labeller->qname_to_alias($source['_id']['r']); + if (isset($f['value']) && ($f['value'] == '_link_' || $f['value'] == 'link')) { + if ($f['value'] == '_link_') { + $this->warningLog("Table spec value '_link_' is deprecated", $f); + } + + // If value exists, set as array + if (isset($dest[$f['fieldName']])) { + if (!is_array($dest[$f['fieldName']])) { + $dest[$f['fieldName']] = [$dest[$f['fieldName']]]; } + + $dest[$f['fieldName']][] = $this->labeller->qname_to_alias($source['_id']['r']); + } else { + $dest[$f['fieldName']] = $this->labeller->qname_to_alias($source['_id']['r']); } } } @@ -1126,12 +1117,11 @@ protected function addFields($source, $spec, &$dest) /** * Generate values for a given predicate. * - * @param array $source - * @param array $f + * @param array $source + * @param array $f * @param string $predicate - * @param array $dest */ - protected function generateValues($source, $f, $predicate, &$dest) + protected function generateValues(array $source, array $f, $predicate, array &$dest) { $values = []; if (isset($source[$predicate][VALUE_URI]) && !empty($source[$predicate][VALUE_URI])) { @@ -1147,6 +1137,7 @@ protected function generateValues($source, $f, $predicate, &$dest) } elseif (isset($v[VALUE_URI]) && !empty($v[VALUE_URI])) { $values[] = $v[VALUE_URI]; } + // _id's shouldn't appear in value arrays, so no need for third condition here } } @@ -1173,10 +1164,8 @@ protected function generateValues($source, $f, $predicate, &$dest) * Recursively get functions that can modify a predicate. * * @param array $array - * - * @return array */ - protected function getPredicateFunctions($array) + protected function getPredicateFunctions($array): array { $predicateFunctions = []; if (is_array($array)) { @@ -1192,13 +1181,12 @@ protected function getPredicateFunctions($array) } /** - * @param array $source * @param array $joins * @param array $dest * @param string $from * @param string $contextAlias */ - protected function doJoins($source, $joins, &$dest, $from, $contextAlias) + protected function doJoins(array $source, $joins, &$dest, $from, $contextAlias) { $this->expandSequence($joins, $source); foreach ($joins as $predicate => $ruleset) { @@ -1247,10 +1235,8 @@ protected function doJoins($source, $joins, &$dest, $from, $contextAlias) } } - if (count($recursiveJoins) > 0) { - foreach ($recursiveJoins as $r) { - $this->doJoins($r['data'], $r['ruleset'], $dest, $from, $contextAlias); - } + foreach ($recursiveJoins as $r) { + $this->doJoins($r['data'], $r['ruleset'], $dest, $from, $contextAlias); } } } @@ -1261,43 +1247,38 @@ protected function doJoins($source, $joins, &$dest, $from, $contextAlias) * * @param mixed $source * @param mixed $countSpec - * @param mixed $dest + * @param int[] $dest */ - protected function doCounts($source, $countSpec, &$dest) + protected function doCounts(array $source, $countSpec, array &$dest) { // process count aggregate function foreach ($countSpec as $c) { $fieldName = $c['fieldName']; - if (isset($c['temporary']) && $c['temporary'] === true) { - if (!in_array($fieldName, $this->temporaryFields)) { - $this->temporaryFields[] = $fieldName; - } + if (isset($c['temporary']) && $c['temporary'] === true && !in_array($fieldName, $this->temporaryFields)) { + $this->temporaryFields[] = $fieldName; } + $applyRegex = isset($c['regex']) ?: null; $count = 0; // just count predicates at current location if (isset($source[$c['property']])) { if (isset($source[$c['property']][VALUE_URI]) || isset($source[$c['property']][VALUE_LITERAL])) { - if ($applyRegex != null) { - $count = $this->applyRegexToValue($c['regex'], $source[$c['property']]); - } else { - $count = 1; - } - } else { - if ($applyRegex != null) { - foreach ($source[$c['property']] as $value) { - if ($this->applyRegexToValue($c['regex'], $value)) { - $count++; - } + $count = $applyRegex != null ? $this->applyRegexToValue($c['regex'], $source[$c['property']]) : 1; + } elseif ($applyRegex != null) { + foreach ($source[$c['property']] as $value) { + if ($this->applyRegexToValue($c['regex'], $value)) { + $count++; } - } else { - $count = count($source[$c['property']]); } + } else { + $count = count($source[$c['property']]); } } + if (!isset($dest[$fieldName])) { $dest[$fieldName] = 0; } + $dest[$fieldName] += $count; } } @@ -1307,10 +1288,8 @@ protected function doCounts($source, $countSpec, &$dest) * includes rdf:type (or is empty, meaning addition or deletion vs. update). * * @param string $rdfType - * - * @return bool */ - protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes, array $subjectPredicates) + protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes, array $subjectPredicates): bool { // We don't know if this is an alias or a fqURI, nor what is in the valid types, necessarily $types = [$rdfType]; @@ -1326,16 +1305,18 @@ protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes } $intersectingTypes = array_unique(array_intersect($types, $validTypes)); - if (!empty($intersectingTypes)) { + if ($intersectingTypes !== []) { // Table rows only need to be invalidated if their rdf:type property has changed // This means we're either adding or deleting a graph - if (empty($subjectPredicates)) { + if ($subjectPredicates === []) { return true; } + // Check for alias in changed predicates if (in_array('rdf:type', $subjectPredicates)) { return true; } + // Check for fully qualified URI in changed predicates if (in_array(RDF_TYPE, $subjectPredicates)) { return true; @@ -1366,50 +1347,40 @@ protected function getCollectionForTableSpec($tableSpecId) * * @param string $modifier * @param string $value - * @param array $options + * @param array $options * * @return mixed * * @throws \Exception */ - private function applyModifier($modifier, $value, $options = []) + private function applyModifier($modifier, $value, array $options = []) { - try { - switch ($modifier) { - case 'predicates': - // Used to generate a list of values - does nothing here - break; - - case 'lowercase': - if (is_array($value)) { - $value = array_map('strtolower', $value); - } else { - $value = strtolower($value); - } + switch ($modifier) { + case 'predicates': + // Used to generate a list of values - does nothing here + break; - break; + case 'lowercase': + $value = is_array($value) ? array_map('strtolower', $value) : strtolower($value); - case 'join': - if (is_array($value)) { - $value = implode($options['glue'], $value); - } + break; - break; + case 'join': + if (is_array($value)) { + $value = implode($options['glue'], $value); + } - case 'date': - if (is_string($value)) { - $value = DateUtil::getMongoDate(strtotime($value) * 1000); - } + break; - break; + case 'date': + if (is_string($value)) { + $value = DateUtil::getMongoDate(strtotime($value) * 1000); + } - default: - throw new \Exception('Could not apply modifier:' . $modifier); + break; - break; - } - } catch (\Exception $e) { - throw $e; + default: + throw new \Exception('Could not apply modifier:' . $modifier); } return $value; @@ -1419,13 +1390,13 @@ private function applyModifier($modifier, $value, $options = []) * Apply a regex to the RDF property value defined in $value. * * @param mixed $regex - * @param mixed $value + * @param array $value * * @return int * * @throws \Tripod\Exceptions\Exception */ - private function applyRegexToValue($regex, $value) + private function applyRegexToValue($regex, array $value) { if (isset($value[VALUE_URI]) || isset($value[VALUE_LITERAL])) { $v = $value[VALUE_URI] ?: $value[VALUE_LITERAL]; diff --git a/src/mongo/delegates/TransactionLog.php b/src/mongo/delegates/TransactionLog.php index 7c34bf8b..5d645815 100644 --- a/src/mongo/delegates/TransactionLog.php +++ b/src/mongo/delegates/TransactionLog.php @@ -1,5 +1,7 @@ config = $config->getTransactionLogConfig(); + $this->transaction_db = $config->getTransactionLogDatabase(); $this->transaction_collection = $this->transaction_db->selectCollection($this->config['collection']); } @@ -33,7 +38,7 @@ public function __construct() * * @throws \Tripod\Exceptions\Exception */ - public function createNewTransaction($transaction_id, $changes, $originalCBDs, $storeName, $podName) + public function createNewTransaction($transaction_id, $changes, $originalCBDs, $storeName, $podName): void { $transaction = [ '_id' => $transaction_id, @@ -52,7 +57,7 @@ public function createNewTransaction($transaction_id, $changes, $originalCBDs, $ throw new \Exception('Error creating new transaction'); } } catch (\Exception $e) { - throw new \Tripod\Exceptions\Exception('Error creating new transaction: ' . $e->getMessage()); + throw new \Tripod\Exceptions\Exception('Error creating new transaction: ' . $e->getMessage(), $e->getCode(), $e); } } @@ -63,7 +68,7 @@ public function createNewTransaction($transaction_id, $changes, $originalCBDs, $ * @param string $transaction_id the id of the transaction you wish to cancel * @param \Exception $error pass in the exception you wish to log */ - public function cancelTransaction($transaction_id, ?\Exception $error = null) + public function cancelTransaction($transaction_id, ?\Exception $error = null): void { $params = ['status' => 'cancelling']; if ($error != null) { @@ -84,7 +89,7 @@ public function cancelTransaction($transaction_id, ?\Exception $error = null) * @param string $transaction_id the id of the transaction you wish to set as failed * @param \Exception $error exception you wish to log */ - public function failTransaction($transaction_id, ?\Exception $error = null) + public function failTransaction($transaction_id, ?\Exception $error = null): void { $params = ['status' => 'failed', 'failedTime' => DateUtil::getMongoDate()]; if ($error != null) { @@ -104,7 +109,7 @@ public function failTransaction($transaction_id, ?\Exception $error = null) * @param string $transaction_id - the id of the transaction you want to mark as completed * @param array $newCBDs array of CBD's that represent the after state for each modified entity */ - public function completeTransaction($transaction_id, array $newCBDs) + public function completeTransaction($transaction_id, array $newCBDs): void { $this->updateTransaction( ['_id' => $transaction_id], @@ -128,7 +133,7 @@ public function getTransaction($transaction_id) /** * Purges all transactions from the transaction log. */ - public function purgeAllTransactions() + public function purgeAllTransactions(): void { $this->transaction_collection->drop(); } diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 016c07ac..c4cb167a 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -1,5 +1,7 @@ applyHooks($this::HOOK_FN_PRE, $this->saveChangesHooks, [ 'pod' => $this->getPodName(), 'oldGraph' => $oldGraph, @@ -187,6 +189,7 @@ public function saveChanges( 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 @@ -224,16 +227,13 @@ public function saveChanges( } // ////// LOCKS \\\\\\\\ - /** * Get locked documents for a date range or all documents if no date range is given. * * @param string $fromDateTime * @param string $tillDateTime - * - * @return array */ - public function getLockedDocuments($fromDateTime = null, $tillDateTime = null) + public function getLockedDocuments($fromDateTime = null, $tillDateTime = null): array { $query = []; if (!empty($fromDateTime) || !empty($tillDateTime)) { @@ -242,10 +242,12 @@ public function getLockedDocuments($fromDateTime = null, $tillDateTime = null) if (!empty($fromDateTime)) { $query[_LOCKED_FOR_TRANS_TS][MONGO_OPERATION_GTE] = DateUtil::getMongoDate(strtotime($fromDateTime) * 1000); } + if (!empty($tillDateTime)) { $query[_LOCKED_FOR_TRANS_TS][MONGO_OPERATION_LTE] = DateUtil::getMongoDate(strtotime($tillDateTime) * 1000); } } + $docs = $this->getLocksCollection()->find($query, ['sort' => [_LOCKED_FOR_TRANS => 1]]); if ($this->getLocksCollection()->count($query) == 0) { @@ -266,11 +268,10 @@ public function getLockedDocuments($fromDateTime = null, $tillDateTime = null) * @param string $transaction_id * @param string $reason * - * @return bool * * @throws \Exception, if something goes wrong when unlocking documents, or creating audit entries */ - public function removeInertLocks($transaction_id, $reason) + public function removeInertLocks($transaction_id, $reason): bool { $query = [_LOCKED_FOR_TRANS => $transaction_id]; $docs = $this->getLocksCollection()->find($query); @@ -352,17 +353,14 @@ public function removeInertLocks($transaction_id, $reason) } // /////// REPLAY TRANSACTION LOG /////// - /** * replays all transactions from the transaction log, use the function params to control the from and to date if you * only want to replay transactions created during specific window. * * @param string|null $fromDate only transactions after this specified date. This must be a datetime string i.e. '2010-01-15 00:00:00' * @param string|null $toDate only transactions before this specified date. This must be a datetime string i.e. '2010-01-15 00:00:00' - * - * @return bool */ - public function replayTransactionLog($fromDate = null, $toDate = null) + public function replayTransactionLog($fromDate = null, $toDate = null): bool { $cursor = $this->getTransactionLog()->getCompletedTransactions($this->storeName, $this->podName, $fromDate, $toDate); foreach ($cursor as $result) { @@ -386,7 +384,7 @@ public function getTransactionLog() return $this->transactionLog; } - public function setTransactionLog(TransactionLog $transactionLog) + public function setTransactionLog(TransactionLog $transactionLog): void { $this->transactionLog = $transactionLog; } @@ -394,7 +392,7 @@ public function setTransactionLog(TransactionLog $transactionLog) /** * Register save changes event hooks. */ - public function registerSaveChangesEventHook(IEventHook $hook) + public function registerSaveChangesEventHook(IEventHook $hook): void { $this->saveChangesHooks[] = $hook; } @@ -476,7 +474,7 @@ protected function validateGraphCardinality(ExtendedGraph $graph) foreach ($cardinality as $qname => $cardinalityValue) { [$namespace, $predicateName] = explode(':', $qname); if (!array_key_exists($namespace, $namespaces)) { - throw new CardinalityException("Namespace '{$namespace}' not defined for qname: {$qname}"); + throw new CardinalityException(sprintf("Namespace '%s' not defined for qname: %s", $namespace, $qname)); } // NB: The only constraint we currently support is a value of 1 to enforce one triple per subject/predicate. @@ -490,7 +488,7 @@ protected function validateGraphCardinality(ExtendedGraph $graph) $v[] = $predicateValue['value']; } - throw new CardinalityException("Cardinality failed on {$subjectUri} for '{$qname}' - should only have 1 value and has: " . implode(', ', $v)); + throw new CardinalityException(sprintf("Cardinality failed on %s for '%s' - should only have 1 value and has: ", $subjectUri, $qname) . implode(', ', $v)); } } } @@ -516,6 +514,7 @@ protected function storeChanges(ChangeSet $cs, $contextAlias) // store the details of the transaction in the transaction log $mongoGraph = new MongoGraph(); $mongoGraph->_index = $cs->_index; + $csDoc = $mongoGraph->to_tripod_view_array('changes', $contextAlias); // todo - this changed to tripod view array, why is "changes" the docId? $originalCBDs = []; @@ -552,7 +551,7 @@ protected function storeChanges(ChangeSet $cs, $contextAlias) $t->stop(); $this->timingLog(MONGO_WRITE, ['duration' => $t->result(), 'subjectsOfChange' => implode(', ', $subjectsOfChange)]); - $this->getStat()->timer(MONGO_WRITE . ".{$this->getPodName()}", $t->result()); + $this->getStat()->timer(MONGO_WRITE . ('.' . $this->getPodName()), $t->result()); return $changes; } catch (\Exception $e) { @@ -568,7 +567,7 @@ protected function storeChanges(ChangeSet $cs, $contextAlias) ); $this->rollbackTransaction($transaction_id, $originalCBDs, $e); - throw new Exception('Error storing changes: ' . $e->getMessage() . ' >>>' . $e->getTraceAsString()); + throw new Exception('Error storing changes: ' . $e->getMessage() . ' >>>' . $e->getTraceAsString(), $e->getCode(), $e); } } @@ -576,11 +575,10 @@ protected function storeChanges(ChangeSet $cs, $contextAlias) * @param string $transaction_id id of the transaction * @param array $originalCBDs containing the original CBDS * - * @return bool * * @throws \Exception */ - protected function rollbackTransaction($transaction_id, $originalCBDs, \Exception $exception) + protected function rollbackTransaction(string $transaction_id, $originalCBDs, \Exception $exception): bool { // set transaction to cancelling $this->getTransactionLog()->cancelTransaction($transaction_id, $exception); @@ -601,7 +599,7 @@ protected function rollbackTransaction($transaction_id, $originalCBDs, \Exceptio ] ); - throw new \Exception("Failed to restore Original CBDS for transaction: {$transaction_id} stopped at " . $g[_ID_KEY]); + throw new \Exception(sprintf('Failed to restore Original CBDS for transaction: %s stopped at ', $transaction_id) . $g[_ID_KEY]); } } } else { @@ -614,6 +612,7 @@ protected function rollbackTransaction($transaction_id, $originalCBDs, \Exceptio ] ); } + $this->unlockAllDocuments($transaction_id); // set transaction to failed @@ -624,20 +623,16 @@ protected function rollbackTransaction($transaction_id, $originalCBDs, \Exceptio /** * Returns a unique transaction ID. - * - * @return string */ - protected function generateTransactionId() + protected function generateTransactionId(): string { return 'transaction_' . $this->getUniqId(); } /** * Returns a unique id: for mocking. - * - * @return string */ - protected function getUniqId() + protected function getUniqId(): string { return uniqid('', true); } @@ -645,15 +640,13 @@ protected function getUniqId() /** * Adds/updates/deletes the graph in the database. * - * @param array $originalCBDs * @param string $contextAlias * @param string $transaction_id * - * @return array - * + * @return array * @throws \Exception */ - protected function applyChangeSet(ChangeSet $cs, $originalCBDs, $contextAlias, $transaction_id) + protected function applyChangeSet(ChangeSet $cs, array $originalCBDs, $contextAlias, $transaction_id) { $subjectsAndPredicatesOfChange = []; if (in_array($this->getCollection()->getCollectionName(), $this->getConfigInstance()->getPods($this->getStoreName()))) { @@ -714,21 +707,23 @@ protected function applyChangeSet(ChangeSet $cs, $originalCBDs, $contextAlias, $ if (isset($additionsRemovals['removals'])) { $elemsToRemove = []; foreach ($additionsRemovals['removals'] as $removal) { - $valueIndex = array_search($removal, $valueObject); + $valueIndex = array_search($removal, $valueObject, true); if ($valueIndex === false) { $values = array_values($removal); $v = array_pop($values); - $this->errorLog("Removal value {$subjectOfChange} {$predicate} {$v} does not appear in target document to be updated", ['doc' => $doc]); + $this->errorLog(sprintf('Removal value %s %s %s does not appear in target document to be updated', $subjectOfChange, $predicate, $v), ['doc' => $doc]); - throw new \Exception("Removal value {$subjectOfChange} {$predicate} {$v} does not appear in target document to be updated"); + throw new \Exception(sprintf('Removal value %s %s %s does not appear in target document to be updated', $subjectOfChange, $predicate, $v)); } $elemsToRemove[] = $valueIndex; } - if (count($elemsToRemove) > 0) { + + if ($elemsToRemove !== []) { foreach ($elemsToRemove as $elem) { unset($valueObject[$elem]); } + $valueObject = array_values($valueObject); // renumbers array after unsets } } @@ -736,16 +731,14 @@ protected function applyChangeSet(ChangeSet $cs, $originalCBDs, $contextAlias, $ if (count($valueObject) > 0) { // unique value object $valueObject = array_map('unserialize', array_unique(array_map('serialize', $valueObject))); - - if (count($valueObject) == 1) { + if (count($valueObject) === 1) { $valueObject = $valueObject[0]; // un-array if only one value } + $this->addOperatorToChange($mongoUpdateOperations, MONGO_OPERATION_SET, [$nsPredicate => $valueObject]); - } else { + } elseif ($predicateExists) { // remove all existing values, if existed in the first place - if ($predicateExists) { - $this->addOperatorToChange($mongoUpdateOperations, MONGO_OPERATION_UNSET, [$nsPredicate => 1]); - } + $this->addOperatorToChange($mongoUpdateOperations, MONGO_OPERATION_UNSET, [$nsPredicate => 1]); } } @@ -774,7 +767,7 @@ protected function applyChangeSet(ChangeSet $cs, $originalCBDs, $contextAlias, $ 'upsert' => $update['upsert'], 'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER, ]); - array_push($newCBDs, $newDoc); + $newCBDs[] = $newDoc; } catch (\Exception $e) { $this->errorLog( MONGO_WRITE, @@ -784,7 +777,7 @@ protected function applyChangeSet(ChangeSet $cs, $originalCBDs, $contextAlias, $ ] ); - throw new \Exception($e); + throw new \Exception($e, $e->getCode(), $e); } } @@ -801,9 +794,9 @@ protected function applyChangeSet(ChangeSet $cs, $originalCBDs, $contextAlias, $ /** * Normalize our subjects and predicates of change to use aliases rather than fq uris. * - * @return array + * @param array> $subjectsAndPredicatesOfChange */ - protected function subjectsAndPredicatesOfChangeUrisToAliases(array $subjectsAndPredicatesOfChange) + protected function subjectsAndPredicatesOfChangeUrisToAliases(array $subjectsAndPredicatesOfChange): array { $aliases = []; foreach ($subjectsAndPredicatesOfChange as $subject => $predicates) { @@ -830,8 +823,6 @@ protected function getDocumentForUpdate($subjectOfChange, $contextAlias, array $ foreach ($cbds as $c) { if ($c[_ID_KEY] == [_ID_RESOURCE => $this->labeller->uri_to_alias($subjectOfChange), _ID_CONTEXT => $contextAlias]) { return $c; - - break; } } @@ -893,7 +884,7 @@ protected function queueASyncOperations(array $subjectsAndPredicatesOfChange, $c 'statsConfig' => $this->getStatsConfig(), ]; - if (isset($this->queueName)) { + if ($this->queueName !== null) { $data[OP_QUEUE] = $this->queueName; $queueName = $this->queueName; } else { @@ -912,7 +903,7 @@ protected function queueASyncOperations(array $subjectsAndPredicatesOfChange, $c */ protected function getDiscoverImpactedSubjects() { - if (!isset($this->discoverImpactedSubjects)) { + if ($this->discoverImpactedSubjects === null) { $this->discoverImpactedSubjects = new DiscoverImpactedSubjects(); } @@ -930,7 +921,7 @@ protected function getDiscoverImpactedSubjects() * * @throws \Exception */ - protected function lockAllDocuments($subjectsOfChange, $transaction_id, $contextAlias) + protected function lockAllDocuments($subjectsOfChange, $transaction_id, $contextAlias): ?array { for ($retry = 1; $retry <= $this->retriesToGetLock; $retry++) { $originalCBDs = []; @@ -964,15 +955,16 @@ protected function lockAllDocuments($subjectsOfChange, $transaction_id, $context } } - if (count($subjectsOfChange) == count($lockedSubjects)) { + if (count($subjectsOfChange) === count($lockedSubjects)) { // if all subjects of change locked, we are good. return $originalCBDs; } // If any subject was locked, unlock it - if (count($lockedSubjects)) { + if ($lockedSubjects !== []) { $this->unlockAllDocuments($transaction_id); } + $this->debugLog( MONGO_LOCK, [ @@ -1005,11 +997,10 @@ protected function lockAllDocuments($subjectsOfChange, $transaction_id, $context * * @param string $transaction_id id for this transaction * - * @return bool * * @throws \Exception is thrown if for any reason the update to mongo fails */ - protected function unlockAllDocuments($transaction_id) + protected function unlockAllDocuments(string $transaction_id): bool { $result = $this->getLocksCollection()->deleteMany([_LOCKED_FOR_TRANS => $transaction_id], ['w' => 1]); @@ -1093,6 +1084,7 @@ protected function lockSingleDocument($s, $transaction_id, $contextAlias) if (!$result->isAcknowledged()) { throw new \Exception('Failed to create new document: write not acknowledged'); } + $document = $this->getCollection()->findOne([_ID_KEY => [_ID_RESOURCE => $this->labeller->uri_to_alias($s), _ID_CONTEXT => $contextAlias]]); } catch (\Exception $e) { $this->errorLog( @@ -1122,10 +1114,7 @@ protected function getAuditManualRollbacksCollection() return $this->config->getCollectionForManualRollbackAudit($this->storeName); } - /** - * @return ObjectId - */ - protected function generateIdForNewMongoDocument() + protected function generateIdForNewMongoDocument(): \MongoDB\BSON\ObjectId { return new ObjectId(); } @@ -1140,6 +1129,7 @@ protected function getMongoDate() /** * Saves a transaction. + * @param array $transaction */ protected function applyTransaction(array $transaction) { @@ -1149,7 +1139,7 @@ protected function applyTransaction(array $transaction) $subjectsOfChange = []; foreach ($changes as $c) { if ($c['rdf:type'][VALUE_URI] == 'cs:ChangeSet') { - array_push($subjectsOfChange, $c['cs:subjectOfChange']['u']); + $subjectsOfChange[] = $c['cs:subjectOfChange']['u']; } } @@ -1167,11 +1157,9 @@ protected function applyTransaction(array $transaction) /** * Creates a new Driver instance. * - * @param array $data - * - * @return Driver + * @param array $data */ - protected function getTripod($data) + protected function getTripod(array $data): \Tripod\Mongo\Driver { return new Driver( $data['collection'], @@ -1189,7 +1177,7 @@ protected function getTripod($data) * * @return bool */ - protected function updateCollection($query, $update, $options) + protected function updateCollection($query, $update, array $options) { return $this->getCollection()->replaceOne($query, $update, $options); } @@ -1213,7 +1201,7 @@ protected function getContextAlias($context = null) */ protected function getLocksDatabase() { - if (!isset($this->locksDb)) { + if ($this->locksDb === null) { $this->locksDb = $this->config->getDatabase($this->storeName); } @@ -1225,7 +1213,7 @@ protected function getLocksDatabase() */ protected function getLocksCollection() { - if (!isset($this->locksCollection)) { + if ($this->locksCollection === null) { $this->locksCollection = $this->getLocksDatabase()->selectCollection(LOCKS_COLLECTION); } @@ -1236,10 +1224,8 @@ protected function getLocksCollection() * Helper function to group the changes for $changeUri by namespaced predicate, then by additions and removals. * * @param mixed $changeUri - * - * @return array */ - private function getAdditionsRemovalsGroupedByNsPredicate(ChangeSet $cs, $changeUri) + private function getAdditionsRemovalsGroupedByNsPredicate(ChangeSet $cs, $changeUri): array { $additionsGroupedByNsPredicate = $this->getChangesGroupedByNsPredicate($cs, $changeUri, $this->labeller->qname_to_uri('cs:addition')); $removalsGroupedByNsPredicate = $this->getChangesGroupedByNsPredicate($cs, $changeUri, $this->labeller->qname_to_uri('cs:removal')); @@ -1249,12 +1235,15 @@ private function getAdditionsRemovalsGroupedByNsPredicate(ChangeSet $cs, $change if (!isset($mergedResult[$predicate])) { $mergedResult[$predicate] = []; } + $mergedResult[$predicate]['additions'] = $values; } + foreach ($removalsGroupedByNsPredicate as $predicate => $values) { if (!isset($mergedResult[$predicate])) { $mergedResult[$predicate] = []; } + $mergedResult[$predicate]['removals'] = $values; } @@ -1267,11 +1256,10 @@ private function getAdditionsRemovalsGroupedByNsPredicate(ChangeSet $cs, $change * @param mixed $changeUri * @param mixed $changePredicate * - * @return array * * @throws Exception */ - private function getChangesGroupedByNsPredicate(ChangeSet $cs, $changeUri, $changePredicate) + private function getChangesGroupedByNsPredicate(ChangeSet $cs, $changeUri, $changePredicate): array { $changes = $cs->get_subject_property_values($changeUri, $changePredicate); @@ -1285,7 +1273,7 @@ private function getChangesGroupedByNsPredicate(ChangeSet $cs, $changeUri, $chan } $object = $cs->get_subject_property_values($c['value'], $this->labeller->qname_to_uri('rdf:object')); - if (count($object) != 1) { + if (count($object) !== 1) { $this->getLogger()->error('Expecting object array with exactly 1 element', $object); throw new Exception('Object of removal malformed'); @@ -1303,27 +1291,26 @@ private function getChangesGroupedByNsPredicate(ChangeSet $cs, $changeUri, $chan /** * Helper method to add operator to a set of existing changes ready to be sent to Mongo. * - * @param mixed $changes + * @param array $changes * @param mixed $operator - * @param mixed $kvp + * @param array|array $kvp */ - private function addOperatorToChange(&$changes, $operator, $kvp) + private function addOperatorToChange(array &$changes, string $operator, array $kvp): void { if (!isset($changes[$operator]) || !is_array($changes[$operator])) { $changes[$operator] = []; } + foreach ($kvp as $key => $value) { if (isset($changes[$operator][$key])) { $value = array_merge($value, $changes[$operator][$key]); } + $changes[$operator][$key] = $value; } } - /** - * @return array - */ - private function getAsyncOperations() + private function getAsyncOperations(): array { $types = []; foreach ($this->async as $op => $isAsync) { @@ -1335,10 +1322,7 @@ private function getAsyncOperations() return $types; } - /** - * @return array - */ - private function getSyncOperations() + private function getSyncOperations(): array { $types = []; foreach ($this->async as $op => $isAsync) { diff --git a/src/mongo/delegates/Views.php b/src/mongo/delegates/Views.php index 73703381..e471beeb 100644 --- a/src/mongo/delegates/Views.php +++ b/src/mongo/delegates/Views.php @@ -1,5 +1,7 @@ readPreference = $readPreference; } - /** - * @return string - */ - public function getOperationType() + public function getOperationType(): string { return OP_VIEWS; } @@ -49,7 +48,7 @@ public function getOperationType() * * @param ImpactedSubject */ - public function update(ImpactedSubject $subject) + public function update(ImpactedSubject $subject): void { $resource = $subject->getResourceId(); $resourceUri = $resource[_ID_RESOURCE]; @@ -69,12 +68,12 @@ public function getTypesInSpecifications() /** * @param string $contextAlias * - * @return array|mixed + * @return mixed[] */ - public function findImpactedComposites(array $resourcesAndPredicates, $contextAlias) + public function findImpactedComposites(array $resourcesAndPredicates, $contextAlias): array { // This should never happen, but in the event that we have been passed an empty array or something - if (empty($resourcesAndPredicates)) { + if ($resourcesAndPredicates === []) { return []; } @@ -89,7 +88,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl // build $filter for queries to impact index $filter[] = [_ID_RESOURCE => $resourceAlias, _ID_CONTEXT => $contextAlias]; $rdfTypePredicates = array_intersect($predicates, $typeKeys); - if (!empty($rdfTypePredicates)) { + if ($rdfTypePredicates !== []) { $changedTypes[] = $resourceAlias; } } @@ -97,7 +96,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl // first re-gen views where resources appear in the impact index $query = ['value.' . _IMPACT_INDEX => ['$in' => $filter]]; - if (!empty($changedTypes)) { + if ($changedTypes !== []) { $query = ['$or' => [$query]]; foreach ($changedTypes as $resourceAlias) { $query['$or'][] = [ @@ -160,11 +159,13 @@ public function getViews(array $filter, $viewType) $values[] = ['value.' . _GRAPHS . '.' . $p => $o]; } } + $query[$predicate] = $values; } else { $query['value.' . _GRAPHS . '.' . $predicate] = $object; } } + $viewCollection = $this->getConfigInstance()->getCollectionForView($this->storeName, $viewType, $this->readPreference); return $this->fetchGraph($query, MONGO_VIEW, $viewCollection); @@ -174,12 +175,10 @@ public function getViews(array $filter, $viewType) * For given $resource, return the view of type $viewType. * * @param string|null $resource - * @param string $viewType * @param string|null $context - * * @return MongoGraph */ - public function getViewForResource($resource, $viewType, $context = null) + public function getViewForResource($resource, string $viewType, $context = null) { if (empty($resource)) { return new MongoGraph(); @@ -192,7 +191,7 @@ public function getViewForResource($resource, $viewType, $context = null) $viewCollection = $this->config->getCollectionForView($this->storeName, $viewType, $this->readPreference); $graph = $this->fetchGraph($query, MONGO_VIEW, $viewCollection); if ($graph->is_empty()) { - $this->getStat()->increment(MONGO_VIEW_CACHE_MISS . ".{$viewType}"); + $this->getStat()->increment(MONGO_VIEW_CACHE_MISS . ('.' . $viewType)); $viewSpec = $this->getConfigInstance()->getViewSpecification($this->storeName, $viewType); if ($viewSpec == null) { return new MongoGraph(); @@ -241,7 +240,7 @@ public function getViewForResources(array $resources, $viewType, $context = null // account for missing subjects $returnedSubjects = $g->get_subjects(); $missingSubjects = array_diff($resources, $returnedSubjects); - if (!empty($missingSubjects)) { + if ($missingSubjects !== []) { $regrabResources = []; foreach ($missingSubjects as $missingSubject) { $viewSpec = $this->getConfigInstance()->getViewSpecification($this->storeName, $viewType); @@ -261,7 +260,7 @@ public function getViewForResources(array $resources, $viewType, $context = null $regrabResources[] = $missingSubject; } - if (!empty($regrabResources)) { + if ($regrabResources !== []) { // only try to regrab resources if there are any to regrab $cursorSize = 101; if (count($regrabResources) > 101) { @@ -282,7 +281,7 @@ public function getViewForResources(array $resources, $viewType, $context = null * @param array $resources * @param string|null $context */ - public function generateViews($resources, $context = null) + public function generateViews($resources, $context = null): void { $contextAlias = $this->getContextAlias($context); @@ -332,11 +331,10 @@ public function generateViews($resources, $context = null) * @param string|null $resource * @param string|null $context * - * @return mixed * * @throws \Exception */ - public function generateViewsForResourcesOfType($rdfType, $resource = null, $context = null) + public function generateViewsForResourcesOfType($rdfType, $resource = null, $context = null): void { $rdfType = $this->labeller->qname_to_alias($rdfType); $rdfTypeAlias = $this->labeller->uri_to_alias($rdfType); @@ -348,12 +346,13 @@ public function generateViewsForResourcesOfType($rdfType, $resource = null, $con ($viewSpec['type'] == $rdfType || (is_array($viewSpec['type']) && in_array($rdfType, $viewSpec['type']))) || ($viewSpec['type'] == $rdfTypeAlias || (is_array($viewSpec['type']) && in_array($rdfTypeAlias, $viewSpec['type'])))) { $foundSpec = true; - $this->debugLog("Processing {$viewSpec['_id']}"); + $this->debugLog('Processing ' . $viewSpec['_id']); $this->generateView($key, $resource, $context); } } + if (!$foundSpec) { - $this->debugLog("Could not find any view specifications for {$resource} with resource type '{$rdfType}'"); + $this->debugLog(sprintf("Could not find any view specifications for %s with resource type '%s'", $resource, $rdfType)); return; } @@ -367,24 +366,27 @@ public function generateViewsForResourcesOfType($rdfType, $resource = null, $con * * @return int The number of views deleted */ - public function deleteViewsByViewId($viewId, $timestamp = null) + public function deleteViewsByViewId(string $viewId, $timestamp = null) { $viewSpec = $this->getConfigInstance()->getViewSpecification($this->storeName, $viewId); if ($viewSpec == null) { - $this->debugLog("Could not find a view specification with viewId '{$viewId}'"); + $this->debugLog(sprintf("Could not find a view specification with viewId '%s'", $viewId)); return; } + $query = ['_id.type' => $viewId]; if ($timestamp) { if (!$timestamp instanceof UTCDateTime) { $timestamp = DateUtil::getMongoDate($timestamp); } + $query['$or'] = [ [\_CREATED_TS => ['$lt' => $timestamp]], [\_CREATED_TS => ['$exists' => false]], ]; } + $deleteResult = $this->getCollectionForViewSpec($viewId) ->deleteMany($query); @@ -394,24 +396,23 @@ public function deleteViewsByViewId($viewId, $timestamp = null) /** * Given a specific $viewId, generates a single view for the $resource. * - * @param string $viewId * @param string|null $resource * @param string|null $context * @param string|null $queueName Queue for background bulk generation * * @return array - * * @throws ViewException */ - public function generateView($viewId, $resource = null, $context = null, $queueName = null) + public function generateView(string $viewId, $resource = null, $context = null, $queueName = null): ?array { $contextAlias = $this->getContextAlias($context); $viewSpec = $this->getConfigInstance()->getViewSpecification($this->storeName, $viewId); if ($viewSpec == null) { - $this->debugLog("Could not find a view specification for {$resource} with viewId '{$viewId}'"); + $this->debugLog(sprintf("Could not find a view specification for %s with viewId '%s'", $resource, $viewId)); return null; } + $t = new Timer(); $t->start(); @@ -432,6 +433,7 @@ public function generateView($viewId, $resource = null, $context = null, $queueN $types[] = ['rdf:type.u' => $this->labeller->qname_to_alias($viewSpec['type'])]; $types[] = ['rdf:type.u' => $this->labeller->uri_to_alias($viewSpec['type'])]; } + $filter = ['$or' => $types]; if (isset($resource)) { $resourceAlias = $this->labeller->uri_to_alias($resource); @@ -452,6 +454,7 @@ public function generateView($viewId, $resource = null, $context = null, $queueN $jobOptions[ApplyOperation::TRACKING_KEY] = $jobGroup->getId()->__toString(); $jobGroup->setJobCount($count); } + foreach ($docs as $doc) { if ($queueName && !$resource) { $subject = new ImpactedSubject( @@ -503,7 +506,7 @@ public function generateView($viewId, $resource = null, $context = null, $queueN } } - if (!empty($subjects)) { + if ($subjects !== []) { $this->queueApplyJob($subjects, $queueName, $jobOptions); } @@ -513,7 +516,7 @@ public function generateView($viewId, $resource = null, $context = null, $queueN 'duration' => $t->result(), 'filter' => $filter, 'from' => $from]); - $this->getStat()->timer(MONGO_CREATE_VIEW . ".{$viewId}", $t->result()); + $this->getStat()->timer(MONGO_CREATE_VIEW . ('.' . $viewId), $t->result()); $stat = ['count' => $count]; if (isset($jobOptions[ApplyOperation::TRACKING_KEY])) { @@ -527,7 +530,7 @@ public function generateView($viewId, $resource = null, $context = null, $queueN * Count the number of documents in the spec that match $filters. * * @param string $viewSpec View spec ID - * @param array $filters Query filters to get count on + * @param array $filters Query filters to get count on * * @return int */ @@ -544,11 +547,11 @@ public function count($viewSpec, array $filters = []) * @param bool $buildImpactIndex * @param mixed $source * @param mixed $joins - * @param mixed $dest + * @param array $dest * @param mixed $from * @param mixed $contextAlias */ - protected function doJoins($source, $joins, &$dest, $from, $contextAlias, $buildImpactIndex = true) + protected function doJoins(array $source, $joins, array &$dest, $from, $contextAlias, $buildImpactIndex = true) { // expand sequences before doing any joins... $this->expandSequence($joins, $source); @@ -577,6 +580,7 @@ protected function doJoins($source, $joins, &$dest, $from, $contextAlias, $build if (isset($ruleset['maxJoins']) && !$joinsPushed < $ruleset['maxJoins']) { break; // maxJoins reached } + $joinUris[] = [_ID_RESOURCE => $v[VALUE_URI], _ID_CONTEXT => $contextAlias]; $joinsPushed++; } @@ -599,19 +603,22 @@ protected function doJoins($source, $joins, &$dest, $from, $contextAlias, $build if (isset($ruleset['condition'])) { $ruleset['condition']['._id'] = $linkMatch['_id']; } + if (!(isset($ruleset['condition']) && $collection->count($ruleset['condition']) == 0)) { // make sure any sequences are expanded before extracting properties if (isset($ruleset['joins'])) { $this->expandSequence($ruleset['joins'], $linkMatch); } + if (isset($ruleset['filter'])) { foreach ($ruleset['filter'] as $filterPredicate => $filter) { foreach ($filter as $filterType => $filterMatch) { if (isset($linkMatch[$filterPredicate])) { foreach ($linkMatch[$filterPredicate] as $linkMatchType => $linkMatchValues) { - if (is_array($linkMatchValues) == false) { + if (is_array($linkMatchValues) === false) { $linkMatchValues = [$linkMatchType => $linkMatchValues]; } + foreach ($linkMatchValues as $linkMatchType => $linkMatchValue) { if ($this->matchesFilter($linkMatchType, $linkMatchValue, $filterType, $filterMatch)) { $dest[_GRAPHS][] = $this->extractProperties($linkMatch, $ruleset, $from); @@ -631,10 +638,9 @@ protected function doJoins($source, $joins, &$dest, $from, $contextAlias, $build } } } - if (count($recursiveJoins) > 0) { - foreach ($recursiveJoins as $r) { - $this->doJoins($r['data'], $r['ruleset'], $dest, $from, $contextAlias, $buildImpactIndex); - } + + foreach ($recursiveJoins as $r) { + $this->doJoins($r['data'], $r['ruleset'], $dest, $from, $contextAlias, $buildImpactIndex); } } } @@ -647,18 +653,14 @@ protected function doJoins($source, $joins, &$dest, $from, $contextAlias, $build * @param string $linkMatchValue * @param string $filterType * @param string $filterMatch - * - * @return bool */ - protected function matchesFilter($linkMatchType, $linkMatchValue, $filterType, $filterMatch) + protected function matchesFilter($linkMatchType, $linkMatchValue, $filterType, $filterMatch): bool { - if ($linkMatchType === $filterType) { - if ($linkMatchValue === $filterMatch || $this->labeller->uri_to_alias($linkMatchValue) === $filterMatch) { - return true; - } + if ($linkMatchType !== $filterType) { + return false; } - return false; + return $linkMatchValue === $filterMatch || $this->labeller->uri_to_alias($linkMatchValue) === $filterMatch; } /** @@ -666,12 +668,10 @@ protected function matchesFilter($linkMatchType, $linkMatchValue, $filterType, $ * of CBDs in a view. * * @param mixed $source - * @param mixed $viewSpec + * @param array $viewSpec * @param mixed $from - * - * @return array */ - protected function extractProperties($source, $viewSpec, $from) + protected function extractProperties(array $source, array $viewSpec, $from): array { $obj = []; if (isset($viewSpec['include'])) { @@ -680,23 +680,23 @@ protected function extractProperties($source, $viewSpec, $from) if (isset($source[$p])) { $obj[$p] = $source[$p]; } - if ($p === INCLUDE_RDF_SEQUENCE) { - if ($source['rdf:type']) { - foreach ($source['rdf:type'] as $u => $t) { - if (is_array($t) == false) { - $t = [$u => $t]; - } - foreach ($t as $typeOfType => $type) { - if ($typeOfType === 'u' && $type === 'rdf:Seq') { - $seqNumber = 1; - $found = true; - while ($found) { - if (isset($source['rdf:_' . $seqNumber])) { - $obj['rdf:_' . $seqNumber] = $source['rdf:_' . $seqNumber]; - $seqNumber++; - } else { - $found = false; - } + + if ($p === INCLUDE_RDF_SEQUENCE && $source['rdf:type']) { + foreach ($source['rdf:type'] as $u => $t) { + if (is_array($t) === false) { + $t = [$u => $t]; + } + + foreach ($t as $typeOfType => $type) { + if ($typeOfType === 'u' && $type === 'rdf:Seq') { + $seqNumber = 1; + $found = true; + while ($found) { + if (isset($source['rdf:_' . $seqNumber])) { + $obj['rdf:_' . $seqNumber] = $source['rdf:_' . $seqNumber]; + $seqNumber++; + } else { + $found = false; } } } @@ -704,19 +704,22 @@ protected function extractProperties($source, $viewSpec, $from) } } } + if (isset($viewSpec['joins'])) { foreach ($viewSpec['joins'] as $p => $join) { if (isset($join['maxJoins'])) { // todo: refactor with below (extract method) // only include up to maxJoins for ($i = 0; $i < $join['maxJoins']; $i++) { - if (isset($source[$p]) && (isset($source[$p][VALUE_URI]) || isset($source[$p][VALUE_LITERAL])) && $i == 0) { // cater for source with only one val + if (isset($source[$p]) && (isset($source[$p][VALUE_URI]) || isset($source[$p][VALUE_LITERAL])) && $i === 0) { // cater for source with only one val $obj[$p] = $source[$p]; } + if (isset($source[$p], $source[$p][$i])) { if (!isset($obj[$p])) { $obj[$p] = []; } + $obj[$p][] = $source[$p][$i]; } } @@ -731,13 +734,15 @@ protected function extractProperties($source, $viewSpec, $from) // todo: refactor with above (extract method) // only include up to maxJoins for ($i = 0; $i < $viewSpec['joins'][$p]['maxJoins']; $i++) { - if ($val && (isset($val[VALUE_URI]) || isset($val[VALUE_LITERAL])) && $i == 0) { // cater for source with only one val + if ($val && (isset($val[VALUE_URI]) || isset($val[VALUE_LITERAL])) && $i === 0) { // cater for source with only one val $obj[$p] = $val; } + if ($val && isset($val[$i])) { if (!$obj[$p]) { $obj[$p] = []; } + $obj[$p][] = $val[$i]; } } @@ -769,6 +774,7 @@ protected function extractProperties($source, $viewSpec, $from) $count = count($source[$c['property']]); } } + $obj[$predicate] = [VALUE_LITERAL => (string) $count]; } } @@ -791,10 +797,8 @@ protected function getCollectionForViewSpec($viewSpecId) * @param array|string $resourceUriOrArray * @param string $context * @param string $viewType - * - * @return array */ - private function createTripodViewIdsFromResourceUris($resourceUriOrArray, $context, $viewType) + private function createTripodViewIdsFromResourceUris(array $resourceUriOrArray, $context, $viewType): array { $contextAlias = $this->getContextAlias($context); $ret = []; @@ -812,13 +816,6 @@ private function createTripodViewIdsFromResourceUris($resourceUriOrArray, $conte */ private function getFromCollectionForViewSpec($viewSpec) { - $from = null; - if (isset($viewSpec['from'])) { - $from = $viewSpec['from']; - } else { - $from = $this->podName; - } - - return $from; + return $viewSpec['from'] ?? $this->podName; } } diff --git a/src/mongo/documents/Tables.php b/src/mongo/documents/Tables.php index d4017774..3e749e5a 100644 --- a/src/mongo/documents/Tables.php +++ b/src/mongo/documents/Tables.php @@ -1,5 +1,7 @@ exchangeArray($this->toTableRow($data)); } @@ -24,7 +26,7 @@ public function bsonUnserialize(array $data) /** * Models the table row from the source data. * - * @param array $doc Database document + * @param array $doc Database document * * @return array */ diff --git a/src/mongo/jobs/ApplyOperation.php b/src/mongo/jobs/ApplyOperation.php index a21ab2ff..eb4848eb 100644 --- a/src/mongo/jobs/ApplyOperation.php +++ b/src/mongo/jobs/ApplyOperation.php @@ -1,5 +1,7 @@ getStat()->increment( MONGO_QUEUE_APPLY_OPERATION_JOB . '.' . SUBJECT_COUNT, @@ -74,6 +78,7 @@ public function perform() break; } } + $this->infoLog( '[JobGroupId ' . $jobGroup->getId()->__toString() . '] composite cleanup for ' . $subject['operation'] . ' removed ' . $count . ' stale composite documents' @@ -88,7 +93,7 @@ public function perform() * @param string|null $queueName * @param array $otherData */ - public function createJob(array $subjects, $queueName = null, $otherData = []) + public function createJob(array $subjects, $queueName = null, $otherData = []): void { $configInstance = $this->getConfigInstance(); if (!$queueName) { @@ -116,20 +121,16 @@ function (ImpactedSubject $subject) { /** * Stat string for successful job timer. - * - * @return string */ - protected function getStatTimerSuccessKey() + protected function getStatTimerSuccessKey(): string { return MONGO_QUEUE_APPLY_OPERATION_SUCCESS; } /** * Stat string for failed job increment. - * - * @return string */ - protected function getStatFailureIncrementKey() + protected function getStatFailureIncrementKey(): string { return MONGO_QUEUE_APPLY_OPERATION_FAIL; } @@ -137,9 +138,9 @@ protected function getStatFailureIncrementKey() /** * For mocking. * - * @return ImpactedSubject + * @param array $args */ - protected function createImpactedSubject(array $args) + protected function createImpactedSubject(array $args): \Tripod\Mongo\ImpactedSubject { return new ImpactedSubject( $args['resourceId'], @@ -155,20 +156,16 @@ protected function createImpactedSubject(array $args) * * @param string $storeName Tripod store (database) name * @param ObjectId|string $trackingKey JobGroup ID - * - * @return JobGroup */ - protected function getJobGroup($storeName, $trackingKey) + protected function getJobGroup($storeName, $trackingKey): \Tripod\Mongo\JobGroup { return new JobGroup($storeName, $trackingKey); } /** * For mocking. - * - * @return MongoSearchProvider */ - protected function getSearchProvider(Driver $tripod) + protected function getSearchProvider(Driver $tripod): \Tripod\Mongo\MongoSearchProvider { return new MongoSearchProvider($tripod); } diff --git a/src/mongo/jobs/DiscoverImpactedSubjects.php b/src/mongo/jobs/DiscoverImpactedSubjects.php index 649876ed..d1ba9cf8 100644 --- a/src/mongo/jobs/DiscoverImpactedSubjects.php +++ b/src/mongo/jobs/DiscoverImpactedSubjects.php @@ -1,5 +1,7 @@ getStat()->increment(MONGO_QUEUE_DISCOVER_JOB . '.' . SUBJECT_COUNT, $this->subjectCount); @@ -47,7 +53,7 @@ public function tearDown() * * @throws \Exception */ - public function perform() + public function perform(): void { $tripod = $this->getTripod( $this->args[self::STORE_NAME_KEY], @@ -74,12 +80,9 @@ public function perform() $this->subjectCount++; $subjectTimer = new Timer(); $subjectTimer->start(); - if (isset($this->args[self::QUEUE_KEY]) || count($subject->getSpecTypes()) == 0) { - if (isset($this->args[self::QUEUE_KEY])) { - $queueName = $this->args[self::QUEUE_KEY]; - } else { - $queueName = $configInstance::getApplyQueueName(); - } + if (isset($this->args[self::QUEUE_KEY]) || count($subject->getSpecTypes()) === 0) { + $queueName = $this->args[self::QUEUE_KEY] ?? $configInstance::getApplyQueueName(); + $this->addSubjectToQueue($subject, $queueName); } else { $specsGroupedByQueue = []; @@ -111,15 +114,19 @@ public function perform() break; } + if (!$spec || !isset($spec['queue'])) { if (!$spec) { $spec = []; } + $spec['queue'] = $configInstance::getApplyQueueName(); } + if (!isset($specsGroupedByQueue[$spec['queue']])) { $specsGroupedByQueue[$spec['queue']] = []; } + $specsGroupedByQueue[$spec['queue']][] = $specType; } @@ -135,14 +142,17 @@ public function perform() $this->addSubjectToQueue($queuedSubject, $queueName); } } + $subjectTimer->stop(); // stat time taken to discover impacted subjects for the given subject of change $this->getStat()->timer(MONGO_QUEUE_DISCOVER_SUBJECT, $subjectTimer->result()); } - if (!empty($this->subjectsGroupedByQueue)) { + + if ($this->subjectsGroupedByQueue !== []) { foreach ($this->subjectsGroupedByQueue as $queueName => $subjects) { $this->getApplyOperation()->createJob($subjects, $queueName, $this->getTripodOptions()); } + $this->subjectsGroupedByQueue = []; } } @@ -152,7 +162,7 @@ public function perform() /** * @param string|null $queueName */ - public function createJob(array $data, $queueName = null) + public function createJob(array $data, $queueName = null): void { $configInstance = $this->getConfigInstance(); if (!$queueName) { @@ -160,25 +170,22 @@ public function createJob(array $data, $queueName = null) } elseif (strpos($queueName, $configInstance::getDiscoverQueueName()) === false) { $queueName = $configInstance::getDiscoverQueueName() . '::' . $queueName; } + $this->submitJob($queueName, get_class($this), array_merge($data, $this->generateConfigJobArgs())); } /** * Stat string for successful job timer. - * - * @return string */ - protected function getStatTimerSuccessKey() + protected function getStatTimerSuccessKey(): string { return MONGO_QUEUE_DISCOVER_SUCCESS; } /** * Stat string for failed job increment. - * - * @return string */ - protected function getStatFailureIncrementKey() + protected function getStatFailureIncrementKey(): string { return MONGO_QUEUE_DISCOVER_FAIL; } @@ -191,6 +198,7 @@ protected function addSubjectToQueue(ImpactedSubject $subject, $queueName) if (!array_key_exists($queueName, $this->subjectsGroupedByQueue)) { $this->subjectsGroupedByQueue[$queueName] = []; } + $this->subjectsGroupedByQueue[$queueName][] = $subject; } @@ -201,7 +209,7 @@ protected function addSubjectToQueue(ImpactedSubject $subject, $queueName) */ protected function getApplyOperation() { - if (!isset($this->applyOperation)) { + if ($this->applyOperation === null) { $this->applyOperation = new ApplyOperation(); } diff --git a/src/mongo/jobs/EnsureIndexes.php b/src/mongo/jobs/EnsureIndexes.php index 19093a0c..915e7407 100644 --- a/src/mongo/jobs/EnsureIndexes.php +++ b/src/mongo/jobs/EnsureIndexes.php @@ -1,5 +1,7 @@ debugLog('Ensuring indexes for tenant=' . $this->args[self::STORENAME_KEY] . ', reindex=' . $this->args[self::REINDEX_KEY] . ', background=' . $this->args[self::BACKGROUND_KEY]); @@ -37,7 +42,7 @@ public function perform() * @param string $queueName * @param mixed $background */ - public function createJob($storeName, $reindex, $background, $queueName = null) + public function createJob($storeName, $reindex, $background, $queueName = null): void { $configInstance = $this->getConfigInstance(); if (!$queueName) { @@ -57,28 +62,21 @@ public function createJob($storeName, $reindex, $background, $queueName = null) /** * Stat string for successful job timer. - * - * @return string */ - protected function getStatTimerSuccessKey() + protected function getStatTimerSuccessKey(): string { return MONGO_QUEUE_ENSURE_INDEXES_SUCCESS; } /** * Stat string for failed job increment. - * - * @return string */ - protected function getStatFailureIncrementKey() + protected function getStatFailureIncrementKey(): string { return MONGO_QUEUE_ENSURE_INDEXES_FAIL; } - /** - * @return IndexUtils - */ - protected function getIndexUtils() + protected function getIndexUtils(): \Tripod\Mongo\IndexUtils { return new IndexUtils(); } diff --git a/src/mongo/providers/ISearchProvider.php b/src/mongo/providers/ISearchProvider.php index 7478ec98..ff17ca77 100644 --- a/src/mongo/providers/ISearchProvider.php +++ b/src/mongo/providers/ISearchProvider.php @@ -1,5 +1,7 @@ tripod = $tripod; $this->storeName = $tripod->getStoreName(); $this->labeller = new Labeller(); $this->config = \Tripod\Config::getInstance(); @@ -48,11 +44,10 @@ public function __construct(Driver $tripod) * * @param array $document the document to index * - * @return mixed * * @throws SearchException if there was an error indexing the document */ - public function indexDocument($document) + public function indexDocument($document): void { if (isset($document['_id']['type'])) { $collection = $this->config->getCollectionForSearchDocument($this->storeName, $document['_id']['type']); @@ -78,11 +73,10 @@ public function indexDocument($document) * @param string $context * @param array|string|null $specId * - * @return mixed * * @throws SearchException if there was an error removing the document */ - public function deleteDocument($resource, $context, $specId = []) + public function deleteDocument($resource, $context, $specId = []): void { $query = [_ID_KEY . '.' . _ID_RESOURCE => $this->labeller->uri_to_alias($resource), _ID_KEY . '.' . _ID_CONTEXT => $context]; @@ -94,18 +88,21 @@ public function deleteDocument($resource, $context, $specId = []) if (!in_array($specId, $specTypes)) { return; } + $query[_ID_KEY][_ID_TYPE] = $specId; $searchTypes[] = $specId; } elseif (is_array($specId)) { // Only filter on search document spec types $specId = array_intersect($specTypes, $specId); - if (empty($specId)) { + if ($specId === []) { return; } + $query[_ID_KEY . '.' . _ID_TYPE] = ['$in' => array_values($specId)]; $searchTypes = $specId; } } + foreach ($this->config->getCollectionsForSearch($this->storeName, $searchTypes) as $collection) { $collection->deleteMany($query); } @@ -122,7 +119,7 @@ public function deleteDocument($resource, $context, $specId = []) * * @return array the ids of search documents that had matching entries in their impact index */ - public function findImpactedDocuments(array $resourcesAndPredicates, $context) + public function findImpactedDocuments(array $resourcesAndPredicates, $context): array { $contextAlias = $this->labeller->uri_to_alias($context); @@ -142,7 +139,7 @@ public function findImpactedDocuments(array $resourcesAndPredicates, $context) $id = [_ID_RESOURCE => $resourceAlias, _ID_CONTEXT => $contextAlias]; // If we don't have a working config or there are no predicates listed, remove all // rows associated with the resource in all search types - if (empty($specPredicates) || empty($resourcePredicates)) { + if ($specPredicates === [] || empty($resourcePredicates)) { // build $filter for queries to impact index $resourceFilters[] = $id; } else { @@ -152,6 +149,7 @@ public function findImpactedDocuments(array $resourcesAndPredicates, $context) if (!isset($searchDocFilters[$searchDocType])) { $searchDocFilters[$searchDocType] = []; } + // build $filter for queries to impact index $searchDocFilters[$searchDocType][] = $id; } @@ -160,7 +158,7 @@ public function findImpactedDocuments(array $resourcesAndPredicates, $context) } $searchTypes = []; - if (empty($searchDocFilters) && !empty($resourceFilters)) { + if ($searchDocFilters === [] && $resourceFilters !== []) { $query = [_IMPACT_INDEX => ['$in' => $resourceFilters]]; } else { $query = []; @@ -170,7 +168,7 @@ public function findImpactedDocuments(array $resourcesAndPredicates, $context) $searchTypes[] = $searchDocType; } - if (!empty($resourceFilters)) { + if ($resourceFilters !== []) { $query[] = [_IMPACT_INDEX => ['$in' => $resourceFilters]]; } @@ -180,7 +178,8 @@ public function findImpactedDocuments(array $resourcesAndPredicates, $context) $query = ['$or' => $query]; } } - if (empty($query)) { + + if ($query === []) { return []; } @@ -207,17 +206,20 @@ public function findImpactedDocuments(array $resourcesAndPredicates, $context) * * @throws SearchException */ - public function search($q, $type, $indices = [], $fields = [], $limit = 10, $offset = 0) + public function search($q, $type, $indices = [], $fields = [], $limit = 10, $offset = 0): array { if (empty($q)) { throw new SearchException('You must specify a query'); } + if (empty($type)) { throw new SearchException('You must specify the search document type to restrict the query to'); } + if (empty($indices)) { throw new SearchException('You must specify at least one index from the search document specification to query against'); } + if (empty($fields)) { throw new SearchException('You must specify at least one field from the search document specification to return'); } @@ -234,25 +236,25 @@ public function search($q, $type, $indices = [], $fields = [], $limit = 10, $off $terms = array_values(array_diff($original_terms, $this->stopWords)); // todo: this means if all the words entered were stop words, then use the orginal terms rather than do nothing! - if (empty($terms)) { + if ($terms === []) { $terms = $original_terms; } $regexes = []; foreach ($terms as $t) { - $regexes[] = new Regex("{$t}", ''); + $regexes[] = new Regex($t, ''); } $query = []; $query['_id.type'] = $type; - if (count($indices) == 1) { + if (count($indices) === 1) { $searchIndex = $indices[0]; $query[$searchIndex] = ['$all' => $regexes]; } else { $query['$or'] = []; foreach ($indices as $searchIndex) { - $query['$or'][] = ["{$searchIndex}" => ['$all' => $regexes]]; + $query['$or'][] = [$searchIndex => ['$all' => $regexes]]; } } @@ -260,8 +262,10 @@ public function search($q, $type, $indices = [], $fields = [], $limit = 10, $off foreach ($fields as $field) { $fieldsToReturn[$field] = 1; } + $searchTimer = new Timer(); $searchTimer->start(); + $cursor = $this->config->getCollectionForSearchDocument($this->storeName, $type) ->find($query, [ 'projection' => $fieldsToReturn, @@ -289,12 +293,9 @@ public function search($q, $type, $indices = [], $fields = [], $limit = 10, $off if (count($fields) > 1) { $r = []; foreach ($fields as $field) { - if (isset($result[$field])) { - $r[$field] = $result[$field]; - } else { - $r[$field] = ''; - } + $r[$field] = $result[$field] ?? ''; } + $searchResults['results'][] = $r; } else { $searchResults['results'][] = $result[$fields[0]]; @@ -303,16 +304,14 @@ public function search($q, $type, $indices = [], $fields = [], $limit = 10, $off } else { $searchResults['head']['count'] = 0; } + $searchTimer->stop(); $searchResults['head']['duration'] = $searchTimer->result() . ' ms'; return $searchResults; } - /** - * @return string - */ - public function getSearchCollectionName() + public function getSearchCollectionName(): string { return SEARCH_INDEX_COLLECTION; } @@ -333,18 +332,21 @@ public function deleteSearchDocumentsByTypeId($typeId, $timestamp = null) { $searchSpec = $this->getSearchDocumentSpecification($typeId); if ($searchSpec == null) { - throw new SearchException("Could not find a search specification for {$typeId}"); + throw new SearchException('Could not find a search specification for ' . $typeId); } + $query = ['_id.type' => $typeId]; if ($timestamp) { if (!$timestamp instanceof UTCDateTime) { $timestamp = new UTCDateTime($timestamp); } + $query['$or'] = [ [\_CREATED_TS => ['$lt' => $timestamp]], [\_CREATED_TS => ['$exists' => false]], ]; } + $deleteResponse = $this->getCollectionForSearchSpec($typeId) ->deleteMany($query); @@ -355,7 +357,7 @@ public function deleteSearchDocumentsByTypeId($typeId, $timestamp = null) * Count the number of documents in the spec that match $filters. * * @param string $searchSpec Search spec ID - * @param array $filters Query filters to get count on + * @param array $filters Query filters to get count on * * @return int */ diff --git a/src/mongo/serializers/NQuadSerializer.php b/src/mongo/serializers/NQuadSerializer.php index 4e10071d..954cba5d 100644 --- a/src/mongo/serializers/NQuadSerializer.php +++ b/src/mongo/serializers/NQuadSerializer.php @@ -1,5 +1,7 @@ esc_chars = []; $this->raw = 0; @@ -28,20 +31,23 @@ public function getTerm($v) if (preg_match('/^\_\:/', $v)) { return $v; } + if (preg_match('/^[a-z0-9]+\:[^\s\"]*$/is', $v)) { return '<' . htmlspecialchars($this->escape($v)) . '>'; } return $this->getTerm(['type' => 'literal', 'value' => $v]); } + if ($v['type'] != 'literal') { return $this->getTerm($v['value']); } + // literal $quot = '"'; if ($this->raw && preg_match('/\"/', $v['value'])) { $quot = "'"; - if (preg_match('/\'/', $v['value'])) { + if (preg_match("/'/", $v['value'])) { $quot = '"""'; if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) { $quot = "'''"; @@ -51,7 +57,8 @@ public function getTerm($v) } } } - if ($this->raw && (strlen($quot) == 1) && preg_match('/[\x0d\x0a]/', $v['value'])) { + + if ($this->raw && (strlen($quot) === 1) && preg_match('/[\x0d\x0a]/', $v['value'])) { $quot = $quot . $quot . $quot; } @@ -66,10 +73,8 @@ public function getTerm($v) /** * @param array $index * @param string $context - * - * @return string */ - public function getSerializedIndex($index, $context) + public function getSerializedIndex($index, ?string $context): string { $r = ''; $nl = "\n"; @@ -87,13 +92,15 @@ public function getSerializedIndex($index, $context) if (!is_array($os)) { // single literal o $os = [['value' => $os, 'type' => 'literal']]; } + foreach ($os as $o) { $o = $this->getTerm($o); - $r .= $r ? $nl : ''; + $r .= $r !== '' && $r !== '0' ? $nl : ''; $r .= $s . ' ' . $p . ' ' . $o; if ($context != null) { $r .= ' <' . $context . '>'; } + $r .= ' .'; } } @@ -120,6 +127,7 @@ public function escape($v) if (!isset($this->esc_chars[$c])) { $this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c)); } + $r .= $this->esc_chars[$c]; } @@ -128,10 +136,8 @@ public function escape($v) /** * @param string $c - * - * @return int */ - public function getCharNo($c) + public function getCharNo($c): int { $c_utf = utf8_encode($c); $bl = strlen($c_utf); // binary length @@ -172,40 +178,52 @@ public function getEscapedChar($c, $no) { // see http://www.w3.org/TR/rdf-testcases/#ntrip_strings if ($no < 9) { return '\u' . sprintf('%04X', $no); - } // #x0-#x8 (0-8) + } + // #x0-#x8 (0-8) if ($no == 9) { return '\t'; - } // #x9 (9) + } + // #x9 (9) if ($no == 10) { return '\n'; - } // #xA (10) + } + // #xA (10) if ($no < 13) { return '\u' . sprintf('%04X', $no); - } // #xB-#xC (11-12) + } + // #xB-#xC (11-12) if ($no == 13) { return '\r'; - } // #xD (13) + } + // #xD (13) if ($no < 32) { return '\u' . sprintf('%04X', $no); - } // #xE-#x1F (14-31) + } + // #xE-#x1F (14-31) if ($no < 34) { return $c; - } // #x20-#x21 (32-33) + } + // #x20-#x21 (32-33) if ($no == 34) { return '\"'; - } // #x22 (34) + } + // #x22 (34) if ($no < 92) { return $c; - } // #x23-#x5B (35-91) + } + // #x23-#x5B (35-91) if ($no == 92) { return '\\\\'; - } // #x5C (92) + } + // #x5C (92) if ($no < 127) { return $c; - } // #x5D-#x7E (93-126) + } + // #x5D-#x7E (93-126) if ($no < 65536) { return '\u' . sprintf('%04X', $no); - } // #x7F-#xFFFF (128-65535) + } + // #x7F-#xFFFF (128-65535) if ($no < 1114112) { return '\U' . sprintf('%08X', $no); } // #x10000-#x10FFFF (65536-1114111) diff --git a/src/mongo/util/DateUtil.php b/src/mongo/util/DateUtil.php index 57858d5a..9d5ded69 100644 --- a/src/mongo/util/DateUtil.php +++ b/src/mongo/util/DateUtil.php @@ -1,5 +1,7 @@ getConfig(); $dbs = ($storeName == null) ? $config->getDbs() : [$storeName]; @@ -77,12 +79,12 @@ public function ensureIndexes($reindex = false, $storeName = null, $background = if (isset($spec['ensureIndexes'])) { $indexes = array_merge($indexes, $spec['ensureIndexes']); } - if ($reindex) { - if (!in_array($collection->getNamespace(), $reindexedCollections)) { - $collection->dropIndexes(); - $reindexedCollections[] = $collection->getNamespace(); - } + + if ($reindex && !in_array($collection->getNamespace(), $reindexedCollections)) { + $collection->dropIndexes(); + $reindexedCollections[] = $collection->getNamespace(); } + foreach ($indexes as $index) { $collection->createIndex( $index, @@ -107,12 +109,12 @@ public function ensureIndexes($reindex = false, $storeName = null, $background = if (isset($spec['ensureIndexes'])) { $indexes = array_merge($indexes, $spec['ensureIndexes']); } - if ($reindex) { - if (!in_array($collection->getNamespace(), $reindexedCollections)) { - $collection->dropIndexes(); - $reindexedCollections[] = $collection->getNamespace(); - } + + if ($reindex && !in_array($collection->getNamespace(), $reindexedCollections)) { + $collection->dropIndexes(); + $reindexedCollections[] = $collection->getNamespace(); } + foreach ($indexes as $index) { $collection->createIndex( $index, @@ -135,12 +137,11 @@ public function ensureIndexes($reindex = false, $storeName = null, $background = [\_CREATED_TS => 1], ]; - if ($reindex) { - if (!in_array($collection->getNamespace(), $reindexedCollections)) { - $collection->dropIndexes(); - $reindexedCollections[] = $collection->getNamespace(); - } + if ($reindex && !in_array($collection->getNamespace(), $reindexedCollections)) { + $collection->dropIndexes(); + $reindexedCollections[] = $collection->getNamespace(); } + foreach ($indexes as $index) { $collection->createIndex( $index, @@ -160,7 +161,7 @@ public function ensureIndexes($reindex = false, $storeName = null, $background = * * @return \Tripod\Mongo\Config */ - protected function getConfig() + protected function getConfig(): \Tripod\Mongo\IConfigInstance { return Config::getInstance(); } diff --git a/src/mongo/util/TriplesUtil.php b/src/mongo/util/TriplesUtil.php index e88190d9..96595c29 100644 --- a/src/mongo/util/TriplesUtil.php +++ b/src/mongo/util/TriplesUtil.php @@ -1,5 +1,7 @@ getDefaultContextAlias() : $this->labeller->uri_to_alias($context); if (array_key_exists($podName, $this->collections)) { @@ -57,6 +59,7 @@ public function loadTriplesAbout($subject, array $triples, $storeName, $podName, $graph->add_literal_triple($subject, $predicate, $object); } } + if ($allowableTypes != null && is_array($allowableTypes)) { $types = $graph->get_resource_triple_values($subject, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); if ($types == null || empty($types)) { @@ -73,6 +76,7 @@ public function loadTriplesAbout($subject, array $triples, $storeName, $podName, return; } + $this->saveCBD($subject, $graph, $collection, $context); } @@ -107,10 +111,7 @@ public function bsonizeTriplesAbout($subject, array $triples, $context = null) return $graph->to_tripod_array($subject, $context); } - /** - * @return array - */ - public function extractMissingPredicateNs(array $triples) + public function extractMissingPredicateNs(array $triples): array { $missingNs = []; $graph = new MongoGraph(); @@ -130,10 +131,7 @@ public function extractMissingPredicateNs(array $triples) return array_unique($missingNs); } - /** - * @return array - */ - public function extractMissingObjectNs(array $triples) + public function extractMissingObjectNs(array $triples): array { $missingNs = []; $graph = new MongoGraph(); @@ -157,10 +155,8 @@ public function extractMissingObjectNs(array $triples) /** * @param string $ns - * - * @return string */ - public function suggestPrefix($ns) + public function suggestPrefix($ns): string { $parts = preg_split('/[\/#]/', $ns); for ($i = count($parts) - 1; $i >= 0; $i--) { @@ -209,7 +205,7 @@ protected function saveCBD($cbdSubject, MongoGraph $cbdGraph, Collection $collec { $cbdSubject = $this->labeller->uri_to_alias($cbdSubject); if ($cbdGraph == null || $cbdGraph->is_empty()) { - throw new \Exception("graph for {$cbdSubject} was null"); + throw new \Exception(sprintf('graph for %s was null', $cbdSubject)); } try { @@ -227,7 +223,7 @@ protected function saveCBD($cbdSubject, MongoGraph $cbdGraph, Collection $collec try { $collection->updateOne($criteria, ['$set' => $existingGraph->to_tripod_array($cbdSubject, $context)], ['w' => 1]); } catch (\Exception $e2) { - throw new \Exception($e2->getMessage()); // todo: would be good to have typed exception + throw new \Exception($e2->getMessage(), $e->getCode(), $e); // todo: would be good to have typed exception } } else { // retry @@ -236,7 +232,7 @@ protected function saveCBD($cbdSubject, MongoGraph $cbdGraph, Collection $collec try { $collection->insertOne($cbdGraph->to_tripod_array($cbdSubject, $context), ['w' => 1]); } catch (\Exception $e2) { - throw new \Exception($e2->getMessage()); // todo: would be good to have typed exception + throw new \Exception($e2->getMessage(), $e->getCode(), $e); // todo: would be good to have typed exception } } } @@ -254,6 +250,7 @@ private function isUri($object) /** * @return string + * @param list|bool $parts */ private function extract_object(array $parts) { @@ -271,7 +268,7 @@ private function extract_object(array $parts) $json_string = '{"string":"' . str_replace('\u', '\u', $str) . '"}'; $json = json_decode($json_string, true); if (!empty($json)) { - $str = $json['string']; + return $json['string']; } return $str; @@ -279,15 +276,9 @@ private function extract_object(array $parts) /** * @param string $input - * - * @return bool */ - private function is_object_literal($input) + private function is_object_literal($input): bool { - if ($input[0] == '"') { - return true; - } - - return false; + return $input[0] == '"'; } } diff --git a/test/performance/mongo/LargeGraphTest.php b/test/performance/mongo/LargeGraphTest.php index f68bbb50..5c359bf6 100644 --- a/test/performance/mongo/LargeGraphTest.php +++ b/test/performance/mongo/LargeGraphTest.php @@ -1,5 +1,7 @@ loadLargeGraphData(); } - public function testUpdateSingleTripleOfLargeGraph() + public function testUpdateSingleTripleOfLargeGraph(): void { $uri = 'http://largegraph/1'; @@ -37,6 +39,7 @@ public function testUpdateSingleTripleOfLargeGraph() $graph = new ExtendedGraph(); $graph->add_literal_triple($uri, 'http://rdfs.org/sioc/spec/name', 'new name'); + $this->tripod->saveChanges(new ExtendedGraph(), $graph); $testEndTime = microtime(); @@ -48,7 +51,7 @@ public function testUpdateSingleTripleOfLargeGraph() ); } - public function testDescribeOfLargeGraph() + public function testDescribeOfLargeGraph(): void { $uri = 'http://largegraph/1'; @@ -56,6 +59,7 @@ public function testDescribeOfLargeGraph() $graph = new ExtendedGraph(); $graph->add_literal_triple($uri, 'http://rdfs.org/sioc/spec/name', 'new name'); + $this->tripod->describeResource($uri); $testEndTime = microtime(); @@ -75,7 +79,7 @@ protected function loadLargeGraphData() } } - protected function getConfigLocation() + protected function getConfigLocation(): string { return __DIR__ . '/../../unit/mongo/data/config.json'; } diff --git a/test/performance/mongo/MongoTripodConfigTest.php b/test/performance/mongo/MongoTripodConfigTest.php index 4a353613..a20d2c0c 100644 --- a/test/performance/mongo/MongoTripodConfigTest.php +++ b/test/performance/mongo/MongoTripodConfigTest.php @@ -1,5 +1,7 @@ add_literal_triple('http://some/subject/1', 'http://some/predicate', $value); @@ -29,14 +31,15 @@ public function testAddValidValueToLiteralResultsInTriple($value) $this->assertTrue($hasPropertyResult, 'The triple should have been added for this value'); } - public function addValidValueToLiteralResultsInTriple_Provider() + /** + * @return \Iterator<(int | string), array<(1.2 | int | string | true)>> + */ + public function addValidValueToLiteralResultsInTriple_Provider(): \Iterator { - return [ - ['String'], - [1], - [1.2], - [true], - ]; + yield ['String']; + yield [1]; + yield [1.2]; + yield [true]; } /** @@ -44,7 +47,7 @@ public function addValidValueToLiteralResultsInTriple_Provider() * * @param mixed $value */ - public function testAddInvalidValueToLiteralResultsInNoTriple($value) + public function testAddInvalidValueToLiteralResultsInNoTriple($value): void { $graph = new ExtendedGraph(); $addResult = $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', $value); @@ -54,13 +57,14 @@ public function testAddInvalidValueToLiteralResultsInNoTriple($value) $this->assertFalse($hasPropertyResult, 'The triple should not have been added for this value'); } - public function addInvalidValueToLiteralResultsInNoTriple_Provider() + /** + * @return \Iterator<(int | string), array<(Closure(): void | \stdClass | null)>> + */ + public function addInvalidValueToLiteralResultsInNoTriple_Provider(): \Iterator { - return [ - [null], - [new stdClass()], - [function (): void {}], - ]; + yield [null]; + yield [new stdClass()]; + yield [function (): void {}]; } /** @@ -68,7 +72,7 @@ public function addInvalidValueToLiteralResultsInNoTriple_Provider() * * @param mixed $value */ - public function testAddInvalidSubjectToLiteralThrowsException($value) + public function testAddInvalidSubjectToLiteralThrowsException($value): void { $this->expectException(Tripod\Exceptions\Exception::class); @@ -76,18 +80,19 @@ public function testAddInvalidSubjectToLiteralThrowsException($value) $graph->add_resource_triple($value, 'http://some/predicate', 'http://someplace.com'); } - public function addInvalidSubjectToLiteralResultsInNoTriple_Provider() + /** + * @return \Iterator<(int | string), array<(1.2 | array | Closure(): void | int | \stdClass | string | true | null)>> + */ + public function addInvalidSubjectToLiteralResultsInNoTriple_Provider(): \Iterator { - return [ - [''], - [1], - [1.2], - [true], - [[]], - [null], - [new stdClass()], - [function (): void {}], - ]; + yield ['']; + yield [1]; + yield [1.2]; + yield [true]; + yield [[]]; + yield [null]; + yield [new stdClass()]; + yield [function (): void {}]; } /** @@ -95,7 +100,7 @@ public function addInvalidSubjectToLiteralResultsInNoTriple_Provider() * * @param mixed $value */ - public function testAddInvalidPredicateToLiteralThrowsException($value) + public function testAddInvalidPredicateToLiteralThrowsException($value): void { $this->expectException(Tripod\Exceptions\Exception::class); @@ -103,7 +108,10 @@ public function testAddInvalidPredicateToLiteralThrowsException($value) $graph->add_resource_triple('http://some/subject/1', $value, 'http://someplace.com'); } - public function addInvalidPredicateToLiteralResultsInNoTriple_Provider() + /** + * @return array|null[]|\stdClass[]|(\Closure(): void)[]> + */ + public function addInvalidPredicateToLiteralResultsInNoTriple_Provider(): array { return [ [''], @@ -117,7 +125,7 @@ public function addInvalidPredicateToLiteralResultsInNoTriple_Provider() ]; } - public function testAddValidValueToResourceResultsInTriple() + public function testAddValidValueToResourceResultsInTriple(): void { $value = 'A String'; $graph = new ExtendedGraph(); @@ -133,7 +141,7 @@ public function testAddValidValueToResourceResultsInTriple() * * @param mixed $value */ - public function testAddInvalidValueToResourceResultsInNoTriple($value) + public function testAddInvalidValueToResourceResultsInNoTriple($value): void { $graph = new ExtendedGraph(); @@ -144,17 +152,18 @@ public function testAddInvalidValueToResourceResultsInNoTriple($value) $this->assertFalse($hasPropertyResult, 'The triple should not have been added for this value'); } - public function addInvalidValueToResourceResultsInNoTriple_Provider() + /** + * @return \Iterator<(int | string), array<(1.2 | array | Closure(): void | int | \stdClass | true | null)>> + */ + public function addInvalidValueToResourceResultsInNoTriple_Provider(): \Iterator { - return [ - [1], - [1.2], - [true], - [[]], - [null], - [new stdClass()], - [function (): void {}], - ]; + yield [1]; + yield [1.2]; + yield [true]; + yield [[]]; + yield [null]; + yield [new stdClass()]; + yield [function (): void {}]; } /** @@ -162,7 +171,7 @@ public function addInvalidValueToResourceResultsInNoTriple_Provider() * * @param mixed $value */ - public function testAddInvalidSubjectToResourceThrowsException($value) + public function testAddInvalidSubjectToResourceThrowsException($value): void { $this->expectException(Tripod\Exceptions\Exception::class); @@ -170,18 +179,19 @@ public function testAddInvalidSubjectToResourceThrowsException($value) $graph->add_resource_triple($value, 'http://some/predicate', 'http://someplace.com'); } - public function addInvalidSubjectToResourceResultsInNoTriple_Provider() + /** + * @return \Iterator<(int | string), array<(1.2 | array | Closure(): void | int | \stdClass | string | true | null)>> + */ + public function addInvalidSubjectToResourceResultsInNoTriple_Provider(): \Iterator { - return [ - [''], - [1], - [1.2], - [true], - [[]], - [null], - [new stdClass()], - [function (): void {}], - ]; + yield ['']; + yield [1]; + yield [1.2]; + yield [true]; + yield [[]]; + yield [null]; + yield [new stdClass()]; + yield [function (): void {}]; } /** @@ -189,7 +199,7 @@ public function addInvalidSubjectToResourceResultsInNoTriple_Provider() * * @param mixed $value */ - public function testAddInvalidPredicateToResourceThrowsException($value) + public function testAddInvalidPredicateToResourceThrowsException($value): void { $this->expectException(Tripod\Exceptions\Exception::class); @@ -197,7 +207,10 @@ public function testAddInvalidPredicateToResourceThrowsException($value) $graph->add_resource_triple('http://some/subject/1', $value, 'http://someplace.com'); } - public function addInvalidPredicateToResourceResultsInNoTriple_Provider() + /** + * @return array|null[]|\stdClass[]|(\Closure(): void)[]> + */ + public function addInvalidPredicateToResourceResultsInNoTriple_Provider(): array { return [ [''], @@ -211,7 +224,7 @@ public function addInvalidPredicateToResourceResultsInNoTriple_Provider() ]; } - public function testRemoveProperties() + public function testRemoveProperties(): void { $graph = new ExtendedGraph(); @@ -226,7 +239,7 @@ public function testRemoveProperties() $this->assertFalse($graph->subject_has_property('http://some/subject/3', 'http://some/predicate/to/remove'), 'should have removed triple about subject 3'); } - public function testGetFirstResource() + public function testGetFirstResource(): void { $graph = new ExtendedGraph(); @@ -238,7 +251,7 @@ public function testGetFirstResource() $this->assertEquals('my default', $graph->get_first_resource('http://some/subject/3', 'http://other/predicate', 'my default'), 'should have returned default value'); } - public function testRemoveResourceTriple() + public function testRemoveResourceTriple(): void { $graph = new ExtendedGraph(); @@ -263,7 +276,7 @@ public function testRemoveResourceTriple() $this->assertEquals([], $graph->get_index(), 'should have empty index'); } - public function testRemoveLiteralTriple() + public function testRemoveLiteralTriple(): void { $graph = new ExtendedGraph(); @@ -288,7 +301,7 @@ public function testRemoveLiteralTriple() $this->assertEquals([], $graph->get_index(), 'should have empty index'); } - public function testGetResourceProperties() + public function testGetResourceProperties(): void { $graph = new ExtendedGraph(); @@ -301,7 +314,7 @@ public function testGetResourceProperties() $this->assertEquals($values, ['http://value/1', 'http://value/2', 'http://value/3'], 'should have returned 3 values'); } - public function testGetSubjectsWithPropertyValue() + public function testGetSubjectsWithPropertyValue(): void { $graph = new ExtendedGraph(); @@ -316,7 +329,7 @@ public function testGetSubjectsWithPropertyValue() $this->assertEquals($subjects, ['http://some/subject/2', 'http://some/subject/2-with-literal'], 'should have returned correct subject'); } - public function testGetSequenceValues() + public function testGetSequenceValues(): void { $graph = new ExtendedGraph(); $graph->add_resource_triple('http://some/subject/1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_4', 'http://value/4'); @@ -329,7 +342,7 @@ public function testGetSequenceValues() $this->assertEquals($expectedArray, $graph->get_sequence_values('http://some/subject/1')); } - public function testAddResourceToSequence() + public function testAddResourceToSequence(): void { $testSubject = 'http://some/subject/s1'; $testObject1 = 'http://some/object/o1'; @@ -355,7 +368,7 @@ public function testAddResourceToSequence() $this->assertEquals(['http://some/other/object'], $objects); } - public function testAddResourceToSequenceInPosition() + public function testAddResourceToSequenceInPosition(): void { $testSubject = 'http://some/subject/s1'; $testObject1 = 'http://some/object/o1'; @@ -391,7 +404,7 @@ public function testAddResourceToSequenceInPosition() $this->assertEquals([$testObject3, $testObject2, $testObject4, $testObject1, $testObject5], $objects); } - public function testAddToSequenceInPositionAgain() + public function testAddToSequenceInPositionAgain(): void { $graph = new ExtendedGraph(); $graph->add_resource_to_sequence('http://seq', 'http://item/1'); @@ -408,7 +421,7 @@ public function testAddToSequenceInPositionAgain() $this->assertTrue($graph->has_resource_triple('http://seq', ExtendedGraph::rdf . '_5', 'http://item/4')); } - public function testAddLiteralToSequence() + public function testAddLiteralToSequence(): void { $testSubject = 'http://some/subject/s1'; $testObject1 = 'foo1'; @@ -434,55 +447,59 @@ public function testAddLiteralToSequence() $this->assertEquals(['bar'], $objects); } - public function testGetTripleCountWithNoParams() + public function testGetTripleCountWithNoParams(): void { $graph = new ExtendedGraph(); $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/2', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/3', 'http://some/predicate', 'some object'); + $expected = 3; $actual = $graph->get_triple_count(); $this->assertEquals($expected, $actual); } - public function testGetTripleCountWithSubject() + public function testGetTripleCountWithSubject(): void { $graph = new ExtendedGraph(); $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/2', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/3', 'http://some/predicate', 'some object'); + $expected = 1; $actual = $graph->get_triple_count('http://some/subject/1'); $this->assertEquals($expected, $actual); } - public function testGetTripleCountWithPredicate() + public function testGetTripleCountWithPredicate(): void { $graph = new ExtendedGraph(); $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/2', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/3', 'http://some/predicate', 'some object'); + $expected = 3; $actual = $graph->get_triple_count(false, 'http://some/predicate'); $this->assertEquals($expected, $actual); } - public function testGetTripleCountWithObject() + public function testGetTripleCountWithObject(): void { $graph = new ExtendedGraph(); $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/2', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/3', 'http://some/predicate', 'some object'); + $expected = 3; $actual = $graph->get_triple_count(false, false, 'some object'); $this->assertEquals($expected, $actual); } - public function testGetTripleCountWithSubjectandPredicate() + public function testGetTripleCountWithSubjectandPredicate(): void { $graph = new ExtendedGraph(); @@ -490,12 +507,13 @@ public function testGetTripleCountWithSubjectandPredicate() $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', 'another object'); $graph->add_literal_triple('http://some/subject/2', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/3', 'http://some/predicate', 'some object'); + $expected = 2; $actual = $graph->get_triple_count('http://some/subject/1', 'http://some/predicate'); $this->assertEquals($expected, $actual); } - public function testGetTripleCountWithSubjectPredicateAndObject() + public function testGetTripleCountWithSubjectPredicateAndObject(): void { $graph = new ExtendedGraph(); @@ -503,12 +521,13 @@ public function testGetTripleCountWithSubjectPredicateAndObject() $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', 'another object'); $graph->add_literal_triple('http://some/subject/2', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/3', 'http://some/predicate', 'some object'); + $expected = 1; $actual = $graph->get_triple_count('http://some/subject/1', 'http://some/predicate', 'some object'); $this->assertEquals($expected, $actual); } - public function testGetTripleCountWithEmptyGraph() + public function testGetTripleCountWithEmptyGraph(): void { $graph = new ExtendedGraph(); $expected = 0; @@ -516,7 +535,7 @@ public function testGetTripleCountWithEmptyGraph() $this->assertEquals($expected, $actual); } - public function testGetTripleCountWithNonExistentSubject() + public function testGetTripleCountWithNonExistentSubject(): void { $graph = new ExtendedGraph(); $expected = 0; @@ -524,13 +543,14 @@ public function testGetTripleCountWithNonExistentSubject() $this->assertEquals($expected, $actual); } - public function testReplaceUris() + public function testReplaceUris(): void { $graph = new ExtendedGraph(); $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', 'some object'); $graph->add_literal_triple('http://some/subject/4', 'http://some/predicate', 'http://some/subject/1'); $graph->add_resource_triple('http://some/subject/2', 'http://some/predicate', 'http://some/subject/1'); $graph->replace_uris('http://some/subject/1', 'http://some/subject/3'); + $index = $graph->get_index(); $this->assertFalse($graph->has_triples_about('http://some/subject/1'), 'resource with old uri still exists'); $this->assertTrue($graph->has_triples_about('http://some/subject/3'), "resource with new uri doesn't exists"); @@ -539,21 +559,22 @@ public function testReplaceUris() $graph->replace_uris('http://some/predicate', 'http://some/predicate2'); $index = $graph->get_index(); - $this->assertTrue(isset($index['http://some/subject/2']['http://some/predicate2']), 'predicate should be replaced'); - $this->assertFalse(isset($index['http://some/subject/2']['http://some/predicate']), 'predicate should be replaced and old one not be in graph'); + $this->assertArrayHasKey('http://some/predicate2', $index['http://some/subject/2'], 'predicate should be replaced'); + $this->assertArrayNotHasKey('http://some/predicate', $index['http://some/subject/2'], 'predicate should be replaced and old one not be in graph'); } - public function testReplaceResourceTriples() + public function testReplaceResourceTriples(): void { $graph = new ExtendedGraph(); $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', 'some object'); $graph->add_resource_triple('http://some/subject/2', 'http://some/predicate', 'http://some/subject/1'); $graph->replace_resource_triples('http://some/subject/2', 'http://some/predicate', 'http://some/subject/3'); + $index = $graph->get_index(); $this->assertEquals('http://some/subject/3', $index['http://some/subject/2']['http://some/predicate'][0]['value'], 'http://some/subject/3'); } - public function testReplaceLiteralTriple() + public function testReplaceLiteralTriple(): void { $graph = new ExtendedGraph(); $graph->add_literal_triple('http://some/subject/s1', 'http://some/predicate', 'some object'); @@ -562,14 +583,14 @@ public function testReplaceLiteralTriple() $this->assertEquals('replacement object', $index['http://some/subject/s1']['http://some/predicate'][0]['value'], "should be 'replacement object'"); } - public function testReplaceLiteralTripleReturnsFalseIfNoReplacementMade() + public function testReplaceLiteralTripleReturnsFalseIfNoReplacementMade(): void { $graph = new ExtendedGraph(); $graph->add_literal_triple('http://some/subject/s1', 'http://some/predicate', 'some object'); $this->assertFalse($graph->replace_literal_triple('http://some/othersubject/s1', 'http://some/predicate', 'some object', 'replacement object'), 'Should return FALSE'); } - public function testGetResources() + public function testGetResources(): void { $graph = new ExtendedGraph(); @@ -585,11 +606,11 @@ public function testGetResources() sort($expected); sort($actual); - $this->assertEquals(count($expected), count($actual), 'should get same number of resource uris'); + $this->assertCount(count($expected), $actual, 'should get same number of resource uris'); $this->assertEquals($expected, $actual, 'should get expected array containing all the resource uris'); } - public function testGetLabelForUri() + public function testGetLabelForUri(): void { $graph = new ExtendedGraph(); @@ -605,7 +626,7 @@ public function testGetLabelForUri() $this->assertEquals($graph->get_label_for_uri($s1), $label, 'get_label_for_uri(uri) should return the value of a label property'); } - public function testGetLabelForUriLabelPropsNotInitialised() + public function testGetLabelForUriLabelPropsNotInitialised(): void { ExtendedGraph::initProperties(['labelProperties' => null]); $this->expectException(Exception::class); @@ -622,7 +643,7 @@ public function testGetLabelForUriLabelPropsNotInitialised() $graph->get_label_for_uri($s1); } - public function testGetLabelForUriReturnsEmptyStringIfSubjectNotFound() + public function testGetLabelForUriReturnsEmptyStringIfSubjectNotFound(): void { $graph = new ExtendedGraph(); @@ -635,10 +656,10 @@ public function testGetLabelForUriReturnsEmptyStringIfSubjectNotFound() ExtendedGraph::initProperties(['labelProperties' => ['http://www.w3.org/2000/01/rdf-schema#label']]); - $this->assertEquals($graph->get_label_for_uri('http://example.com/1'), ''); + $this->assertEquals('', $graph->get_label_for_uri('http://example.com/1')); } - public function testGetLabelForUriReturnsEmptyStringLabelNotFound() + public function testGetLabelForUriReturnsEmptyStringLabelNotFound(): void { $graph = new ExtendedGraph(); @@ -651,10 +672,10 @@ public function testGetLabelForUriReturnsEmptyStringLabelNotFound() ExtendedGraph::initProperties(['labelProperties' => ['http://www.w3.org/2000/01/rdf-schema#label2']]); - $this->assertEquals($graph->get_label_for_uri($s1), ''); + $this->assertEquals('', $graph->get_label_for_uri($s1)); } - public function testIsEqualToReturnsTrueForIdenticalGraphs() + public function testIsEqualToReturnsTrueForIdenticalGraphs(): void { $s = 'http://example.com/people/bloggs-joe'; $rdfType = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; @@ -669,7 +690,7 @@ public function testIsEqualToReturnsTrueForIdenticalGraphs() $this->assertTrue($graph2->is_equal_to($graph1), 'graph2 should equal graph1'); } - public function testIsEqualToReturnsFalseForDifferingGraphs() + public function testIsEqualToReturnsFalseForDifferingGraphs(): void { $rdfType = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; @@ -708,7 +729,7 @@ public function testIsEqualToReturnsFalseForDifferingGraphs() $this->assertFalse($graph5->is_equal_to($graph2), 'graph5 should not equal graph2'); } - public function testIsEqualToIgnoresNamespaceDifferences() + public function testIsEqualToIgnoresNamespaceDifferences(): void { $s = 'http://example.com/people/bloggs-joe'; $rdfType = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; @@ -731,7 +752,7 @@ public function testIsEqualToIgnoresNamespaceDifferences() $this->assertTrue($graph3->is_equal_to($graph2), 'graph3 should equal graph2'); } - public function testRemoveResourceFromSequence() + public function testRemoveResourceFromSequence(): void { $graph = new ExtendedGraph(); @@ -752,11 +773,10 @@ public function testRemoveResourceFromSequence() $this->assertTrue($graph->has_resource_triple($s, ExtendedGraph::rdf . '_2', $sub3)); } - public function testFromGraph() + public function testFromGraph(): void { $itemUri = 'http://foo/item'; $mainResourceUri = 'http://foo/mainResource'; - $partOfResourceUri = 'http://foo/partOfResource'; $itemGraph = new ExtendedGraph(); @@ -769,7 +789,7 @@ public function testFromGraph() $this->assertTrue($graph->is_equal_to($itemGraph)); } - public function testRemoveSubjectsOfType() + public function testRemoveSubjectsOfType(): void { $graph = new ExtendedGraph(); $graph->add_resource_triple('http://test/1', ExtendedGraph::rdf . 'type', self::ONT_resource . 'Item'); @@ -779,11 +799,11 @@ public function testRemoveSubjectsOfType() $graph->remove_subjects_of_type(self::ONT_resource . 'Item'); $subjects = $graph->get_subjects(); - $this->assertEquals(1, count($subjects)); + $this->assertCount(1, $subjects); $this->assertEquals('http://test/3', $subjects[0]); } - public function testReplaceLiteralTriples() + public function testReplaceLiteralTriples(): void { $graph = new ExtendedGraph(); $graph->add_literal_triple('http://test/1', 'http://www.w3.org/2000/01/rdf-schema#label', 'value1'); @@ -795,7 +815,7 @@ public function testReplaceLiteralTriples() $this->assertFalse($graph->has_literal_triple('http://test/1', 'http://www.w3.org/2000/01/rdf-schema#label', 'value2')); } - public function testFromJson() + public function testFromJson(): void { $graph = new ExtendedGraph(); $graph->from_json('{ @@ -816,12 +836,12 @@ public function testFromJson() } }'); - $this->assertEquals(3, count($graph->get_subjects())); + $this->assertCount(3, $graph->get_subjects()); $this->assertEquals(['http://subject/1', 'http://subject/2', 'http://subject/3'], $graph->get_subjects()); $this->assertEquals(['http://value/1', 'http://value/2', 'http://value/3'], $graph->get_resource_properties('http://predicate')); } - public function testFromInvalidJson() + public function testFromInvalidJson(): void { $graph = new ExtendedGraph(); $index = $graph->get_index(); @@ -832,7 +852,7 @@ public function testFromInvalidJson() $this->assertEquals($index, $graph->get_index()); } - public function testAddJson() + public function testAddJson(): void { $graph = new ExtendedGraph(); $graph->add_json('{ @@ -843,7 +863,7 @@ public function testAddJson() } }'); - $this->assertEquals(1, count($graph->get_subjects())); + $this->assertCount(1, $graph->get_subjects()); $this->assertEquals(['http://subject/1'], $graph->get_subjects()); $this->assertEquals(['http://value/1'], $graph->get_resource_properties('http://predicate')); @@ -855,12 +875,12 @@ public function testAddJson() } }'); - $this->assertEquals(2, count($graph->get_subjects())); + $this->assertCount(2, $graph->get_subjects()); $this->assertEquals(['http://subject/1', 'http://subject/2'], $graph->get_subjects()); $this->assertEquals(['http://value/1', 'http://value/2'], $graph->get_resource_properties('http://predicate')); } - public function testAddInvalidJson() + public function testAddInvalidJson(): void { $graph = new ExtendedGraph(); $graph->add_json('{ @@ -872,7 +892,7 @@ public function testAddInvalidJson() }'); $this->assertEquals(1, $graph->get_triple_count()); - $this->assertEquals(1, count($graph->get_subjects())); + $this->assertCount(1, $graph->get_subjects()); $this->assertEquals(['http://subject/1'], $graph->get_subjects()); $this->assertEquals(['http://value/1'], $graph->get_resource_properties('http://predicate')); $index = $graph->get_index(); diff --git a/test/unit/TimerTest.php b/test/unit/TimerTest.php index 3944986c..04b299fb 100644 --- a/test/unit/TimerTest.php +++ b/test/unit/TimerTest.php @@ -1,5 +1,7 @@ expectException(Exception::class); @@ -19,7 +21,7 @@ public function testResultWhenStartTimeNotSet() $timer->result(); } - public function testResultWhenEndTimeNotSet() + public function testResultWhenEndTimeNotSet(): void { $timer = new Timer(); $timer->start(); @@ -28,19 +30,20 @@ public function testResultWhenEndTimeNotSet() $timer->result(); } - public function testResultGetTimeInMilliSeconds() + public function testResultGetTimeInMilliSeconds(): void { $timer = new Timer(); $timer->start(); sleep(1); // Let's pause for one seconds otherwise we will get 0 as a result. $timer->stop(); - $status = ($timer->result() >= 1000) ? true : false; + $status = $timer->result() >= 1000; $this->assertTrue($status); } + /** END: result() tests */ /** START: microResult() tests */ - public function testMicroResultWhenStartTimeNotSet() + public function testMicroResultWhenStartTimeNotSet(): void { $timer = new Timer(); $this->expectException(Exception::class); @@ -48,7 +51,7 @@ public function testMicroResultWhenStartTimeNotSet() $timer->result(); } - public function testMicroResultWhenEndTimeNotSet() + public function testMicroResultWhenEndTimeNotSet(): void { $timer = new Timer(); $timer->start(); @@ -57,14 +60,15 @@ public function testMicroResultWhenEndTimeNotSet() $timer->result(); } - public function testMicroResultGetTimeInMilliSeconds() + public function testMicroResultGetTimeInMilliSeconds(): void { $timer = new Timer(); $timer->start(); sleep(1); // Let's pause for one seconds otherwise we might get 0 as a result. $timer->stop(); - $status = ($timer->microResult() >= 1000000) ? true : false; + $status = $timer->microResult() >= 1000000; $this->assertTrue($status); } + // END: microResult() tests } diff --git a/test/unit/mongo/ApplyOperationTest.php b/test/unit/mongo/ApplyOperationTest.php index dbc43e59..f5b6e16e 100644 --- a/test/unit/mongo/ApplyOperationTest.php +++ b/test/unit/mongo/ApplyOperationTest.php @@ -1,5 +1,7 @@ setArgs(); unset($this->args['tripodConfig']); @@ -29,7 +31,7 @@ public function testMandatoryArgTripodConfig() $this->performJob($job); } - public function testMandatoryArgSubject() + public function testMandatoryArgSubject(): void { $this->setArgs(); unset($this->args['subjects']); @@ -41,7 +43,7 @@ public function testMandatoryArgSubject() $this->performJob($job); } - public function testApplyViewOperation() + public function testApplyViewOperation(): void { $this->setArgs(); $applyOperation = $this->getMockBuilder(ApplyOperation::class) @@ -87,11 +89,11 @@ public function testApplyViewOperation() $applyOperation->expects($this->once()) ->method('createImpactedSubject') - ->will($this->returnValue($subject)); + ->willReturn($subject); $applyOperation->expects($this->exactly(3)) ->method('getStat') - ->will($this->returnValue($statMock)); + ->willReturn($statMock); $statMock->expects($this->once()) ->method('increment') @@ -105,12 +107,12 @@ public function testApplyViewOperation() $subject->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $tripod->expects($this->once()) ->method('getComposite') ->with(OP_VIEWS) - ->will($this->returnValue($views)); + ->willReturn($views); $views->expects($this->once()) ->method('update') @@ -119,7 +121,7 @@ public function testApplyViewOperation() $this->performJob($applyOperation); } - public function testApplyViewOperationDecrementsJobGroupForBatchOperations() + public function testApplyViewOperationDecrementsJobGroupForBatchOperations(): void { $this->setArgs(); $applyOperation = $this->getMockBuilder(ApplyOperation::class) @@ -128,6 +130,7 @@ public function testApplyViewOperationDecrementsJobGroupForBatchOperations() $applyOperation->args = $this->args; $applyOperation->job = new Resque_Job('queue', ['id' => uniqid()]); + $jobTrackerId = new ObjectId(); $applyOperation->args[ApplyOperation::TRACKING_KEY] = $jobTrackerId->__toString(); @@ -139,7 +142,7 @@ public function testApplyViewOperationDecrementsJobGroupForBatchOperations() $jobGroup->expects($this->once()) ->method('incrementJobCount') ->with(-1) - ->will($this->returnValue(2)); + ->willReturn(2); $statMock = $this->getMockStat( $this->args['statsConfig']['config']['host'], @@ -179,16 +182,16 @@ public function testApplyViewOperationDecrementsJobGroupForBatchOperations() $applyOperation->expects($this->once()) ->method('createImpactedSubject') - ->will($this->returnValue($subject)); + ->willReturn($subject); $applyOperation->expects($this->exactly(3)) ->method('getStat') - ->will($this->returnValue($statMock)); + ->willReturn($statMock); $applyOperation->expects($this->once()) ->method('getJobGroup') ->with('tripod_php_testing', $jobTrackerId->__toString()) - ->will($this->returnValue($jobGroup)); + ->willReturn($jobGroup); $applyOperation->expects($this->never()) ->method('getTripod'); @@ -205,12 +208,12 @@ public function testApplyViewOperationDecrementsJobGroupForBatchOperations() $subject->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $tripod->expects($this->once()) ->method('getComposite') ->with(OP_VIEWS) - ->will($this->returnValue($views)); + ->willReturn($views); $views->expects($this->once()) ->method('update') @@ -220,7 +223,7 @@ public function testApplyViewOperationDecrementsJobGroupForBatchOperations() $this->performJob($applyOperation); } - public function testApplyViewOperationCleanupIfAllGroupJobsComplete() + public function testApplyViewOperationCleanupIfAllGroupJobsComplete(): void { $this->setArgs(OP_VIEWS, ['v_foo_bar']); $applyOperation = $this->getMockBuilder(ApplyOperation::class) @@ -229,6 +232,7 @@ public function testApplyViewOperationCleanupIfAllGroupJobsComplete() $applyOperation->args = $this->args; $applyOperation->job = new Resque_Job('queue', ['id' => uniqid()]); + $jobTrackerId = new ObjectId(); $applyOperation->args[ApplyOperation::TRACKING_KEY] = $jobTrackerId->__toString(); $timestamp = new UTCDateTime(hexdec(substr($jobTrackerId, 0, 8)) * 1000); @@ -241,7 +245,7 @@ public function testApplyViewOperationCleanupIfAllGroupJobsComplete() $jobGroup->expects($this->once()) ->method('incrementJobCount') ->with(-1) - ->will($this->returnValue(0)); + ->willReturn(0); $statMock = $this->getMockStat( $this->args['statsConfig']['config']['host'], @@ -281,21 +285,21 @@ public function testApplyViewOperationCleanupIfAllGroupJobsComplete() $applyOperation->expects($this->once()) ->method('createImpactedSubject') - ->will($this->returnValue($subject)); + ->willReturn($subject); $applyOperation->expects($this->exactly(3)) ->method('getStat') - ->will($this->returnValue($statMock)); + ->willReturn($statMock); $applyOperation->expects($this->once()) ->method('getJobGroup') ->with('tripod_php_testing', $jobTrackerId->__toString()) - ->will($this->returnValue($jobGroup)); + ->willReturn($jobGroup); $applyOperation->expects($this->once()) ->method('getTripod') ->with('tripod_php_testing', 'CBD_testing') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $statMock->expects($this->once()) ->method('increment') @@ -309,11 +313,11 @@ public function testApplyViewOperationCleanupIfAllGroupJobsComplete() $subject->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $tripod->expects($this->exactly(2)) ->method('getTripodViews') - ->will($this->returnValue($views)); + ->willReturn($views); $views->expects($this->once()) ->method('update') @@ -322,12 +326,12 @@ public function testApplyViewOperationCleanupIfAllGroupJobsComplete() $views->expects($this->once()) ->method('deleteViewsByViewId') ->with('v_foo_bar', $timestamp) - ->will($this->returnValue(3)); + ->willReturn(3); $this->performJob($applyOperation); } - public function testApplyTableOperation() + public function testApplyTableOperation(): void { $this->setArgs(); $applyOperation = $this->getMockBuilder(ApplyOperation::class) @@ -385,11 +389,11 @@ public function testApplyTableOperation() $applyOperation->expects($this->once()) ->method('createImpactedSubject') - ->will($this->returnValue($subject)); + ->willReturn($subject); $applyOperation->expects($this->exactly(3)) ->method('getStat') - ->will($this->returnValue($statMock)); + ->willReturn($statMock); $statMock->expects($this->once()) ->method('increment') @@ -403,12 +407,12 @@ public function testApplyTableOperation() $subject->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $tripod->expects($this->once()) ->method('getComposite') ->with(OP_TABLES) - ->will($this->returnValue($tables)); + ->willReturn($tables); $tables->expects($this->once()) ->method('update') @@ -417,7 +421,7 @@ public function testApplyTableOperation() $this->performJob($applyOperation); } - public function testApplyTableOperationDecrementsJobGroupForBatchOperations() + public function testApplyTableOperationDecrementsJobGroupForBatchOperations(): void { $this->setArgs(OP_TABLES, ['t_resource']); $applyOperation = $this->getMockBuilder(ApplyOperation::class) @@ -445,7 +449,7 @@ public function testApplyTableOperationDecrementsJobGroupForBatchOperations() $jobGroup->expects($this->once()) ->method('incrementJobCount') ->with(-1) - ->will($this->returnValue(2)); + ->willReturn(2); $subject = $this->getMockBuilder(ImpactedSubject::class) ->onlyMethods(['getTripod']) @@ -478,16 +482,16 @@ public function testApplyTableOperationDecrementsJobGroupForBatchOperations() $applyOperation->expects($this->once()) ->method('createImpactedSubject') - ->will($this->returnValue($subject)); + ->willReturn($subject); $applyOperation->expects($this->exactly(3)) ->method('getStat') - ->will($this->returnValue($statMock)); + ->willReturn($statMock); $applyOperation->expects($this->once()) ->method('getJobGroup') ->with('tripod_php_testing', $jobTrackerId->__toString()) - ->will($this->returnValue($jobGroup)); + ->willReturn($jobGroup); $applyOperation->expects($this->never()) ->method('getTripod'); @@ -504,12 +508,12 @@ public function testApplyTableOperationDecrementsJobGroupForBatchOperations() $subject->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $tripod->expects($this->once()) ->method('getComposite') ->with(OP_TABLES) - ->will($this->returnValue($tables)); + ->willReturn($tables); $tables->expects($this->once()) ->method('update') @@ -520,7 +524,7 @@ public function testApplyTableOperationDecrementsJobGroupForBatchOperations() $this->performJob($applyOperation); } - public function testApplyTableOperationCleanupIfAllGroupJobsComplete() + public function testApplyTableOperationCleanupIfAllGroupJobsComplete(): void { $this->setArgs(OP_TABLES, ['t_resource']); $applyOperation = $this->getMockBuilder(ApplyOperation::class) @@ -549,7 +553,7 @@ public function testApplyTableOperationCleanupIfAllGroupJobsComplete() $jobGroup->expects($this->once()) ->method('incrementJobCount') ->with(-1) - ->will($this->returnValue(0)); + ->willReturn(0); $subject = $this->getMockBuilder(ImpactedSubject::class) ->onlyMethods(['getTripod']) @@ -582,21 +586,21 @@ public function testApplyTableOperationCleanupIfAllGroupJobsComplete() $applyOperation->expects($this->once()) ->method('createImpactedSubject') - ->will($this->returnValue($subject)); + ->willReturn($subject); $applyOperation->expects($this->exactly(3)) ->method('getStat') - ->will($this->returnValue($statMock)); + ->willReturn($statMock); $applyOperation->expects($this->once()) ->method('getJobGroup') ->with('tripod_php_testing', $jobTrackerId->__toString()) - ->will($this->returnValue($jobGroup)); + ->willReturn($jobGroup); $applyOperation->expects($this->once()) ->method('getTripod') ->with('tripod_php_testing', 'CBD_testing') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $statMock->expects($this->once()) ->method('increment') @@ -610,11 +614,11 @@ public function testApplyTableOperationCleanupIfAllGroupJobsComplete() $subject->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $tripod->expects($this->exactly(2)) ->method('getTripodTables') - ->will($this->returnValue($tables)); + ->willReturn($tables); $tables->expects($this->once()) ->method('update') @@ -622,12 +626,12 @@ public function testApplyTableOperationCleanupIfAllGroupJobsComplete() $tables->expects($this->once()) ->method('deleteTableRowsByTableId') ->with('t_resource', $timestamp) - ->will($this->returnValue(4)); + ->willReturn(4); $this->performJob($applyOperation); } - public function testApplySearchOperation() + public function testApplySearchOperation(): void { $this->setArgs(OP_SEARCH, ['i_search_resource']); $applyOperation = $this->getMockBuilder(ApplyOperation::class) @@ -670,11 +674,11 @@ public function testApplySearchOperation() $applyOperation->expects($this->once()) ->method('createImpactedSubject') - ->will($this->returnValue($subject)); + ->willReturn($subject); $applyOperation->expects($this->exactly(3)) ->method('getStat') - ->will($this->returnValue($statMock)); + ->willReturn($statMock); $statMock->expects($this->once()) ->method('increment') @@ -688,12 +692,12 @@ public function testApplySearchOperation() $subject->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $tripod->expects($this->once()) ->method('getComposite') ->with(OP_SEARCH) - ->will($this->returnValue($search)); + ->willReturn($search); $search->expects($this->once()) ->method('update') @@ -702,7 +706,7 @@ public function testApplySearchOperation() $this->performJob($applyOperation); } - public function testApplySearchOperationDecrementsJobGroupForBatchOperations() + public function testApplySearchOperationDecrementsJobGroupForBatchOperations(): void { $this->setArgs(OP_SEARCH, ['i_search_resource']); $applyOperation = $this->getMockBuilder(ApplyOperation::class) @@ -730,7 +734,7 @@ public function testApplySearchOperationDecrementsJobGroupForBatchOperations() $jobGroup->expects($this->once()) ->method('incrementJobCount') ->with(-1) - ->will($this->returnValue(2)); + ->willReturn(2); $subject = $this->getMockBuilder(ImpactedSubject::class) ->onlyMethods(['getTripod']) @@ -758,16 +762,16 @@ public function testApplySearchOperationDecrementsJobGroupForBatchOperations() $applyOperation->expects($this->once()) ->method('createImpactedSubject') - ->will($this->returnValue($subject)); + ->willReturn($subject); $applyOperation->expects($this->exactly(3)) ->method('getStat') - ->will($this->returnValue($statMock)); + ->willReturn($statMock); $applyOperation->expects($this->once()) ->method('getJobGroup') ->with('tripod_php_testing', $jobTrackerId->__toString()) - ->will($this->returnValue($jobGroup)); + ->willReturn($jobGroup); $applyOperation->expects($this->never()) ->method('getTripod'); @@ -784,12 +788,12 @@ public function testApplySearchOperationDecrementsJobGroupForBatchOperations() $subject->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $tripod->expects($this->once()) ->method('getComposite') ->with(OP_SEARCH) - ->will($this->returnValue($search)); + ->willReturn($search); $search->expects($this->once()) ->method('update') @@ -798,7 +802,7 @@ public function testApplySearchOperationDecrementsJobGroupForBatchOperations() $this->performJob($applyOperation); } - public function testApplySearchOperationCleanupIfAllGroupJobsComplete() + public function testApplySearchOperationCleanupIfAllGroupJobsComplete(): void { $this->setArgs(OP_SEARCH, ['i_search_resource']); $applyOperation = $this->getMockBuilder(ApplyOperation::class) @@ -827,7 +831,7 @@ public function testApplySearchOperationCleanupIfAllGroupJobsComplete() $jobGroup->expects($this->once()) ->method('incrementJobCount') ->with(-1) - ->will($this->returnValue(0)); + ->willReturn(0); $subject = $this->getMockBuilder(ImpactedSubject::class) ->onlyMethods(['getTripod']) @@ -860,26 +864,26 @@ public function testApplySearchOperationCleanupIfAllGroupJobsComplete() $applyOperation->expects($this->once()) ->method('createImpactedSubject') - ->will($this->returnValue($subject)); + ->willReturn($subject); $applyOperation->expects($this->exactly(3)) ->method('getStat') - ->will($this->returnValue($statMock)); + ->willReturn($statMock); $applyOperation->expects($this->once()) ->method('getJobGroup') ->with('tripod_php_testing', $jobTrackerId->__toString()) - ->will($this->returnValue($jobGroup)); + ->willReturn($jobGroup); $applyOperation->expects($this->once()) ->method('getTripod') ->with('tripod_php_testing', 'CBD_testing') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $applyOperation->expects($this->once()) ->method('getSearchProvider') ->with($tripod) - ->will($this->returnValue($searchProvider)); + ->willReturn($searchProvider); $statMock->expects($this->once()) ->method('increment') @@ -894,12 +898,12 @@ public function testApplySearchOperationCleanupIfAllGroupJobsComplete() $subject->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $tripod->expects($this->once()) ->method('getComposite') ->with(OP_SEARCH) - ->will($this->returnValue($search)); + ->willReturn($search); $search->expects($this->once()) ->method('update') @@ -908,12 +912,12 @@ public function testApplySearchOperationCleanupIfAllGroupJobsComplete() $searchProvider->expects($this->once()) ->method('deleteSearchDocumentsByTypeId') ->with('i_search_resource', $timestamp) - ->will($this->returnValue(8)); + ->willReturn(8); $this->performJob($applyOperation); } - public function testCreateJobDefaultQueue() + public function testCreateJobDefaultQueue(): void { $impactedSubject = new ImpactedSubject( [_ID_RESOURCE => 'http://example.com/1', _ID_CONTEXT => 'http://talisaspire.com/'], @@ -944,7 +948,7 @@ public function testCreateJobDefaultQueue() $applyOperation->createJob([$impactedSubject]); } - public function testCreateJobUnreachableRedis() + public function testCreateJobUnreachableRedis(): void { $impactedSubject = new ImpactedSubject( [_ID_RESOURCE => 'http://example.com/1', _ID_CONTEXT => 'http://talisaspire.com/'], @@ -959,7 +963,7 @@ public function testCreateJobUnreachableRedis() ->getMock(); $e = new Exception('Connection to Redis failed after 1 failures.Last Error : (0) php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known'); - $applyOperation->expects($this->any())->method('enqueue')->will($this->throwException($e)); + $applyOperation->method('enqueue')->willThrowException($e); // expect 5 retries. Catch this with call to warning log $applyOperation->expects($this->exactly(5))->method('warningLog'); @@ -969,15 +973,16 @@ public function testCreateJobUnreachableRedis() try { $applyOperation->createJob([$impactedSubject]); } catch (JobException $e) { - $this->assertEquals('Exception queuing job - Connection to Redis failed after 1 failures.Last Error : (0) php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known', $e->getMessage()); + $this->assertSame('Exception queuing job - Connection to Redis failed after 1 failures.Last Error : (0) php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known', $e->getMessage()); $exceptionThrown = true; } + if (!$exceptionThrown) { $this->fail('Did not throw JobException'); } } - public function testCreateJobStatusFalse() + public function testCreateJobStatusFalse(): void { $impactedSubject = new ImpactedSubject( [_ID_RESOURCE => 'http://example.com/1', _ID_CONTEXT => 'http://talisaspire.com/'], @@ -991,8 +996,8 @@ public function testCreateJobStatusFalse() ->onlyMethods(['enqueue', 'getJobStatus', 'warningLog']) ->getMock(); - $applyOperation->expects($this->any())->method('enqueue')->will($this->returnValue('sometoken')); - $applyOperation->expects($this->any())->method('getJobStatus')->will($this->returnValue(false)); + $applyOperation->method('enqueue')->willReturn('sometoken'); + $applyOperation->method('getJobStatus')->willReturn(false); // expect 5 retries. Catch this with call to warning log $applyOperation->expects($this->exactly(5))->method('warningLog'); @@ -1002,15 +1007,16 @@ public function testCreateJobStatusFalse() try { $applyOperation->createJob([$impactedSubject]); } catch (JobException $e) { - $this->assertEquals('Exception queuing job - Could not retrieve status for queued job - job sometoken failed to tripod::apply', $e->getMessage()); + $this->assertSame('Exception queuing job - Could not retrieve status for queued job - job sometoken failed to tripod::apply', $e->getMessage()); $exceptionThrown = true; } + if (!$exceptionThrown) { $this->fail('Did not throw JobException'); } } - public function testCreateJobSpecifyQueue() + public function testCreateJobSpecifyQueue(): void { $impactedSubject = new ImpactedSubject( [_ID_RESOURCE => 'http://example.com/1', _ID_CONTEXT => 'http://talisaspire.com/'], @@ -1047,6 +1053,7 @@ public function testCreateJobSpecifyQueue() * Sets job arguments. * * @param mixed $operation + * @param string[] $specTypes */ protected function setArgs($operation = OP_VIEWS, array $specTypes = []) { diff --git a/test/unit/mongo/ConfigGeneratorTest.php b/test/unit/mongo/ConfigGeneratorTest.php index e24d3282..2c50cbcd 100644 --- a/test/unit/mongo/ConfigGeneratorTest.php +++ b/test/unit/mongo/ConfigGeneratorTest.php @@ -1,5 +1,7 @@ config); } - public function testCreateFromConfig() + public function testCreateFromConfig(): void { /** @var TestConfigGenerator $instance */ $instance = Config::getInstance(); @@ -37,20 +39,21 @@ public function testCreateFromConfig() ); } - public function testSerializeConfig() + public function testSerializeConfig(): void { /** @var TestConfigGenerator $instance */ $instance = Config::getInstance(); $this->assertEquals($this->config, $instance->serialize()); } - public function testConfigGeneratorsSerializedInDiscoverJobs() + public function testConfigGeneratorsSerializedInDiscoverJobs(): void { $originalGraph = new ExtendedGraph(); $originalGraph->add_resource_triple('http://example.com/1', RDF_TYPE, RDFS_CLASS); $newGraph = new ExtendedGraph(); $newGraph->add_resource_triple('http://example.com/1', RDF_TYPE, OWL_CLASS); + $subjectsAndPredicatesOfChange = ['http://example.com/1' => [RDF_TYPE]]; $tripod = $this->getMockBuilder(Driver::class) @@ -78,13 +81,11 @@ public function testConfigGeneratorsSerializedInDiscoverJobs() ->onlyMethods(['createJob']) ->getMock(); - $tripod->expects($this->once())->method('getDataUpdater')->will($this->returnValue($updates)); - $updates->expects($this->once())->method('getDiscoverImpactedSubjects')->will($this->returnValue($discoverJob)); + $tripod->expects($this->once())->method('getDataUpdater')->willReturn($updates); + $updates->expects($this->once())->method('getDiscoverImpactedSubjects')->willReturn($discoverJob); - $updates->expects($this->once())->method('storeChanges')->will( - $this->returnValue( - ['transaction_id' => uniqid(), 'subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange] - ) + $updates->expects($this->once())->method('storeChanges')->willReturn( + ['transaction_id' => uniqid(), 'subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange] ); $discoverJob->expects($this->once())->method('createJob') @@ -103,7 +104,7 @@ public function testConfigGeneratorsSerializedInDiscoverJobs() ); } - public function testSerializedConfigGeneratorsSentToApplyJobs() + public function testSerializedConfigGeneratorsSentToApplyJobs(): void { $subjectsAndPredicatesOfChange = ['http://example.com/1' => [RDF_TYPE]]; $impactedSubjects = [ @@ -136,9 +137,9 @@ public function testSerializedConfigGeneratorsSentToApplyJobs() $tripod->expects($this->once())->method('getComposite') ->with(OP_VIEWS) - ->will($this->returnValue($views)); + ->willReturn($views); - $views->expects($this->once())->method('getImpactedSubjects')->will($this->returnValue($impactedSubjects)); + $views->expects($this->once())->method('getImpactedSubjects')->willReturn($impactedSubjects); $discoverJob = $this->getMockBuilder(DiscoverImpactedSubjects::class) ->onlyMethods(['getTripod', 'getApplyOperation']) @@ -150,8 +151,8 @@ public function testSerializedConfigGeneratorsSentToApplyJobs() ->getMock(); $discoverJob->args = $jobArgs; $discoverJob->job = (object) ['payload' => ['id' => uniqid()]]; - $discoverJob->expects($this->once())->method('getTripod')->will($this->returnValue($tripod)); - $discoverJob->expects($this->once())->method('getApplyOperation')->will($this->returnValue($applyJob)); + $discoverJob->expects($this->once())->method('getTripod')->willReturn($tripod); + $discoverJob->expects($this->once())->method('getApplyOperation')->willReturn($applyJob); $configInstance = Config::getInstance(); $applyJob->expects($this->once())->method('submitJob') ->with( diff --git a/test/unit/mongo/DateUtilTest.php b/test/unit/mongo/DateUtilTest.php index b6e94474..0fef2ef1 100644 --- a/test/unit/mongo/DateUtilTest.php +++ b/test/unit/mongo/DateUtilTest.php @@ -1,12 +1,14 @@ getMongoDate(); @@ -29,10 +31,10 @@ public function testGetMongoDateWithNoParam() $date = DateUtil::getMongoDate(); $this->assertInstanceOf(UTCDateTime::class, $date); - $this->assertEquals(13, strlen($date->__toString())); + $this->assertSame(13, strlen($date->__toString())); } - public function testGetMongoDateWithParam() + public function testGetMongoDateWithParam(): void { $config = Config::getInstance(); $updatedAt = (new DateUtil())->getMongoDate(); @@ -56,7 +58,7 @@ public function testGetMongoDateWithParam() $date = DateUtil::getMongoDate($time); $this->assertInstanceOf(UTCDateTime::class, $date); - $this->assertEquals(13, strlen($date->__toString())); + $this->assertSame(13, strlen($date->__toString())); $this->assertEquals($time, $date->__toString()); } } diff --git a/test/unit/mongo/DiscoverImpactedSubjectsTest.php b/test/unit/mongo/DiscoverImpactedSubjectsTest.php index 69547b43..bc1d6617 100644 --- a/test/unit/mongo/DiscoverImpactedSubjectsTest.php +++ b/test/unit/mongo/DiscoverImpactedSubjectsTest.php @@ -1,5 +1,7 @@ setArgs(); unset($this->args['tripodConfig']); @@ -26,7 +28,7 @@ public function testMandatoryArgTripodConfig() $this->performJob($job); } - public function testMandatoryArgStoreName() + public function testMandatoryArgStoreName(): void { $this->setArgs(); unset($this->args['storeName']); @@ -38,7 +40,7 @@ public function testMandatoryArgStoreName() $this->performJob($job); } - public function testMandatoryArgPodName() + public function testMandatoryArgPodName(): void { $this->setArgs(); unset($this->args['podName']); @@ -50,7 +52,7 @@ public function testMandatoryArgPodName() $this->performJob($job); } - public function testMandatoryArgChanges() + public function testMandatoryArgChanges(): void { $this->setArgs(); unset($this->args['changes']); @@ -62,7 +64,7 @@ public function testMandatoryArgChanges() $this->performJob($job); } - public function testMandatoryArgOperations() + public function testMandatoryArgOperations(): void { $this->setArgs(); unset($this->args['operations']); @@ -74,7 +76,7 @@ public function testMandatoryArgOperations() $this->performJob($job); } - public function testMandatoryArgContextAlias() + public function testMandatoryArgContextAlias(): void { $this->setArgs(); unset($this->args['contextAlias']); @@ -86,7 +88,7 @@ public function testMandatoryArgContextAlias() $this->performJob($job); } - public function testSubmitApplyOperationsJob() + public function testSubmitApplyOperationsJob(): void { $this->setArgs(); @@ -124,13 +126,11 @@ public function testSubmitApplyOperationsJob() $tripod->expects($this->exactly(3)) ->method('getComposite') - ->will($this->returnValueMap( - [ - [OP_VIEWS, $views], - [OP_TABLES, $tables], - [OP_SEARCH, $search], - ] - )); + ->willReturnMap([ + [OP_VIEWS, $views], + [OP_TABLES, $tables], + [OP_SEARCH, $search], + ]); $discoverImpactedSubjects = $this->getMockBuilder(DiscoverImpactedSubjects::class) ->onlyMethods(['getTripod', 'getApplyOperation', 'getStat']) @@ -145,7 +145,7 @@ public function testSubmitApplyOperationsJob() $discoverImpactedSubjects->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $discoverImpactedSubjects->args = $this->args; $discoverImpactedSubjects->job = new Resque_Job('queue', ['id' => uniqid()]); @@ -168,9 +168,7 @@ public function testSubmitApplyOperationsJob() $views->expects($this->once()) ->method('getImpactedSubjects') ->with($this->args['changes'], $this->args['contextAlias']) - ->will($this->returnValue( - [$viewSubject] - )); + ->willReturn([$viewSubject]); $tableSubjects = [ new ImpactedSubject( @@ -198,22 +196,20 @@ public function testSubmitApplyOperationsJob() $tables->expects($this->once()) ->method('getImpactedSubjects') ->with($this->args['changes'], $this->args['contextAlias']) - ->will($this->returnValue( - $tableSubjects - )); + ->willReturn($tableSubjects); $search->expects($this->once()) ->method('getImpactedSubjects') ->with($this->args['changes'], $this->args['contextAlias']) - ->will($this->returnValue([])); + ->willReturn([]); $discoverImpactedSubjects->expects($this->exactly(2)) ->method('getApplyOperation') - ->will($this->returnValue($applyOperation)); + ->willReturn($applyOperation); $discoverImpactedSubjects->expects($this->exactly(5)) ->method('getStat') - ->will($this->returnValue($statMock)); + ->willReturn($statMock); $applyOperation->expects($this->exactly(2)) ->method('createJob') @@ -246,7 +242,7 @@ public function testSubmitApplyOperationsJob() $this->performJob($discoverImpactedSubjects); } - public function testCreateJobDefaultQueue() + public function testCreateJobDefaultQueue(): void { $labeller = new Labeller(); @@ -280,7 +276,7 @@ public function testCreateJobDefaultQueue() $discoverImpactedSubjects->createJob($jobData); } - public function testCreateJobSpecifyQueue() + public function testCreateJobSpecifyQueue(): void { $labeller = new Labeller(); @@ -316,7 +312,7 @@ public function testCreateJobSpecifyQueue() $discoverImpactedSubjects->createJob($jobData, $queueName); } - public function testManualQueueNamePersistsThroughJob() + public function testManualQueueNamePersistsThroughJob(): void { $discoverImpactedSubjects = $this->getMockBuilder(DiscoverImpactedSubjects::class) ->onlyMethods(['getTripod', 'getApplyOperation']) @@ -360,13 +356,11 @@ public function testManualQueueNamePersistsThroughJob() $tripod->expects($this->exactly(3)) ->method('getComposite') - ->will($this->returnValueMap( - [ - [OP_VIEWS, $views], - [OP_TABLES, $tables], - [OP_SEARCH, $search], - ] - )); + ->willReturnMap([ + [OP_VIEWS, $views], + [OP_TABLES, $tables], + [OP_SEARCH, $search], + ]); $applyOperation = $this->getMockBuilder(ApplyOperation::class) ->onlyMethods(['createJob']) @@ -385,9 +379,7 @@ public function testManualQueueNamePersistsThroughJob() $views->expects($this->once()) ->method('getImpactedSubjects') ->with($this->args['changes'], $this->args['contextAlias']) - ->will($this->returnValue( - [$viewSubject] - )); + ->willReturn([$viewSubject]); $tableSubject = new ImpactedSubject( [ @@ -403,22 +395,20 @@ public function testManualQueueNamePersistsThroughJob() $tables->expects($this->once()) ->method('getImpactedSubjects') ->with($this->args['changes'], $this->args['contextAlias']) - ->will($this->returnValue( - [$tableSubject] - )); + ->willReturn([$tableSubject]); $search->expects($this->once()) ->method('getImpactedSubjects') ->with($this->args['changes'], $this->args['contextAlias']) - ->will($this->returnValue([])); + ->willReturn([]); $discoverImpactedSubjects->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $discoverImpactedSubjects->expects($this->exactly(2)) ->method('getApplyOperation') - ->will($this->returnValue($applyOperation)); + ->willReturn($applyOperation); $applyOperation->expects($this->exactly(2)) ->method('createJob') @@ -436,7 +426,7 @@ public function testManualQueueNamePersistsThroughJob() $this->performJob($discoverImpactedSubjects); } - public function testDiscoverOperationWillSubmitApplyOperationForDistinctQueues() + public function testDiscoverOperationWillSubmitApplyOperationForDistinctQueues(): void { $config = Config::getConfig(); @@ -632,20 +622,20 @@ public function testDiscoverOperationWillSubmitApplyOperationForDistinctQueues() $tables->expects($this->once()) ->method('getImpactedSubjects') ->with($this->args['changes'], $this->args['contextAlias']) - ->will($this->returnValue([$tableSubject1, $tableSubject2])); + ->willReturn([$tableSubject1, $tableSubject2]); $tripod->expects($this->once()) ->method('getComposite') ->with(OP_TABLES) - ->will($this->returnValue($tables)); + ->willReturn($tables); $discoverImpactedSubjects->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $discoverImpactedSubjects->expects($this->exactly(3)) ->method('getApplyOperation') - ->will($this->returnValue($applyOperation)); + ->willReturn($applyOperation); $applyOperation->expects($this->exactly(3)) ->method('createJob') @@ -667,7 +657,7 @@ public function testDiscoverOperationWillSubmitApplyOperationForDistinctQueues() $this->performJob($discoverImpactedSubjects); } - public function testManuallySpecifiedQueueWillOverrideQueuesDefinedInConfig() + public function testManuallySpecifiedQueueWillOverrideQueuesDefinedInConfig(): void { $config = Config::getConfig(); @@ -806,24 +796,24 @@ public function testManuallySpecifiedQueueWillOverrideQueuesDefinedInConfig() $tables->expects($this->once()) ->method('getImpactedSubjects') ->with($this->args['changes'], $this->args['contextAlias']) - ->will($this->returnValue($tableSubjects)); + ->willReturn($tableSubjects); $tripod->expects($this->once()) ->method('getComposite') ->with(OP_TABLES) - ->will($this->returnValue($tables)); + ->willReturn($tables); $discoverImpactedSubjects->expects($this->once()) ->method('getTripod') - ->will($this->returnValue($tripod)); + ->willReturn($tripod); $discoverImpactedSubjects->expects($this->once()) ->method('getApplyOperation') - ->will($this->returnValue($applyOperation)); + ->willReturn($applyOperation); $applyOperation->expects($this->once()) ->method('createJob') - ->withConsecutive( + ->with( [ $tableSubjects, $args['queue'], diff --git a/test/unit/mongo/EnsureIndexesTest.php b/test/unit/mongo/EnsureIndexesTest.php index 47c2b2f8..51945eb6 100644 --- a/test/unit/mongo/EnsureIndexesTest.php +++ b/test/unit/mongo/EnsureIndexesTest.php @@ -1,5 +1,7 @@ args = $this->args; $job->job = new Resque_Job('queue', ['id' => uniqid()]); unset($job->args[$argument]); $this->expectException(Exception::class); - $this->expectExceptionMessage("Argument {$argumentName} was not present in supplied job args for job Tripod\\Mongo\\Jobs\\EnsureIndexes"); + $this->expectExceptionMessage(sprintf('Argument %s was not present in supplied job args for job Tripod\Mongo\Jobs\EnsureIndexes', $argumentName)); $this->performJob($job); } /** * Data provider for testMandatoryArgs. * - * @return array + * @return \Iterator<(int | string), array> */ - public function mandatoryArgDataProvider() + public function mandatoryArgDataProvider(): \Iterator { - return [ - ['tripodConfig', 'tripodConfig or tripodConfigGenerator'], - ['storeName'], - ['reindex'], - ['background'], - ]; + yield ['tripodConfig', 'tripodConfig or tripodConfigGenerator']; + yield ['storeName']; + yield ['reindex']; + yield ['background']; } /** @@ -71,7 +72,7 @@ public function mandatoryArgDataProvider() * * @group ensure-indexes */ - public function testSuccessfullyEnsureIndexesJob() + public function testSuccessfullyEnsureIndexesJob(): void { $job = $this->createMockJob(); $job->args = $this->createDefaultArguments(); @@ -85,7 +86,7 @@ public function testSuccessfullyEnsureIndexesJob() * * @group ensure-indexes */ - public function testEnsureIndexesJobThrowsErrorWhenCreatingIndexes() + public function testEnsureIndexesJobThrowsErrorWhenCreatingIndexes(): void { $job = $this->createMockJob(); $job->args = $this->createDefaultArguments(); @@ -100,7 +101,7 @@ public function testEnsureIndexesJobThrowsErrorWhenCreatingIndexes() * test that calling the create job method on the ensureindexes job class * will use the default queue name. */ - public function testEnsureIndexesCreateJobDefaultQueue() + public function testEnsureIndexesCreateJobDefaultQueue(): void { $jobData = [ 'storeName' => 'tripod_php_testing', @@ -126,9 +127,9 @@ public function testEnsureIndexesCreateJobDefaultQueue() * test that calling the create job method on the ensureindexes job class * will throw the expected exception if redis is unreachable. */ - public function testEnsureIndexesCreateJobUnreachableRedis() + public function testEnsureIndexesCreateJobUnreachableRedis(): void { - $jobData = [ + [ 'storeName' => 'tripod_php_testing', 'tripodConfig' => Config::getConfig(), 'reindex' => false, @@ -144,7 +145,7 @@ public function testEnsureIndexesCreateJobUnreachableRedis() // this is called 6 times because after the first attempt fails it will // retry 5 times. - $job->expects($this->exactly(6))->method('enqueue')->will($this->throwException($e)); + $job->expects($this->exactly(6))->method('enqueue')->willThrowException($e); // expect 5 retries. Catch this with call to warning log $job->expects($this->exactly(5))->method('warningLog'); @@ -158,9 +159,9 @@ public function testEnsureIndexesCreateJobUnreachableRedis() * test that calling the create job method on the ensureindexes job class * will throw the expected exception if the job fails. */ - public function testEnsureIndexesCreateJobStatusFalse() + public function testEnsureIndexesCreateJobStatusFalse(): void { - $jobData = [ + [ 'storeName' => 'tripod_php_testing', 'tripodConfig' => Config::getConfig(), 'reindex' => false, @@ -173,8 +174,8 @@ public function testEnsureIndexesCreateJobStatusFalse() // both of these methods will be called 6 times because after the first attempt fails it will // retry 5 times. - $job->expects($this->exactly(6))->method('enqueue')->will($this->returnValue('sometoken')); - $job->expects($this->exactly(6))->method('getJobStatus')->will($this->returnValue(false)); + $job->expects($this->exactly(6))->method('enqueue')->willReturn('sometoken'); + $job->expects($this->exactly(6))->method('getJobStatus')->willReturn(false); // expect 5 retries. Catch this with call to warning log $job->expects($this->exactly(5))->method('warningLog'); @@ -187,7 +188,7 @@ public function testEnsureIndexesCreateJobStatusFalse() * test that calling the create job method on the ensureindexes job class * will use the queue name specified. */ - public function testEnsureIndexesCreateJobSpecifyQueue() + public function testEnsureIndexesCreateJobSpecifyQueue(): void { $jobData = [ 'storeName' => 'tripod_php_testing', @@ -210,6 +211,7 @@ public function testEnsureIndexesCreateJobSpecifyQueue() $job->createJob('tripod_php_testing', false, true, $queueName); } + // HELPER METHODS BELOW HERE /** @@ -220,7 +222,7 @@ public function testEnsureIndexesCreateJobSpecifyQueue() * * @return EnsureIndexes&MockObject */ - protected function createMockJob($methods = []) + protected function createMockJob($methods = []): \PHPUnit\Framework\MockObject\MockObject { $methodsToStub = ['getIndexUtils', 'submitJob', 'warningLog', 'enqueue', 'getJobStatus']; @@ -240,9 +242,9 @@ protected function createMockJob($methods = []) /** * Returns default arguments for a EnsureIndexes Job. * - * @return array + * @return array */ - protected function createDefaultArguments() + protected function createDefaultArguments(): array { return [ 'tripodConfig' => Config::getConfig(), @@ -267,7 +269,7 @@ protected function jobSuccessfullyEnsuresIndexes($job) $job->expects($this->once()) ->method('getIndexUtils') - ->will($this->returnValue($mockIndexUtils)); + ->willReturn($mockIndexUtils); } /** @@ -282,10 +284,10 @@ protected function jobThrowsExceptionWhenEnsuringIndexes($job) $mockIndexUtils->expects($this->once()) ->method('ensureIndexes') ->with(false, 'tripod_php_testing', true) - ->will($this->throwException(new Exception('Ensuring index failed'))); + ->willThrowException(new Exception('Ensuring index failed')); $job->expects($this->once()) ->method('getIndexUtils') - ->will($this->returnValue($mockIndexUtils)); + ->willReturn($mockIndexUtils); } } diff --git a/test/unit/mongo/IndexUtilsTest.php b/test/unit/mongo/IndexUtilsTest.php index 1e9cf604..10e5afea 100644 --- a/test/unit/mongo/IndexUtilsTest.php +++ b/test/unit/mongo/IndexUtilsTest.php @@ -1,12 +1,14 @@ createMockConfig(); $collection = $this->createMockCollection(); @@ -23,7 +25,7 @@ public function testCBDCollectionIndexesAreCreated() $indexUtils->ensureIndexes(false, 'tripod_php_testing', true); } - public function testCBDCollectionIndexesAreCreatedWithIndexOptions() + public function testCBDCollectionIndexesAreCreatedWithIndexOptions(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -42,7 +44,7 @@ public function testCBDCollectionIndexesAreCreatedWithIndexOptions() $indexUtils->ensureIndexes(false, 'tripod_php_testing', true); } - public function testCBDCollectionIndexesAreCreatedInForeground() + public function testCBDCollectionIndexesAreCreatedInForeground(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -59,7 +61,7 @@ public function testCBDCollectionIndexesAreCreatedInForeground() $indexUtils->ensureIndexes(false, 'tripod_php_testing', false); } - public function testCBDCollectionIndexesAreCreatedInForegroundWithIndexOptions() + public function testCBDCollectionIndexesAreCreatedInForegroundWithIndexOptions(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -78,7 +80,7 @@ public function testCBDCollectionIndexesAreCreatedInForegroundWithIndexOptions() $indexUtils->ensureIndexes(false, 'tripod_php_testing', false); } - public function testCBDCollectionIndexesAreReindexed() + public function testCBDCollectionIndexesAreReindexed(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -95,7 +97,7 @@ public function testCBDCollectionIndexesAreReindexed() $indexUtils->ensureIndexes(true, 'tripod_php_testing', true); } - public function testCBDCollectionIndexesAreReindexedWithIndexOptions() + public function testCBDCollectionIndexesAreReindexedWithIndexOptions(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -114,7 +116,7 @@ public function testCBDCollectionIndexesAreReindexedWithIndexOptions() $indexUtils->ensureIndexes(true, 'tripod_php_testing', true); } - public function testViewIndexesAreCreated() + public function testViewIndexesAreCreated(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -131,7 +133,7 @@ public function testViewIndexesAreCreated() $indexUtils->ensureIndexes(false, 'tripod_php_testing', true); } - public function testViewIndexesAreCreatedInForeground() + public function testViewIndexesAreCreatedInForeground(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -148,7 +150,7 @@ public function testViewIndexesAreCreatedInForeground() $indexUtils->ensureIndexes(false, 'tripod_php_testing', false); } - public function testViewIndexesAreReindexed() + public function testViewIndexesAreReindexed(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -165,7 +167,7 @@ public function testViewIndexesAreReindexed() $indexUtils->ensureIndexes(true, 'tripod_php_testing', true); } - public function testTableIndexesAreCreated() + public function testTableIndexesAreCreated(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -182,7 +184,7 @@ public function testTableIndexesAreCreated() $indexUtils->ensureIndexes(false, 'tripod_php_testing', true); } - public function testTableIndexesAreCreatedInForeground() + public function testTableIndexesAreCreatedInForeground(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -199,7 +201,7 @@ public function testTableIndexesAreCreatedInForeground() $indexUtils->ensureIndexes(false, 'tripod_php_testing', false); } - public function testTableIndexesAreReindexed() + public function testTableIndexesAreReindexed(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -216,7 +218,7 @@ public function testTableIndexesAreReindexed() $indexUtils->ensureIndexes(true, 'tripod_php_testing', true); } - public function testSearchDocIndexesAreCreated() + public function testSearchDocIndexesAreCreated(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -233,7 +235,7 @@ public function testSearchDocIndexesAreCreated() $indexUtils->ensureIndexes(false, 'tripod_php_testing', true); } - public function testSearchDocIndexesAreCreatedInForeground() + public function testSearchDocIndexesAreCreatedInForeground(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -250,7 +252,7 @@ public function testSearchDocIndexesAreCreatedInForeground() $indexUtils->ensureIndexes(false, 'tripod_php_testing', false); } - public function testSearchDocIndexesAreReindexed() + public function testSearchDocIndexesAreReindexed(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -267,7 +269,7 @@ public function testSearchDocIndexesAreReindexed() $indexUtils->ensureIndexes(true, 'tripod_php_testing', true); } - public function testIndexesAreDroppedOnlyOncePerCollectionWhenReindexed() + public function testIndexesAreDroppedOnlyOncePerCollectionWhenReindexed(): void { $config = $this->createMockConfig(); $collection = $this->createMockCollection(); @@ -292,7 +294,7 @@ public function testIndexesAreDroppedOnlyOncePerCollectionWhenReindexed() * * @return IndexUtils&MockObject mocked IndexUtil object */ - protected function createMockIndexUtils($mockConfig) + protected function createMockIndexUtils($mockConfig): \PHPUnit\Framework\MockObject\MockObject { $mockIndexUtils = $this->getMockBuilder(IndexUtils::class) ->onlyMethods(['getConfig']) @@ -300,7 +302,7 @@ protected function createMockIndexUtils($mockConfig) $mockIndexUtils->expects($this->once()) ->method('getConfig') - ->will($this->returnValue($mockConfig)); + ->willReturn($mockConfig); return $mockIndexUtils; } @@ -310,7 +312,7 @@ protected function createMockIndexUtils($mockConfig) * * @return Collection&MockObject mock Collection object */ - protected function createMockCollection() + protected function createMockCollection(): \PHPUnit\Framework\MockObject\MockObject { return $this->getMockBuilder(MongoDB\Collection::class) ->onlyMethods(['createIndex', 'dropIndexes']) @@ -327,7 +329,7 @@ protected function createMockCollection() * * @return MockObject&TripodTestConfig mock Config object */ - protected function createMockConfig() + protected function createMockConfig(): \PHPUnit\Framework\MockObject\MockObject { return $this->getMockBuilder(TripodTestConfig::class) ->onlyMethods([ @@ -344,12 +346,12 @@ protected function createMockConfig() * @param MockObject&TripodTestConfig $mockConfig mock Config object * @param Collection&MockObject $mockCollection mock Collection object */ - protected function getCollectionForCBDShouldBeCalled_n_Times($callCount, $mockConfig, $mockCollection) + protected function getCollectionForCBDShouldBeCalled_n_Times(int $callCount, $mockConfig, $mockCollection) { $mockConfig->expects($this->exactly($callCount)) ->method('getCollectionForCBD') ->with('tripod_php_testing', 'CBD_testing') - ->will($this->returnValue($mockCollection)); + ->willReturn($mockCollection); } /** @@ -357,12 +359,12 @@ protected function getCollectionForCBDShouldBeCalled_n_Times($callCount, $mockCo * @param MockObject&TripodTestConfig $mockConfig mock Config object * @param Collection&MockObject $mockCollection mock Collection object */ - protected function getCollectionForViewShouldBeCalled_n_Times($callCount, $mockConfig, $mockCollection) + protected function getCollectionForViewShouldBeCalled_n_Times(int $callCount, $mockConfig, $mockCollection) { $mockConfig->expects($this->exactly($callCount)) ->method('getCollectionForView') ->with('tripod_php_testing', 'v_testview') - ->will($this->returnValue($mockCollection)); + ->willReturn($mockCollection); } /** @@ -370,12 +372,12 @@ protected function getCollectionForViewShouldBeCalled_n_Times($callCount, $mockC * @param MockObject&TripodTestConfig $mockConfig mock Config object * @param Collection&MockObject $mockCollection mock Collection object */ - protected function getCollectionForTableShouldBeCalled_n_Times($callCount, $mockConfig, $mockCollection) + protected function getCollectionForTableShouldBeCalled_n_Times(int $callCount, $mockConfig, $mockCollection) { $mockConfig->expects($this->exactly($callCount)) ->method('getCollectionForTable') ->with('tripod_php_testing', 't_testtable') - ->will($this->returnValue($mockCollection)); + ->willReturn($mockCollection); } /** @@ -383,12 +385,12 @@ protected function getCollectionForTableShouldBeCalled_n_Times($callCount, $mock * @param MockObject&TripodTestConfig $mockConfig mock Config object * @param Collection&MockObject $mockCollection mock Collection object */ - protected function getCollectionForSearchDocShouldBeCalled_n_Times($callCount, $mockConfig, $mockCollection) + protected function getCollectionForSearchDocShouldBeCalled_n_Times(int $callCount, $mockConfig, $mockCollection) { $mockConfig->expects($this->exactly($callCount)) ->method('getCollectionForSearchDocument') ->with('tripod_php_testing', 'i_search_something') - ->will($this->returnValue($mockCollection)); + ->willReturn($mockCollection); } /** @@ -455,6 +457,7 @@ protected function getCollectionForCBDShouldNeverBeCalled($mockConfig) * * @param Collection&MockObject $mockCollection mock Collection object * @param bool $background create indexes in the background + * @param array $indexOptions */ protected function oneCustomAndThreeInternalTripodCBDIndexesShouldBeCreated($mockCollection, $background = true, array $indexOptions = []) { @@ -539,6 +542,7 @@ protected function threeInternalTripodSearchDocIndexesShouldBeCreated($mockColle * indexes for a CBD collection. * * @param MockObject&TripodTestConfig $mockConfig mock Config object + * @param array $indexOptions */ protected function setConfigForCBDIndexes($mockConfig, array $indexOptions = []) { @@ -564,7 +568,7 @@ protected function setConfigForCBDIndexes($mockConfig, array $indexOptions = []) ], ]; - if (empty($indexOptions)) { + if ($indexOptions === []) { $config['stores']['tripod_php_testing']['pods']['CBD_testing']['indexes'] = [ 'rdf_type' => [ 'rdf:type.u' => 1, diff --git a/test/unit/mongo/JobBaseTest.php b/test/unit/mongo/JobBaseTest.php index 9b15fb29..3c272a5b 100644 --- a/test/unit/mongo/JobBaseTest.php +++ b/test/unit/mongo/JobBaseTest.php @@ -1,11 +1,13 @@ args = $this->getArgs(); @@ -14,7 +16,10 @@ public function testGetTripodConfig() $this->assertInstanceOf(IConfigInstance::class, $job->getTripodConfig()); } - protected function getArgs() + /** + * @return array + */ + protected function getArgs(): array { return [ 'tripodConfig' => Config::getConfig(), diff --git a/test/unit/mongo/MongoGraphTest.php b/test/unit/mongo/MongoGraphTest.php index 88575576..fc512f54 100644 --- a/test/unit/mongo/MongoGraphTest.php +++ b/test/unit/mongo/MongoGraphTest.php @@ -1,5 +1,7 @@ assertEquals('dct:title', $g->uri_to_qname('http://purl.org/dc/terms/title')); } - public function testUriToQNameOnUnRegisteredNS() + public function testUriToQNameOnUnRegisteredNS(): void { $this->expectException(LabellerException::class); $this->expectExceptionMessage('Could not label: http://someunregisteredns/'); @@ -25,7 +27,7 @@ public function testUriToQNameOnUnRegisteredNS() $g->uri_to_qname('http://someunregisteredns/title'); } - public function testQNameToUriOnUnRegisteredNS() + public function testQNameToUriOnUnRegisteredNS(): void { $this->expectException(LabellerException::class); $this->expectExceptionMessage('Could not label: someunregisteredns:title'); @@ -33,7 +35,7 @@ public function testQNameToUriOnUnRegisteredNS() $g->qname_to_uri('someunregisteredns:title'); } - public function testToNQuadsThrowsInvalidArgumentException() + public function testToNQuadsThrowsInvalidArgumentException(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('You must specify the context when serializing to nquads'); @@ -41,7 +43,7 @@ public function testToNQuadsThrowsInvalidArgumentException() $g->to_nquads(null); } - public function testToNQuads() + public function testToNQuads(): void { $g = new MongoGraph(); $g->add_literal_triple('http://example.com/1', $g->qname_to_uri('dct:title'), 'some literal title'); @@ -52,7 +54,7 @@ public function testToNQuads() $this->assertEquals($expected, $g->to_nquads(Config::getInstance()->getDefaultContextAlias())); } - public function testToNQuadsTwoGraphsWithDifferentContext() + public function testToNQuadsTwoGraphsWithDifferentContext(): void { $g = new MongoGraph(); $g->add_literal_triple('http://example.com/1', $g->qname_to_uri('dct:title'), 'some literal title'); @@ -71,7 +73,7 @@ public function testToNQuadsTwoGraphsWithDifferentContext() $this->assertEquals($expected, $g->to_nquads('http://wibble.talisaspire.com/')); } - public function testAddTripodArrayThrowsException() + public function testAddTripodArrayThrowsException(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('Value passed to add_tripod_array is not of type array'); @@ -79,7 +81,7 @@ public function testAddTripodArrayThrowsException() $g->add_tripod_array(null); } - public function testAddTripodArraySingleDoc() + public function testAddTripodArraySingleDoc(): void { $doc = [ '_id' => ['r' => 'http://talisaspire.com/works/4d101f63c10a6-2', 'c' => 'http://talisaspire.com/works/4d101f63c10a6-2'], @@ -109,7 +111,7 @@ public function testAddTripodArraySingleDoc() * * @param mixed $value */ - public function testAddTripodArrayContainingValidLiteralValues($value) + public function testAddTripodArrayContainingValidLiteralValues($value): void { $doc = [ '_id' => ['r' => 'http://talisaspire.com/works/4d101f63c10a6-2', 'c' => 'http://talisaspire.com/works/4d101f63c10a6-2'], @@ -134,14 +136,15 @@ public function testAddTripodArrayContainingValidLiteralValues($value) $this->assertEquals($expected, $g); } - public function addTripodArrayContainingValidLiteralValues_Provider() + /** + * @return \Iterator<(int | string), array<(1.2 | int | string | true)>> + */ + public function addTripodArrayContainingValidLiteralValues_Provider(): \Iterator { - return [ - ['A String'], - [1], - [1.2], - [true], - ]; + yield ['A String']; + yield [1]; + yield [1.2]; + yield [true]; } /** @@ -149,7 +152,7 @@ public function addTripodArrayContainingValidLiteralValues_Provider() * * @param mixed $value */ - public function testAddTripodArrayContainingInvalidLiteralValues($value) + public function testAddTripodArrayContainingInvalidLiteralValues($value): void { $doc = [ '_id' => ['r' => 'http://talisaspire.com/works/4d101f63c10a6-2', 'c' => 'http://talisaspire.com/works/4d101f63c10a6-2'], @@ -172,13 +175,14 @@ public function testAddTripodArrayContainingInvalidLiteralValues($value) $this->assertEquals($expected, $g); } - public function addTripodArrayContainingInvalidLiteralValues_Provider() + /** + * @return \Iterator<(int | string), array<(Closure(): void | \stdClass | null)>> + */ + public function addTripodArrayContainingInvalidLiteralValues_Provider(): \Iterator { - return [ - [null], - [new stdClass()], - [function (): void {}], - ]; + yield [null]; + yield [new stdClass()]; + yield [function (): void {}]; } /** @@ -186,7 +190,7 @@ public function addTripodArrayContainingInvalidLiteralValues_Provider() * * @param mixed $value */ - public function testAddTripodArrayContainingInvalidPredicates($value) + public function testAddTripodArrayContainingInvalidPredicates($value): void { $this->expectException(LabellerException::class); $doc = [ @@ -207,19 +211,20 @@ public function testAddTripodArrayContainingInvalidPredicates($value) $g->add_tripod_array($doc); } - public function addTripodArrayContainingInvalidPredicates_Provider() + /** + * @return \Iterator<(int | string), array<(1.2 | int | true)>> + */ + public function addTripodArrayContainingInvalidPredicates_Provider(): \Iterator { - return [ - [1], - [1.2], - [true], - ]; + yield [1]; + yield [1.2]; + yield [true]; } /** * We are expecting the labeller. */ - public function testAddTripodArrayContainingEmptyPredicate() + public function testAddTripodArrayContainingEmptyPredicate(): void { // Should not be able to label '' $this->expectException(Tripod\Exceptions\Exception::class); @@ -247,7 +252,7 @@ public function testAddTripodArrayContainingEmptyPredicate() * * @param mixed $value */ - public function testAddTripodArrayContainingInvalidSubject($value) + public function testAddTripodArrayContainingInvalidSubject($value): void { $this->expectException(Tripod\Exceptions\Exception::class); $doc = [ @@ -263,17 +268,18 @@ public function testAddTripodArrayContainingInvalidSubject($value) $g->add_tripod_array($doc); } - public function addTripodArrayContainingInvalidSubject_Provider() + /** + * @return \Iterator<(int | string), array<(1.2 | int | string | true)>> + */ + public function addTripodArrayContainingInvalidSubject_Provider(): \Iterator { - return [ - [''], - [1], - [1.2], - [true], - ]; + yield ['']; + yield [1]; + yield [1.2]; + yield [true]; } - public function testAddTripodArrayContainingValidResourceValues() + public function testAddTripodArrayContainingValidResourceValues(): void { $value = 'A String'; $doc = [ @@ -304,7 +310,7 @@ public function testAddTripodArrayContainingValidResourceValues() * * @param mixed $value */ - public function testAddTripodArrayContainingInvalidResourceValues($value) + public function testAddTripodArrayContainingInvalidResourceValues($value): void { $doc = [ '_id' => ['r' => 'http://talisaspire.com/works/4d101f63c10a6-2', 'c' => 'http://talisaspire.com/works/4d101f63c10a6-2'], @@ -327,20 +333,21 @@ public function testAddTripodArrayContainingInvalidResourceValues($value) $this->assertEquals($expected, $g); } - public function addTripodArrayContainingInvalidResourceValues_Provider() + /** + * @return \Iterator<(int | string), array<(1.2 | array | Closure(): void | int | \stdClass | true | null)>> + */ + public function addTripodArrayContainingInvalidResourceValues_Provider(): \Iterator { - return [ - [1], - [1.2], - [true], - [[]], - [null], - [new stdClass()], - [function (): void {}], - ]; + yield [1]; + yield [1.2]; + yield [true]; + yield [[]]; + yield [null]; + yield [new stdClass()]; + yield [function (): void {}]; } - public function testAddTripodArrayWhenAddingViews() + public function testAddTripodArrayWhenAddingViews(): void { // view contains 4 subgraphs $view = json_decode(file_get_contents(__DIR__ . '/data/view.json'), true); @@ -348,7 +355,7 @@ public function testAddTripodArrayWhenAddingViews() $g->add_tripod_array($view); // graph should contain 4 subgraphs - $this->assertEquals(4, count($g->get_subjects())); + $this->assertCount(4, $g->get_subjects()); // assert each subgraph $this->assertHasLiteralTriple($g, 'http://example.com/resources/1', $g->qname_to_uri('dct:date'), '2003'); @@ -370,7 +377,7 @@ public function testAddTripodArrayWhenAddingViews() $this->assertHasResourceTriple($g, 'http://example.com/resources/1/authors', $g->qname_to_uri('rdf:type'), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#Seq'); } - public function testToTripodArray() + public function testToTripodArray(): void { $expected = [ '_id' => ['r' => 'http://talisaspire.com/works/4d101f63c10a6-2', 'c' => 'http://example.com/'], @@ -394,14 +401,14 @@ public function testToTripodArray() $this->assertEquals($expected, $actual); } - public function testToTripodArrayReturnsNullIfDocNotInGraph() + public function testToTripodArrayReturnsNullIfDocNotInGraph(): void { $g = new MongoGraph(); $doc = $g->to_tripod_array('http://example.com/1', 'http://example.com/'); $this->assertNull($doc); } - public function testToTripodViewArray() + public function testToTripodViewArray(): void { $expected = [ '_id' => ['r' => 'http://example.com/things/1', 'c' => 'http://example.com/'], @@ -435,7 +442,7 @@ public function testToTripodViewArray() $this->assertEquals($expected, $actual); } - public function testWriteLockedDocDoesNotExposeVersionOrLockPropertyInGraph() + public function testWriteLockedDocDoesNotExposeVersionOrLockPropertyInGraph(): void { $doc = [ '_id' => ['r' => 'http://example.com/things/1', 'c' => 'http://example.com/'], @@ -445,6 +452,6 @@ public function testWriteLockedDocDoesNotExposeVersionOrLockPropertyInGraph() $g = new MongoGraph(); $g->add_tripod_array($doc); - $this->assertTrue(count($g->get_index()) == 0, 'Graph should contain no data'); + $this->assertCount(0, $g->get_index(), 'Graph should contain no data'); } } diff --git a/test/unit/mongo/MongoSearchProviderTest.php b/test/unit/mongo/MongoSearchProviderTest.php index 92a68d89..7377fcf0 100644 --- a/test/unit/mongo/MongoSearchProviderTest.php +++ b/test/unit/mongo/MongoSearchProviderTest.php @@ -1,5 +1,7 @@ tripodTransactionLog->purgeAllTransactions(); $this->tripod = new Driver('CBD_testing', 'tripod_php_testing'); - $this->indexer = new SearchIndexer($this->tripod); - $this->searchProvider = new MongoSearchProvider($this->tripod); + $this->searchIndexer = new SearchIndexer($this->tripod); + $this->mongoSearchProvider = new MongoSearchProvider($this->tripod); $this->getTripodCollection($this->tripod)->drop(); $this->loadBaseSearchDataViaTripod(); @@ -52,11 +54,12 @@ protected function setUp(): void } } } - $this->indexer->generateAndIndexSearchDocuments($result['_id']['r'], $result['_id']['c'], $this->tripod->getPodName()); + + $this->searchIndexer->generateAndIndexSearchDocuments($result['_id']['r'], $result['_id']['c'], $this->tripod->getPodName()); } } - public function testSearchIndexing() + public function testSearchIndexing(): void { // assert that there are only 12 based on the data we loaded into tripod $actualSearchDocumentCount = $this->getCountForSearchSpecs($this->tripod); @@ -185,7 +188,7 @@ public function testSearchIndexing() } } - public function testSearchIndexingRemovesDocWhenTypeHasNoCorrespondingSearchdocSpec() + public function testSearchIndexingRemovesDocWhenTypeHasNoCorrespondingSearchdocSpec(): void { // update a document $id = ['_id.r' => 'http://talisaspire.com/resources/doc1']; @@ -193,7 +196,7 @@ public function testSearchIndexingRemovesDocWhenTypeHasNoCorrespondingSearchdocS ->updateOne($id, ['$set' => ['rdf:type' => ['u' => 'bibo:Article']]]); // reindex - $this->indexer->generateAndIndexSearchDocuments('http://talisaspire.com/resources/doc1', 'http://talisaspire.com/', $this->tripod->getPodName()); + $this->searchIndexer->generateAndIndexSearchDocuments('http://talisaspire.com/resources/doc1', 'http://talisaspire.com/', $this->tripod->getPodName()); $actualSearchDocumentCount = $this->getCountForSearchSpecs($this->tripod); @@ -207,7 +210,7 @@ public function testSearchIndexingRemovesDocWhenTypeHasNoCorrespondingSearchdocS } } - public function testSearchIndexingGeneratesNewDocForChangedTypeThatHasACorrespondingSearchdocSpec() + public function testSearchIndexingGeneratesNewDocForChangedTypeThatHasACorrespondingSearchdocSpec(): void { // update a document $id = ['_id.r' => 'http://talisaspire.com/resources/doc1']; @@ -220,7 +223,7 @@ public function testSearchIndexingGeneratesNewDocForChangedTypeThatHasACorrespon $this->getTripodCollection($this->tripod)->updateOne($id, ['$set' => $newData]); // reindex - $this->indexer->generateAndIndexSearchDocuments('http://talisaspire.com/resources/doc1', 'http://talisaspire.com/', $this->tripod->getPodName()); + $this->searchIndexer->generateAndIndexSearchDocuments('http://talisaspire.com/resources/doc1', 'http://talisaspire.com/', $this->tripod->getPodName()); $actualSearchDocumentCount = $this->getCountForSearchSpecs($this->tripod); @@ -233,6 +236,7 @@ public function testSearchIndexingGeneratesNewDocForChangedTypeThatHasACorrespon break; } } + $this->assertEquals($result['_id'], [ 'r' => 'http://talisaspire.com/resources/doc1', 'c' => 'http://talisaspire.com/', @@ -240,7 +244,7 @@ public function testSearchIndexingGeneratesNewDocForChangedTypeThatHasACorrespon ]); } - public function testSearchIndexingGeneratesTwoDocumentsForGivenResourceTheDeletesOneAfterFurtherUpdate() + public function testSearchIndexingGeneratesTwoDocumentsForGivenResourceTheDeletesOneAfterFurtherUpdate(): void { // update a document $id = ['_id.r' => 'http://talisaspire.com/resources/doc1']; @@ -253,7 +257,7 @@ public function testSearchIndexingGeneratesTwoDocumentsForGivenResourceTheDelete $this->getTripodCollection($this->tripod)->updateOne($id, ['$set' => $newData]); // reindex - $this->indexer->generateAndIndexSearchDocuments('http://talisaspire.com/resources/doc1', 'http://talisaspire.com/', $this->tripod->getPodName()); + $this->searchIndexer->generateAndIndexSearchDocuments('http://talisaspire.com/resources/doc1', 'http://talisaspire.com/', $this->tripod->getPodName()); $actualSearchDocumentCount = $this->getCountForSearchSpecs($this->tripod); @@ -269,7 +273,7 @@ public function testSearchIndexingGeneratesTwoDocumentsForGivenResourceTheDelete } } - $this->assertEquals(2, count($results)); + $this->assertCount(2, $results); $expected = [ [ 'r' => 'http://talisaspire.com/resources/doc1', @@ -283,10 +287,7 @@ public function testSearchIndexingGeneratesTwoDocumentsForGivenResourceTheDelete ], ]; foreach ($results as $result) { - $this->assertTrue(in_array( - $result['_id'], - $expected - )); + $this->assertContains($result['_id'], $expected); } // now update it again removing the resourcelist:List type @@ -296,7 +297,7 @@ public function testSearchIndexingGeneratesTwoDocumentsForGivenResourceTheDelete $this->getTripodCollection($this->tripod)->updateOne($id, ['$set' => $newData]); // reindex - $this->indexer->generateAndIndexSearchDocuments('http://talisaspire.com/resources/doc1', 'http://talisaspire.com/', $this->tripod->getPodName()); + $this->searchIndexer->generateAndIndexSearchDocuments('http://talisaspire.com/resources/doc1', 'http://talisaspire.com/', $this->tripod->getPodName()); $actualSearchDocumentCount = $this->getCountForSearchSpecs($this->tripod); @@ -312,7 +313,7 @@ public function testSearchIndexingGeneratesTwoDocumentsForGivenResourceTheDelete } } - $this->assertEquals(1, count($results)); + $this->assertCount(1, $results); $result = array_pop($results); $this->assertEquals($result['_id'], [ @@ -322,51 +323,51 @@ public function testSearchIndexingGeneratesTwoDocumentsForGivenResourceTheDelete ]); } - public function testSearchThrowsExceptionIfNoQuery() + public function testSearchThrowsExceptionIfNoQuery(): void { $this->expectException(SearchException::class); $this->expectExceptionMessage('You must specify a query'); - $this->searchProvider->search('', 'i_search_resource', ['search_terms'], ['result'], 3, 0); + $this->mongoSearchProvider->search('', 'i_search_resource', ['search_terms'], ['result'], 3, 0); } - public function testSearchThrowsExceptionIfNoType() + public function testSearchThrowsExceptionIfNoType(): void { $this->expectException(SearchException::class); $this->expectExceptionMessage('You must specify the search document type to restrict the query to'); - $this->searchProvider->search('poetry', '', ['search_terms'], ['result'], 3, 0); + $this->mongoSearchProvider->search('poetry', '', ['search_terms'], ['result'], 3, 0); } - public function testSearchThrowsExceptionIfSearchIndicesEmpty() + public function testSearchThrowsExceptionIfSearchIndicesEmpty(): void { $this->expectException(SearchException::class); $this->expectExceptionMessage('You must specify at least one index from the search document specification to query against'); - $this->searchProvider->search('poetry', 'i_search_resource', [], ['result'], 3, 0); + $this->mongoSearchProvider->search('poetry', 'i_search_resource', [], ['result'], 3, 0); } - public function testSearchThrowsExceptionIfFieldsToReturnEmpty() + public function testSearchThrowsExceptionIfFieldsToReturnEmpty(): void { $this->expectException(SearchException::class); $this->expectExceptionMessage('You must specify at least one field from the search document specification to return'); - $this->searchProvider->search('poetry', 'i_search_resource', ['search_terms'], [], 3, 0); + $this->mongoSearchProvider->search('poetry', 'i_search_resource', ['search_terms'], [], 3, 0); } - public function testSearchThrowsExceptionIfLimitIsNegative() + public function testSearchThrowsExceptionIfLimitIsNegative(): void { $this->expectException(SearchException::class); $this->expectExceptionMessage('Value for limit must be a positive number'); - $this->searchProvider->search('poetry', 'i_search_resource', ['search_terms'], ['result'], -3, 0); + $this->mongoSearchProvider->search('poetry', 'i_search_resource', ['search_terms'], ['result'], -3, 0); } - public function testSearchThrowsExceptionIfOffsetIsNegative() + public function testSearchThrowsExceptionIfOffsetIsNegative(): void { $this->expectException(SearchException::class); $this->expectExceptionMessage('Value for offset must be a positive number'); - $this->searchProvider->search('poetry', 'i_search_resource', ['search_terms'], ['result'], 3, -1); + $this->mongoSearchProvider->search('poetry', 'i_search_resource', ['search_terms'], ['result'], 3, -1); } - public function testSearchLimitAndOffset() + public function testSearchLimitAndOffset(): void { - $results = $this->searchProvider->search('poetry', 'i_search_resource', ['search_terms'], ['result'], 3, 0); + $results = $this->mongoSearchProvider->search('poetry', 'i_search_resource', ['search_terms'], ['result'], 3, 0); $this->assertEquals(3, $results['head']['limit']); $this->assertEquals(0, $results['head']['offset']); @@ -374,23 +375,23 @@ public function testSearchLimitAndOffset() $secondResult = $results['results'][1]; $thirdResult = $results['results'][2]; - $results2 = $this->searchProvider->search('poetry', 'i_search_resource', ['search_terms'], ['result'], 3, 1); + $results2 = $this->mongoSearchProvider->search('poetry', 'i_search_resource', ['search_terms'], ['result'], 3, 1); $this->assertEquals(9, $results2['head']['count']); $this->assertEquals(3, $results2['head']['limit']); $this->assertEquals(1, $results2['head']['offset']); - $this->assertFalse(in_array($firstResult, $results2['results'])); + $this->assertNotContains($firstResult, $results2['results']); $this->assertEquals($secondResult, $results2['results'][0]); $this->assertEquals($thirdResult, $results2['results'][1]); } - public function testSearchSingleIndex() + public function testSearchSingleIndex(): void { // simple search - $results = $this->searchProvider->search('john locke poetry', 'i_search_resource', ['search_terms'], ['result'], 4, 0); + $results = $this->mongoSearchProvider->search('john locke poetry', 'i_search_resource', ['search_terms'], ['result'], 4, 0); $this->assertEquals(6, $results['head']['count']); $this->assertEquals(4, $results['head']['limit']); - $this->assertEquals(4, count($results['results'])); + $this->assertCount(4, $results['results']); $this->assertEquals(0, $results['head']['offset']); $this->assertEquals('john locke poetry', $results['head']['query']); $this->assertEquals(['john', 'locke', 'poetry'], $results['head']['query_terms_used']); @@ -406,20 +407,20 @@ public function testSearchSingleIndex() $this->assertEquals($expectedResults, $results['results']); // search with some stop words - $results = $this->searchProvider->search('the owl and the pussycat', 'i_search_resource', ['search_terms'], ['result'], 3, 0); + $results = $this->mongoSearchProvider->search('the owl and the pussycat', 'i_search_resource', ['search_terms'], ['result'], 3, 0); $this->assertEquals(1, $results['head']['count']); $this->assertEquals(3, $results['head']['limit']); - $this->assertEquals(1, count($results['results'])); + $this->assertCount(1, $results['results']); $this->assertEquals(0, $results['head']['offset']); $this->assertEquals('the owl and the pussycat', $results['head']['query']); $this->assertEquals(['owl', 'pussycat'], $results['head']['query_terms_used']); $this->assertArrayHasKey('duration', $results['head']); // search returns no results - $results = $this->searchProvider->search('october', 'i_search_resource', ['search_terms'], ['result'], 3, 0); + $results = $this->mongoSearchProvider->search('october', 'i_search_resource', ['search_terms'], ['result'], 3, 0); $this->assertEquals(0, $results['head']['count']); $this->assertEquals(3, $results['head']['limit']); - $this->assertEquals(0, count($results['results'])); + $this->assertCount(0, $results['results']); $this->assertEquals(0, $results['head']['offset']); $this->assertEquals('october', $results['head']['query']); $this->assertEquals(['october'], $results['head']['query_terms_used']); @@ -427,10 +428,10 @@ public function testSearchSingleIndex() $this->assertEquals([], $results['results']); // search single index but return multiple fields - $results = $this->searchProvider->search('john locke poetry', 'i_search_resource', ['search_terms'], ['result', 'rdftype'], 3, 0); + $results = $this->mongoSearchProvider->search('john locke poetry', 'i_search_resource', ['search_terms'], ['result', 'rdftype'], 3, 0); $this->assertEquals(6, $results['head']['count']); $this->assertEquals(3, $results['head']['limit']); - $this->assertEquals(3, count($results['results'])); + $this->assertCount(3, $results['results']); $this->assertEquals(0, $results['head']['offset']); $this->assertEquals('john locke poetry', $results['head']['query']); $this->assertEquals(['john', 'locke', 'poetry'], $results['head']['query_terms_used']); @@ -444,12 +445,12 @@ public function testSearchSingleIndex() $this->assertEquals($expectedResults, $results['results']); } - public function testSearchMultipleIndices() + public function testSearchMultipleIndices(): void { - $results = $this->searchProvider->search('bibo:Book', 'i_search_resource', ['search_terms', 'other_terms'], ['result', 'rdftype'], 3, 0); + $results = $this->mongoSearchProvider->search('bibo:Book', 'i_search_resource', ['search_terms', 'other_terms'], ['result', 'rdftype'], 3, 0); $this->assertEquals(13, $results['head']['count']); $this->assertEquals(3, $results['head']['limit']); - $this->assertEquals(3, count($results['results'])); + $this->assertCount(3, $results['results']); $this->assertEquals(0, $results['head']['offset']); $this->assertEquals('bibo:Book', $results['head']['query']); $this->assertEquals(['bibo:book'], $results['head']['query_terms_used']); @@ -464,7 +465,7 @@ public function testSearchMultipleIndices() $this->assertEquals($expectedResults, $results['results']); } - public function testSearchWorksDirectlyFromTripod() + public function testSearchWorksDirectlyFromTripod(): void { $results = $this->tripod->search([ 'q' => 'john locke poetry', @@ -477,7 +478,7 @@ public function testSearchWorksDirectlyFromTripod() $this->assertEquals(6, $results['head']['count']); $this->assertEquals(3, $results['head']['limit']); - $this->assertEquals(3, count($results['results'])); + $this->assertCount(3, $results['results']); $this->assertEquals(0, $results['head']['offset']); $this->assertEquals('john locke poetry', $results['head']['query']); $this->assertEquals(['john', 'locke', 'poetry'], $results['head']['query_terms_used']); @@ -492,7 +493,7 @@ public function testSearchWorksDirectlyFromTripod() $this->assertEquals($expectedResults, $results['results']); } - public function testDeleteSearchDocumentsByTypeIdThrowsExceptionForInvalidType() + public function testDeleteSearchDocumentsByTypeIdThrowsExceptionForInvalidType(): void { $mockSearchProvider = $this->getMockBuilder(MongoSearchProvider::class) ->onlyMethods(['getSearchDocumentSpecification']) @@ -501,14 +502,14 @@ public function testDeleteSearchDocumentsByTypeIdThrowsExceptionForInvalidType() $mockSearchProvider->expects($this->once()) ->method('getSearchDocumentSpecification') ->with('i_some_type') - ->will($this->returnValue(null)); + ->willReturn(null); $this->expectException(Exception::class); $this->expectExceptionMessage('Could not find a search specification for i_some_type'); $mockSearchProvider->deleteSearchDocumentsByTypeId('i_some_type'); } - public function testDeleteSearchDocumentsByTypeIdDeletesNothingWhenNoMatchFound() + public function testDeleteSearchDocumentsByTypeIdDeletesNothingWhenNoMatchFound(): void { // first, assert that there are only 12 based on the data we loaded into tripod $actualSearchDocumentCount = $this->getCountForSearchSpecs($this->tripod); @@ -522,12 +523,12 @@ public function testDeleteSearchDocumentsByTypeIdDeletesNothingWhenNoMatchFound( $mockSearchProvider->expects($this->once()) ->method('getSearchDocumentSpecification') ->with('i_some_type') - ->will($this->returnValue(['i_some_type' => []])); + ->willReturn(['i_some_type' => []]); try { $mockSearchProvider->deleteSearchDocumentsByTypeId('i_some_type'); } catch (ConfigException $e) { - $this->assertEquals("Search document id 'i_some_type' not in configuration for store 'tripod_php_testing'", $e->getMessage()); + $this->assertSame("Search document id 'i_some_type' not in configuration for store 'tripod_php_testing'", $e->getMessage()); } // search document count should remain same, because we expect that there was nothing to delete @@ -536,7 +537,7 @@ public function testDeleteSearchDocumentsByTypeIdDeletesNothingWhenNoMatchFound( $this->assertEquals(13, $newSearchDocumentCount, 'Should have generated 12 search documents, because there was no match to remove'); } - public function testDeleteSearchDocumentsByTypeIdDeleteAllMatchingDocuments() + public function testDeleteSearchDocumentsByTypeIdDeleteAllMatchingDocuments(): void { // first, assert that there are only 12 based on the data we loaded into tripod $actualSearchDocumentCount = $this->getCountForSearchSpecs($this->tripod); @@ -550,7 +551,7 @@ public function testDeleteSearchDocumentsByTypeIdDeleteAllMatchingDocuments() $mockSearchProvider->expects($this->once()) ->method('getSearchDocumentSpecification') ->with('i_search_resource') - ->will($this->returnValue(['i_search_resource' => []])); + ->willReturn(['i_search_resource' => []]); $mockSearchProvider->deleteSearchDocumentsByTypeId('i_search_resource'); @@ -560,7 +561,7 @@ public function testDeleteSearchDocumentsByTypeIdDeleteAllMatchingDocuments() $this->assertEquals(0, $newSearchDocumentCount, 'Should have 0 search documents after removing all matching documents'); } - public function testDeleteSearchDocumentsByTypeIdDoNotDeleteNonMatchingDocuments() + public function testDeleteSearchDocumentsByTypeIdDoNotDeleteNonMatchingDocuments(): void { // first, assert that there are only 12 based on the data we loaded into tripod $actualSearchDocumentCount = $this->getCountForSearchSpecs($this->tripod); @@ -577,7 +578,7 @@ public function testDeleteSearchDocumentsByTypeIdDoNotDeleteNonMatchingDocuments $this->getTripodCollection($this->tripod)->updateOne($id, ['$set' => $newData]); // reindex - $this->indexer->generateAndIndexSearchDocuments('http://talisaspire.com/resources/doc1', 'http://talisaspire.com/', $this->tripod->getPodName()); + $this->searchIndexer->generateAndIndexSearchDocuments('http://talisaspire.com/resources/doc1', 'http://talisaspire.com/', $this->tripod->getPodName()); // assert that there are now 13 documents after adding new document to collection $updatedSearchDocumentCount = $this->getCountForSearchSpecs($this->tripod); @@ -591,7 +592,7 @@ public function testDeleteSearchDocumentsByTypeIdDoNotDeleteNonMatchingDocuments $mockSearchProvider->expects($this->once()) ->method('getSearchDocumentSpecification') ->with('i_search_resource') - ->will($this->returnValue(['i_search_resource' => []])); + ->willReturn(['i_search_resource' => []]); $mockSearchProvider->deleteSearchDocumentsByTypeId('i_search_resource'); @@ -601,7 +602,7 @@ public function testDeleteSearchDocumentsByTypeIdDoNotDeleteNonMatchingDocuments $this->assertEquals(1, $newSearchDocumentCount, "Should have 1 search documents since there is one search document with 'i_search_list' type that does not match delete type."); } - public function testCountSearchDocuments() + public function testCountSearchDocuments(): void { $tripod = $this->getMockBuilder(Driver::class) ->setConstructorArgs(['CBD_testing', 'tripod_php_testing']) @@ -619,23 +620,23 @@ public function testCountSearchDocuments() $search->expects($this->once()) ->method('getCollectionForSearchSpec') ->with('i_search_list') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('count') ->with(['_id.type' => 'i_search_list']) - ->will($this->returnValue(21)); + ->willReturn(21); $this->assertEquals(21, $search->count('i_search_list')); } - public function testCountSearchDocumentsWithFilters() + public function testCountSearchDocumentsWithFilters(): void { $tripod = $this->getMockBuilder(Driver::class) ->setConstructorArgs(['CBD_testing', 'tripod_php_testing']) ->getMock(); - $filters = ['_cts' => ['$lte' => new UTCDateTime(null)]]; + $filters = ['_cts' => ['$lte' => new UTCDateTime()]]; $query = array_merge(['_id.type' => 'i_search_list'], $filters); $collection = $this->getMockBuilder(Collection::class) ->setConstructorArgs([new Manager(), 'db', 'coll']) @@ -649,17 +650,17 @@ public function testCountSearchDocumentsWithFilters() $search->expects($this->once()) ->method('getCollectionForSearchSpec') ->with('i_search_list') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('count') ->with($query) - ->will($this->returnValue(89)); + ->willReturn(89); $this->assertEquals(89, $search->count('i_search_list', $filters)); } - public function testDeleteSearchDocumentsBySearchId() + public function testDeleteSearchDocumentsBySearchId(): void { $tripod = $this->getMockBuilder(Driver::class) ->setConstructorArgs(['CBD_testing', 'tripod_php_testing']) @@ -677,7 +678,7 @@ public function testDeleteSearchDocumentsBySearchId() $deleteResult->expects($this->once()) ->method('getDeletedCount') - ->will($this->returnValue(9)); + ->willReturn(9); $search = $this->getMockBuilder(MongoSearchProvider::class) ->onlyMethods(['getCollectionForSearchSpec', 'getSearchDocumentSpecification']) @@ -687,24 +688,24 @@ public function testDeleteSearchDocumentsBySearchId() $search->expects($this->once()) ->method('getSearchDocumentSpecification') ->with('i_search_list') - ->will($this->returnValue(['_id' => 'i_search_list'])); + ->willReturn(['_id' => 'i_search_list']); $search->expects($this->once()) ->method('getCollectionForSearchSpec') ->with('i_search_list') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('deleteMany') ->with(['_id.type' => 'i_search_list']) - ->will($this->returnValue($deleteResult)); + ->willReturn($deleteResult); $this->assertEquals(9, $search->deleteSearchDocumentsByTypeId('i_search_list')); } - public function testDeleteSearchDocumentsBySearchIdWithTimestamp() + public function testDeleteSearchDocumentsBySearchIdWithTimestamp(): void { - $timestamp = new UTCDateTime(null); + $timestamp = new UTCDateTime(); $query = [ '_id.type' => 'i_search_list', @@ -730,7 +731,7 @@ public function testDeleteSearchDocumentsBySearchIdWithTimestamp() $deleteResult->expects($this->once()) ->method('getDeletedCount') - ->will($this->returnValue(9)); + ->willReturn(9); $search = $this->getMockBuilder(MongoSearchProvider::class) ->onlyMethods(['getCollectionForSearchSpec', 'getSearchDocumentSpecification']) @@ -740,17 +741,17 @@ public function testDeleteSearchDocumentsBySearchIdWithTimestamp() $search->expects($this->once()) ->method('getSearchDocumentSpecification') ->with('i_search_list') - ->will($this->returnValue(['_id' => 'i_search_list'])); + ->willReturn(['_id' => 'i_search_list']); $search->expects($this->once()) ->method('getCollectionForSearchSpec') ->with('i_search_list') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('deleteMany') ->with($query) - ->will($this->returnValue($deleteResult)); + ->willReturn($deleteResult); $this->assertEquals(9, $search->deleteSearchDocumentsByTypeId('i_search_list', $timestamp)); } diff --git a/test/unit/mongo/MongoTransactionLogTest.php b/test/unit/mongo/MongoTransactionLogTest.php index 66348164..cf47e329 100644 --- a/test/unit/mongo/MongoTransactionLogTest.php +++ b/test/unit/mongo/MongoTransactionLogTest.php @@ -1,5 +1,7 @@ tripodTransactionLog = new TransactionLog(); $this->tripodTransactionLog->purgeAllTransactions(); + $this->tripod->setTransactionLog($this->tripodTransactionLog); } - public function testReplayLogSimpleChangesSinglePropertyOnExistingDocument() + public function testReplayLogSimpleChangesSinglePropertyOnExistingDocument(): void { $uri = 'http://talisaspire.com/examples/1'; @@ -52,6 +55,7 @@ public function testReplayLogSimpleChangesSinglePropertyOnExistingDocument() $originalGraph->add_resource_triple($uri, $originalGraph->qname_to_uri('rdf:type'), $originalGraph->qname_to_uri('acorn:Resource')); $originalGraph->add_literal_triple($uri, $originalGraph->qname_to_uri('searchterms:title'), 'Physics 3rd Edition'); $originalGraph->add_literal_triple($uri, $originalGraph->qname_to_uri('searchterms:author'), 'Joe Bloggs'); + $this->tripod->saveChanges(new ExtendedGraph(), $originalGraph, 'http://talisaspire.com/'); // jsut confirm the values we just added were set in the store $oG = $this->tripod->describeResource($uri); @@ -94,13 +98,14 @@ public function testReplayLogSimpleChangesSinglePropertyOnExistingDocument() $this->assertDocumentVersion(['r' => $uri, 'c' => 'http://talisaspire.com/'], 1); } - public function testReplayLogSimpleAddSingleNewDocument() + public function testReplayLogSimpleAddSingleNewDocument(): void { $uri = 'http://example.com/resources/1'; $g = new MongoGraph(); $g->add_resource_triple($uri, $g->qname_to_uri('rdf:type'), $g->qname_to_uri('acorn:Resource')); $g->add_literal_triple($uri, $g->qname_to_uri('dct:title'), 'wibble'); + $this->tripod->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/', 'something new'); // make sure the new entity was saved correctly @@ -124,13 +129,14 @@ public function testReplayLogSimpleAddSingleNewDocument() $this->assertDocumentVersion(['r' => $uri, 'c' => 'http://talisaspire.com/'], 0); } - public function testReplayLogSimpleAddSingleNewDocumentNamespacedResourceAndContext() + public function testReplayLogSimpleAddSingleNewDocumentNamespacedResourceAndContext(): void { $uri = 'http://basedata.com/b/3'; $g = new MongoGraph(); $g->add_resource_triple($uri, $g->qname_to_uri('rdf:type'), $g->qname_to_uri('acorn:Resource')); $g->add_literal_triple($uri, $g->qname_to_uri('dct:title'), 'wibble'); + $this->tripod->saveChanges(new MongoGraph(), $g, 'http://basedata.com/b/DefaultGraph', 'something new'); // make sure the new entity was saved correctly @@ -160,7 +166,7 @@ public function testReplayLogSimpleAddSingleNewDocumentNamespacedResourceAndCont * We then drop the collection and re-add the original document. * We replay the transaction log to ensure that it does physically remove the document. */ - public function testReplayLogSimpleDeletesSingleEntity() + public function testReplayLogSimpleDeletesSingleEntity(): void { // document is added via setup() method $uri = 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA'; @@ -194,7 +200,7 @@ public function testReplayLogSimpleDeletesSingleEntity() * Since we step backwards through the transaction log. This test verifies that if a more recent * transaction deleted an entity then an older transaction should not re-introduce it. */ - public function testReplayLogSimpleDeletesSingleEntityWithNoBaseData() + public function testReplayLogSimpleDeletesSingleEntityWithNoBaseData(): void { // document is added via setup() method $uri = 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA'; @@ -202,8 +208,10 @@ public function testReplayLogSimpleDeletesSingleEntityWithNoBaseData() // Save a change to entity $oG = new MongoGraph(); $oG->add_literal_triple($uri, $oG->qname_to_uri('searchterms:title'), 'Physics 3rd Edition'); + $nG = new MongoGraph(); $nG->add_literal_triple($uri, $oG->qname_to_uri('searchterms:title'), 'A different title'); + $this->tripod->saveChanges($oG, $nG, 'http://talisaspire.com/'); $this->assertDocumentVersion(['r' => $uri, 'c' => 'http://talisaspire.com/'], 1); @@ -225,7 +233,7 @@ public function testReplayLogSimpleDeletesSingleEntityWithNoBaseData() $this->assertDocumentHasBeenDeleted(['r' => $uri, 'c' => 'http://talisaspire.com/']); } - public function testReplayTransactionsOverSeveralDocumentsAddingAndUpdating() + public function testReplayTransactionsOverSeveralDocumentsAddingAndUpdating(): void { // base documents added via setup() method $uri_1 = 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA'; @@ -236,6 +244,7 @@ public function testReplayTransactionsOverSeveralDocumentsAddingAndUpdating() $oG->add_literal_triple($uri_1, $oG->qname_to_uri('searchterms:title'), 'Physics 3rd Edition'); $oG->add_literal_triple($uri_2, $oG->qname_to_uri('searchterms:discipline'), 'physics'); $oG->add_resource_triple($uri_2, $oG->qname_to_uri('dct:subject'), 'http://talisaspire.com/disciplines/physics'); + $nG = new MongoGraph(); $nG->add_literal_triple($uri_1, $nG->qname_to_uri('searchterms:title'), 'History of UK'); $nG->add_literal_triple($uri_2, $nG->qname_to_uri('searchterms:discipline'), 'history'); @@ -258,6 +267,7 @@ public function testReplayTransactionsOverSeveralDocumentsAddingAndUpdating() // change same entity again: $nG2 = new MongoGraph(); $nG2->add_literal_triple($uri_2, $nG2->qname_to_uri('searchterms:title'), 'some test title'); + $nG3 = new MongoGraph(); $nG3->add_literal_triple($uri_2, $nG2->qname_to_uri('searchterms:title'), 'a different title'); @@ -271,6 +281,7 @@ public function testReplayTransactionsOverSeveralDocumentsAddingAndUpdating() // change same entity again: $nG2 = new MongoGraph(); $nG2->add_literal_triple($uri_1, $nG2->qname_to_uri('searchterms:title'), 'History of UK'); + $nG3 = new MongoGraph(); $nG3->add_literal_triple($uri_1, $nG2->qname_to_uri('searchterms:title'), 'History of the United Kingdom'); @@ -298,7 +309,7 @@ public function testReplayTransactionsOverSeveralDocumentsAddingAndUpdating() $this->assertHasResourceTriple($resource2, $uri_2, $resource1->qname_to_uri('dct:subject'), 'http://talisaspire.com/disciplines/history'); } - public function testReplayTransactionsAddingAndDeleting() + public function testReplayTransactionsAddingAndDeleting(): void { $uri = 'http://example.com/resources/1'; $g = new MongoGraph(); @@ -337,7 +348,7 @@ public function testReplayTransactionsAddingAndDeleting() * This test addes a set of precanned transactions to the transaction log, and then verifies that * only the transactions $gte the given date are replayed. */ - public function testReplayTransactionsFromAGivenDate() + public function testReplayTransactionsFromAGivenDate(): void { $transaction_1 = $this->buildTransactionDocument(1, 'http://example.com/resources/1', '2013-01-21T13:00:00.000Z', '2013-01-21T13:01:00.000Z', 0); $transaction_2 = $this->buildTransactionDocument(2, 'http://example.com/resources/2', '2013-01-21T13:00:00.000Z', '2013-01-21T13:02:00.000Z', 0); @@ -373,7 +384,7 @@ public function testReplayTransactionsFromAGivenDate() * This test addes a set of precanned transactions to the transaction log, and then verifies that * only the transactions $gte the given date are replayed. */ - public function testReplayTransactionsBetweenTwoDates() + public function testReplayTransactionsBetweenTwoDates(): void { $transaction_1 = $this->buildTransactionDocument(1, 'http://example.com/resources/1', '2013-01-21T13:00:00.000Z', '2013-01-21T13:01:00.000Z', 0); $transaction_2 = $this->buildTransactionDocument(2, 'http://example.com/resources/2', '2013-01-21T13:00:00.000Z', '2013-01-21T13:02:00.000Z', 0); @@ -405,7 +416,7 @@ public function testReplayTransactionsBetweenTwoDates() $this->assertFalse($g->has_triples_about('http://example.com/resources/5'), 'Should not contain triples about /resources/5'); } - public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully() + public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully(): void { // STEP 1 $uri = 'http://example.com/resources/1'; @@ -425,10 +436,10 @@ public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully() $mTripodUpdate->expects($this->atLeastOnce()) ->method('getUniqId') - ->will($this->returnValue(1)); + ->willReturn(1); $mTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mTripodUpdate)); + ->willReturn($mTripodUpdate); $mTripod->setTransactionLog($this->tripodTransactionLog); $mTripod->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/'); @@ -438,18 +449,14 @@ public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully() $transactionDocument = $this->getDocument($transactionId, $this->tripod, true); $this->assertEquals($transactionId, $transactionDocument['_id'], 'transtion should have the mocked id we injected'); $this->assertEquals('completed', $transactionDocument['status'], 'status of the transaction should be completed'); - $this->assertEquals(1, count($transactionDocument['originalCBDs']), 'There should only be on CBD in the originalCBs collection'); + $this->assertCount(1, $transactionDocument['originalCBDs'], 'There should only be on CBD in the originalCBs collection'); $this->assertTransactionDate($transactionDocument, 'startTime'); $this->assertTransactionDate($transactionDocument, 'endTime'); - $this->assertTrue(isset($transactionDocument['changes']), 'Transaction should contain changes'); + $this->assertArrayHasKey('changes', $transactionDocument, 'Transaction should contain changes'); $this->assertChangesForGivenSubject($transactionDocument['changes'], $uri, 2, 0); $expectedCBD = ['_id' => ['r' => 'http://example.com/resources/1', 'c' => 'http://talisaspire.com/']]; $actualCBD = $transactionDocument['originalCBDs'][0]; $this->assertEquals($expectedCBD, $actualCBD, 'CBD in transaction should match our expected value exactly'); - - // STEP 2 - // update the same entity with an addition - $mTripod = null; $mTripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) ->setConstructorArgs(['CBD_testing', 'tripod_php_testing']) @@ -461,25 +468,26 @@ public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully() $mTripodUpdate->expects($this->atLeastOnce()) ->method('getUniqId') - ->will($this->returnValue(2)); + ->willReturn(2); $mTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mTripodUpdate)); + ->willReturn($mTripodUpdate); $mTripod->setTransactionLog($this->tripodTransactionLog); $nG = new MongoGraph(); $nG->add_graph($g); $nG->add_literal_triple($uri, $g->qname_to_uri('dct:title'), 'another title'); + $mTripod->saveChanges($g, $nG, 'http://talisaspire.com/'); // assert this transaction is correct $transactionId = 'transaction_2'; $transactionDocument = $this->getDocument($transactionId, $this->tripod, true); $this->assertEquals($transactionId, $transactionDocument['_id'], 'transtion should have the mocked id we injected'); $this->assertEquals('completed', $transactionDocument['status'], 'status of the transaction should be completed'); - $this->assertEquals(1, count($transactionDocument['originalCBDs']), 'There should only be on CBD in the originalCBs collection'); + $this->assertCount(1, $transactionDocument['originalCBDs'], 'There should only be on CBD in the originalCBs collection'); $this->assertTransactionDate($transactionDocument, 'startTime'); $this->assertTransactionDate($transactionDocument, 'endTime'); - $this->assertTrue(isset($transactionDocument['changes']), 'Transaction should contain changes'); + $this->assertArrayHasKey('changes', $transactionDocument, 'Transaction should contain changes'); $this->assertChangesForGivenSubject($transactionDocument['changes'], $uri, 1, 0); $expectedCBD = [ '_id' => ['r' => 'http://example.com/resources/1', 'c' => 'http://talisaspire.com/'], @@ -498,10 +506,6 @@ public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully() ksort($expectedCBD); $this->assertEquals($expectedCBD, $actualCBD, 'CBD in transaction should match our expected value exactly'); - - // STEP 3 - // update the same entity with a removal - $mTripod = null; $mTripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) ->setConstructorArgs(['CBD_testing', 'tripod_php_testing']) @@ -513,25 +517,26 @@ public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully() $mTripodUpdate->expects($this->atLeastOnce()) ->method('getUniqId') - ->will($this->returnValue(3)); + ->willReturn(3); $mTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mTripodUpdate)); + ->willReturn($mTripodUpdate); $mTripod->setTransactionLog($this->tripodTransactionLog); $g = new MongoGraph(); $g->add_graph($nG); $g->remove_literal_triple($uri, $g->qname_to_uri('dct:title'), 'another title'); + $mTripod->saveChanges($nG, $g, 'http://talisaspire.com/'); // assert this transaction $transactionId = 'transaction_3'; $transactionDocument = $this->getDocument($transactionId, $this->tripod, true); $this->assertEquals($transactionId, $transactionDocument['_id'], 'transtion should have the mocked id we injected'); $this->assertEquals('completed', $transactionDocument['status'], 'status of the transaction should be completed'); - $this->assertEquals(1, count($transactionDocument['originalCBDs']), 'There should only be on CBD in the originalCBs collection'); + $this->assertCount(1, $transactionDocument['originalCBDs'], 'There should only be on CBD in the originalCBs collection'); $this->assertTransactionDate($transactionDocument, 'startTime'); $this->assertTransactionDate($transactionDocument, 'endTime'); - $this->assertTrue(isset($transactionDocument['changes']), 'Transaction should contain changes'); + $this->assertArrayHasKey('changes', $transactionDocument, 'Transaction should contain changes'); $this->assertChangesForGivenSubject($transactionDocument['changes'], $uri, 0, 1); $expectedCBD = [ '_id' => ['r' => 'http://example.com/resources/1', 'c' => 'http://talisaspire.com/'], @@ -550,13 +555,14 @@ public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully() $this->assertEquals($expectedCBD, $actualCBD, 'CBD in transaction should match our expected value exactly'); } - public function testTransactionIsLoggedCorrectlyWhenSaveFails() + public function testTransactionIsLoggedCorrectlyWhenSaveFails(): void { $uri = 'http://example.com/resources/1'; // save a new entity, and retrieve it $g = new MongoGraph(); $g->add_resource_triple($uri, $g->qname_to_uri('rdf:type'), $g->qname_to_uri('acorn:Resource')); $g->add_literal_triple($uri, $g->qname_to_uri('dct:title'), 'wibble'); + $mTripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) ->setConstructorArgs(['CBD_testing', 'tripod_php_testing']) @@ -568,18 +574,13 @@ public function testTransactionIsLoggedCorrectlyWhenSaveFails() $mTripodUpdate->expects($this->atLeastOnce()) ->method('getUniqId') - ->will($this->returnValue(1)); + ->willReturn(1); $mTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mTripodUpdate)); + ->willReturn($mTripodUpdate); $mTripod->setTransactionLog($this->tripodTransactionLog); $mTripod->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/'); - - // STEP 2 - // now attempt to update the entity but throw an exception in applyChangeset - // this should cause the save to fail, and this should be reflected in the transaction log - $mTripod = null; $mTripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) ->setConstructorArgs(['CBD_testing', 'tripod_php_testing']) @@ -591,14 +592,14 @@ public function testTransactionIsLoggedCorrectlyWhenSaveFails() $mTripodUpdate->expects($this->atLeastOnce()) ->method('getUniqId') - ->will($this->returnValue(2)); + ->willReturn(2); $mTripodUpdate->expects($this->atLeastOnce()) ->method('applyChangeSet') - ->will($this->throwException(new Exception('exception thrown by mock test'))); + ->willThrowException(new Exception('exception thrown by mock test')); $mTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mTripodUpdate)); + ->willReturn($mTripodUpdate); $mTripod->setTransactionLog($this->tripodTransactionLog); $nG = new MongoGraph(); @@ -617,10 +618,10 @@ public function testTransactionIsLoggedCorrectlyWhenSaveFails() $transactionDocument = $this->getDocument($transactionId, $this->tripod, true); $this->assertEquals($transactionId, $transactionDocument['_id'], 'transtion should have the mocked id we injected'); $this->assertEquals('failed', $transactionDocument['status'], 'status of the transaction should be failed'); - $this->assertEquals(1, count($transactionDocument['originalCBDs']), 'There should only be on CBD in the originalCBs collection'); + $this->assertCount(1, $transactionDocument['originalCBDs'], 'There should only be on CBD in the originalCBs collection'); $this->assertTransactionDate($transactionDocument, 'startTime'); $this->assertTransactionDate($transactionDocument, 'failedTime'); - $this->assertTrue(isset($transactionDocument['changes']), 'Transaction should contain changes'); + $this->assertArrayHasKey('changes', $transactionDocument, 'Transaction should contain changes'); $this->assertChangesForGivenSubject($transactionDocument['changes'], $uri, 1, 0); $expectedCBD = [ '_id' => ['r' => 'http://example.com/resources/1', 'c' => 'http://talisaspire.com/'], @@ -643,7 +644,7 @@ public function testTransactionIsLoggedCorrectlyWhenSaveFails() $this->assertNotEmpty($transactionDocument['error']['trace'], 'The transaction log have a non empty error trace'); } - public function testTransactionsLoggedCorrectlyFromMultipleTripods() + public function testTransactionsLoggedCorrectlyFromMultipleTripods(): void { // Create two tripods onto different collection/dbname and make them use the same transaction log $tripod1 = $this->getMockBuilder(Driver::class) @@ -679,8 +680,10 @@ public function testTransactionsLoggedCorrectlyFromMultipleTripods() // change one of the documents $oG = new MongoGraph(); $oG->add_literal_triple($uri, $g->qname_to_uri('searchterms:title'), 'Some title'); + $nG = new MongoGraph(); $nG->add_literal_triple($uri, $g->qname_to_uri('searchterms:title'), 'Changed title'); + $tripod1->saveChanges($oG, $nG, 'http://talisaspire.com/'); // assert the documents and transaction count @@ -692,7 +695,7 @@ public function testTransactionsLoggedCorrectlyFromMultipleTripods() /** * This test ensures that if insertTransaction returns an error, then a Exception is actually thrown. */ - public function testCreateNewTransactionThrowsExceptionIfInsertFails() + public function testCreateNewTransactionThrowsExceptionIfInsertFails(): void { $mockInsert = $this->getMockBuilder(InsertOneResult::class) ->disableOriginalConstructor() @@ -701,7 +704,7 @@ public function testCreateNewTransactionThrowsExceptionIfInsertFails() $mockInsert ->expects($this->once()) ->method('isAcknowledged') - ->will($this->returnValue(false)); + ->willReturn(false); $mockTransactionLog = $this->getMockBuilder(TransactionLog::class) ->onlyMethods(['insertTransaction']) @@ -709,7 +712,7 @@ public function testCreateNewTransactionThrowsExceptionIfInsertFails() ->getMock(); $mockTransactionLog->expects($this->once()) ->method('insertTransaction') - ->will($this->returnValue($mockInsert)); + ->willReturn($mockInsert); try { $mockTransactionLog->createNewTransaction('transaction_1', [], [], 'mydb', 'mycollection'); @@ -722,18 +725,16 @@ public function testCreateNewTransactionThrowsExceptionIfInsertFails() /** * helper method. * - * @param string $id * @param string $subjectOfChange * @param string $startTime * @param string $endTime * @param int $_version - * - * @return array + * @return array */ - protected function buildTransactionDocument($id, $subjectOfChange, $startTime, $endTime, $_version) + protected function buildTransactionDocument(string $id, $subjectOfChange, $startTime, $endTime, $_version): array { return [ - '_id' => "transaction_{$id}", + '_id' => 'transaction_' . $id, 'changes' => [ [ '_id' => ['r' => '_:cs0', 'c' => 'http://talisaspire.com/'], diff --git a/test/unit/mongo/MongoTripodComputedFieldsTest.php b/test/unit/mongo/MongoTripodComputedFieldsTest.php index d2df981a..6a8c5e75 100644 --- a/test/unit/mongo/MongoTripodComputedFieldsTest.php +++ b/test/unit/mongo/MongoTripodComputedFieldsTest.php @@ -1,5 +1,7 @@ 't_conditional_creators', @@ -81,7 +83,7 @@ public function testConditionalComputedFieldWithDates() $collection->drop(); } - public function testConditionalComputedField() + public function testConditionalComputedField(): void { $tableSpec = [ '_id' => 't_conditional_creators', @@ -145,7 +147,7 @@ public function testConditionalComputedField() $collection->drop(); } - public function testNestedConditionalComputedField() + public function testNestedConditionalComputedField(): void { $tableSpec = [ '_id' => 't_conditional_creators', @@ -229,7 +231,7 @@ public function testNestedConditionalComputedField() $collection->drop(); } - public function testReplaceComputedField() + public function testReplaceComputedField(): void { $tableSpec = [ '_id' => 't_replace_type', @@ -308,7 +310,7 @@ public function testReplaceComputedField() $collection->drop(); } - public function testArithmeticComputedField() + public function testArithmeticComputedField(): void { $tableSpec = [ '_id' => 't_creator_count', @@ -404,7 +406,7 @@ public function testArithmeticComputedField() $collection->drop(); } - public function testNestArithmeticInConditionalIf() + public function testNestArithmeticInConditionalIf(): void { $tableSpec = [ '_id' => 't_conditional_with_nested_arithmetic', @@ -444,7 +446,7 @@ public function testNestArithmeticInConditionalIf() $collection->drop(); } - public function testNestConditionalInArithmeticFunction() + public function testNestConditionalInArithmeticFunction(): void { $tableSpec = [ '_id' => 't_arithmetic_with_nested_conditional', @@ -492,7 +494,7 @@ public function testNestConditionalInArithmeticFunction() $collection->drop(); } - protected function generateUniqueTableId($prefix) + protected function generateUniqueTableId($prefix): string { return uniqid($prefix); } diff --git a/test/unit/mongo/MongoTripodConfigUnitTest.php b/test/unit/mongo/MongoTripodConfigUnitTest.php index fe23cd20..d8fee9b8 100644 --- a/test/unit/mongo/MongoTripodConfigUnitTest.php +++ b/test/unit/mongo/MongoTripodConfigUnitTest.php @@ -1,5 +1,7 @@ tripodConfig = Config::getInstance(); } - public function testGetInstanceThrowsExceptionIfSetInstanceNotCalledFirst() + public function testGetInstanceThrowsExceptionIfSetInstanceNotCalledFirst(): void { // to test that the instance throws an exception if it is called before calling setConfig // i first have to destroy the instance that is created in the setUp() method of our test suite. @@ -37,10 +39,10 @@ public function testGetInstanceThrowsExceptionIfSetInstanceNotCalledFirst() Config::getInstance(); } - public function testNamespaces() + public function testNamespaces(): void { $ns = $this->tripodConfig->getNamespaces(); - $this->assertEquals(16, count($ns), 'Incorrect number of namespaces'); + $this->assertCount(16, $ns, 'Incorrect number of namespaces'); $expectedNs = []; @@ -63,16 +65,16 @@ public function testNamespaces() $this->assertEquals($expectedNs, $ns, 'Incorrect namespaces'); } - public function testTConfig() + public function testTConfig(): void { $config = Config::getInstance(); - $cfg = Config::getConfig(); + Config::getConfig(); $tConfig = $config->getTransactionLogConfig(); $this->assertEquals('tripod_php_testing', $tConfig['database']); $this->assertEquals('transaction_log', $tConfig['collection']); } - public function testCardinality() + public function testCardinality(): void { $cardinality = $this->tripodConfig->getCardinality('tripod_php_testing', 'CBD_testing', 'dct:created'); $this->assertEquals(1, $cardinality, 'Expected cardinality of 1 for dct:created'); @@ -81,7 +83,7 @@ public function testCardinality() $this->assertEquals(-1, $cardinality, 'Expected cardinality of 1 for random:property'); } - public function testCompoundIndexAllArraysThrowsException() + public function testCompoundIndexAllArraysThrowsException(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Compound index IllegalCompoundIndex has more than one field with cardinality > 1 - mongo will not be able to build this index'); @@ -114,18 +116,18 @@ public function testCompoundIndexAllArraysThrowsException() ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testSearchConfig() + public function testSearchConfig(): void { $config = Config::getInstance(); $this->assertEquals(MongoSearchProvider::class, $config->getSearchProviderClassName('tripod_php_testing')); - $this->assertEquals(3, count($config->getSearchDocumentSpecifications('tripod_php_testing'))); + $this->assertCount(3, $config->getSearchDocumentSpecifications('tripod_php_testing')); } - public function testCardinalityRuleWithNoNamespace() + public function testCardinalityRuleWithNoNamespace(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage("Cardinality 'foo:bar' does not have the namespace defined"); @@ -152,10 +154,10 @@ public function testCardinalityRuleWithNoNamespace() ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testGetSearchDocumentSpecificationsByType() + public function testGetSearchDocumentSpecificationsByType(): void { $expectedSpec = [ [ @@ -201,7 +203,7 @@ public function testGetSearchDocumentSpecificationsByType() $this->assertEquals($expectedSpec, $actualSpec); } - public function testGetSearchDocumentSpecificationsById() + public function testGetSearchDocumentSpecificationsById(): void { $expectedSpec = [ @@ -246,14 +248,14 @@ public function testGetSearchDocumentSpecificationsById() $this->assertEquals($expectedSpec, $actualSpec); } - public function testGetSearchDocumentSpecificationsWhereNoneExists() + public function testGetSearchDocumentSpecificationsWhereNoneExists(): void { $expectedSpec = []; $actualSpec = Config::getInstance()->getSearchDocumentSpecifications('something:doesntexist'); $this->assertEquals($expectedSpec, $actualSpec); } - public function testViewSpecCountWithoutTTLThrowsException() + public function testViewSpecCountWithoutTTLThrowsException(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Aggregate function counts exists in spec, but no TTL defined'); @@ -290,10 +292,10 @@ public function testViewSpecCountWithoutTTLThrowsException() ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testViewSpecCountNestedInJoinWithoutTTLThrowsException() + public function testViewSpecCountNestedInJoinWithoutTTLThrowsException(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Aggregate function counts exists in spec, but no TTL defined'); @@ -333,10 +335,10 @@ public function testViewSpecCountNestedInJoinWithoutTTLThrowsException() ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testTableSpecNestedCountWithoutPropertyThrowsException() + public function testTableSpecNestedCountWithoutPropertyThrowsException(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Count spec does not contain property'); @@ -374,10 +376,10 @@ public function testTableSpecNestedCountWithoutPropertyThrowsException() ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testTableSpecNested2ndLevelCountWithoutFieldNameThrowsException() + public function testTableSpecNested2ndLevelCountWithoutFieldNameThrowsException(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Count spec does not contain fieldName'); @@ -418,10 +420,10 @@ public function testTableSpecNested2ndLevelCountWithoutFieldNameThrowsException( ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testTableSpecFieldWithoutFieldName() + public function testTableSpecFieldWithoutFieldName(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Field spec does not contain fieldName'); @@ -456,10 +458,10 @@ public function testTableSpecFieldWithoutFieldName() ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testTableSpecFieldWithoutPredicates() + public function testTableSpecFieldWithoutPredicates(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Field spec does not contain predicates'); @@ -494,10 +496,10 @@ public function testTableSpecFieldWithoutPredicates() ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testTableSpecCountWithoutProperty() + public function testTableSpecCountWithoutProperty(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Count spec does not contain property'); @@ -532,10 +534,10 @@ public function testTableSpecCountWithoutProperty() ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testTableSpecCountWithoutFieldName() + public function testTableSpecCountWithoutFieldName(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Count spec does not contain fieldName'); @@ -570,10 +572,10 @@ public function testTableSpecCountWithoutFieldName() ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testTableSpecCountWithoutPropertyAsAString() + public function testTableSpecCountWithoutPropertyAsAString(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Count spec property was not a string'); @@ -609,10 +611,10 @@ public function testTableSpecCountWithoutPropertyAsAString() ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } - public function testConfigWithoutDefaultNamespaceThrowsException() + public function testConfigWithoutDefaultNamespaceThrowsException(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage('Mandatory config key [defaultContext] is missing from config'); @@ -650,14 +652,14 @@ public function testConfigWithoutDefaultNamespaceThrowsException() ], ]; Config::setConfig($config); - $mtc = Config::getInstance(); + Config::getInstance(); } /** * the indexesGroupedByCollection method should not only return each of the indexes that are defined explicitly in the config.json, * but also include indexes that are inserted by Config object because they are needed by tripod. */ - public function testGetIndexesGroupedByCollection() + public function testGetIndexesGroupedByCollection(): void { $indexSpecs = Config::getInstance()->getIndexesGroupedByCollection('tripod_php_testing'); @@ -683,7 +685,7 @@ public function testGetIndexesGroupedByCollection() $this->assertEquals(['value._graphs.sioc:has_container.u' => 1, 'value._graphs.sioc:topic.u' => 1], $indexSpecs[VIEWS_COLLECTION]['rs1'][0]); } - public function testGetReplicaSetName() + public function testGetReplicaSetName(): void { $config = []; $config['defaultContext'] = 'http://talisaspire.com/'; @@ -728,7 +730,7 @@ public function testGetReplicaSetName() $this->assertNull($mtc->getReplicaSetName('testing_2')); } - public function testGetReplicaSetNameFromConnectionString() + public function testGetReplicaSetNameFromConnectionString(): void { Config::setConfig([ 'defaultContext' => 'http://talisaspire.com/', @@ -752,7 +754,7 @@ public function testGetReplicaSetNameFromConnectionString() $this->assertEquals(null, $mtc->getReplicaSetName('rs2')); } - public function testGetViewSpecification() + public function testGetViewSpecification(): void { $expectedVspec = [ '_id' => 'v_resource_full', @@ -788,7 +790,7 @@ public function testGetViewSpecification() $this->assertNull($vspec); } - public function testGetTableSpecification() + public function testGetTableSpecification(): void { $expectedTspec = [ '_id' => 't_resource', @@ -825,7 +827,7 @@ public function testGetTableSpecification() $this->assertNull($tspec); } - public function testSearchConfigNotPresent() + public function testSearchConfigNotPresent(): void { $config = []; $config['defaultContext'] = 'http://talisaspire.com/'; @@ -851,12 +853,12 @@ public function testSearchConfigNotPresent() $this->assertEquals([], $mtc->getSearchDocumentSpecifications('tripod_php_testing')); } - public function testGetAllTypesInSpecifications() + public function testGetAllTypesInSpecifications(): void { $types = $this->tripodConfig->getAllTypesInSpecifications('tripod_php_testing'); - $this->assertEquals( + $this->assertCount( 12, - count($types), + $types, 'There should be 12 types based on the configured view, table and search specifications in config.json' ); $expectedValues = [ @@ -875,14 +877,14 @@ public function testGetAllTypesInSpecifications() ]; foreach ($expectedValues as $expected) { - $this->assertContains($expected, $types, "List of types should have contained {$expected}"); + $this->assertContains($expected, $types, 'List of types should have contained ' . $expected); } } - public function testGetPredicatesForTableSpec() + public function testGetPredicatesForTableSpec(): void { $predicates = $this->tripodConfig->getDefinedPredicatesInSpec('tripod_php_testing', 't_users'); - $this->assertEquals(6, count($predicates), 'There should be 6 predicates defined in t_users in config.json'); + $this->assertCount(6, $predicates, 'There should be 6 predicates defined in t_users in config.json'); $expectedValues = [ 'rdf:type', 'foaf:firstName', @@ -893,14 +895,14 @@ public function testGetPredicatesForTableSpec() ]; foreach ($expectedValues as $expected) { - $this->assertContains($expected, $predicates, "List of predicates should have contained {$expected}"); + $this->assertContains($expected, $predicates, 'List of predicates should have contained ' . $expected); } } - public function testGetPredicatesForSearchDocSpec() + public function testGetPredicatesForSearchDocSpec(): void { $predicates = $this->tripodConfig->getDefinedPredicatesInSpec('tripod_php_testing', 'i_search_list'); - $this->assertEquals(6, count($predicates), 'There should be 6 predicates defined in i_search_list in config.json'); + $this->assertCount(6, $predicates, 'There should be 6 predicates defined in i_search_list in config.json'); $expectedValues = [ 'rdf:type', @@ -912,15 +914,15 @@ public function testGetPredicatesForSearchDocSpec() ]; foreach ($expectedValues as $expected) { - $this->assertContains($expected, $predicates, "List of predicates should have contained {$expected}"); + $this->assertContains($expected, $predicates, 'List of predicates should have contained ' . $expected); } } - public function testGetPredicatesForSpecFilter() + public function testGetPredicatesForSpecFilter(): void { $predicates = $this->tripodConfig->getDefinedPredicatesInSpec('tripod_php_testing', 'i_search_filter_parse'); - $this->assertEquals(6, count($predicates), 'There should be 6 predicates defined in i_search_filter_parse in config.json'); + $this->assertCount(6, $predicates, 'There should be 6 predicates defined in i_search_filter_parse in config.json'); $expectedValues = [ 'rdf:type', @@ -932,11 +934,11 @@ public function testGetPredicatesForSpecFilter() ]; foreach ($expectedValues as $expected) { - $this->assertContains($expected, $predicates, "List of predicates should have contained {$expected}"); + $this->assertContains($expected, $predicates, 'List of predicates should have contained ' . $expected); } } - public function testCollectionReadPreferencesAreAppliedToDatabase() + public function testCollectionReadPreferencesAreAppliedToDatabase(): void { $mockConfig = $this->getMockBuilder(TripodTestConfig::class) ->onlyMethods(['getDatabase']) @@ -948,19 +950,17 @@ public function testCollectionReadPreferencesAreAppliedToDatabase() ['tripod_php_testing', 'rs1', ReadPreference::RP_SECONDARY_PREFERRED], ['tripod_php_testing', 'rs1', ReadPreference::RP_NEAREST] ) - ->will($this->returnCallback( - function () { - $mongo = new Client(null); + ->willReturnCallback(function () { + $mongo = new Client(); - return $mongo->selectDatabase('tripod_php_testing'); - } - )); + return $mongo->selectDatabase('tripod_php_testing'); + }); $mockConfig->getCollectionForCBD('tripod_php_testing', 'CBD_testing', ReadPreference::RP_SECONDARY_PREFERRED); $mockConfig->getCollectionForCBD('tripod_php_testing', 'CBD_testing', ReadPreference::RP_NEAREST); } - public function testDataLoadedInConfiguredDataSource() + public function testDataLoadedInConfiguredDataSource(): void { $storeName = 'tripod_php_testing'; @@ -976,13 +976,13 @@ public function testDataLoadedInConfiguredDataSource() } } - foreach ($config->getViewSpecifications($storeName) as $id => $spec) { + foreach ($config->getViewSpecifications($storeName) as $spec) { if (!in_array($spec['to_data_source'], $dataSourcesForStore)) { $dataSourcesForStore[] = $spec['to_data_source']; } } - foreach ($config->getTableSpecifications($storeName) as $id => $spec) { + foreach ($config->getTableSpecifications($storeName) as $spec) { if (!in_array($spec['to_data_source'], $dataSourcesForStore)) { $dataSourcesForStore[] = $spec['to_data_source']; } @@ -1009,10 +1009,11 @@ public function testDataLoadedInConfiguredDataSource() break; } + $config->getDatabase($storeName, $source)->drop(); } - if ($diff == false) { + if ($diff === false) { $this->markTestSkipped('All datasources configured for store use same configuration, nothing to test'); } @@ -1024,16 +1025,19 @@ public function testDataLoadedInConfiguredDataSource() $labeller = new Labeller(); $graph->add_resource_triple($subject, RDF_TYPE, $labeller->qname_to_uri('foaf:Person')); $graph->add_literal_triple($subject, FOAF_NAME, 'Anne Example'); + $this->tripod->saveChanges(new ExtendedGraph(), $graph); $newGraph = $this->tripod->describeResource($subject); $newGraph->add_literal_triple($subject, $labeller->qname_to_uri('foaf:email'), 'anne@example.com'); + $this->tripod->saveChanges($graph, $newGraph); // Generate views and tables foreach ($config->getViewSpecifications($storeName) as $viewId => $viewSpec) { $this->tripod->getTripodViews()->generateView($viewId); } + foreach ($config->getTableSpecifications($storeName) as $tableId => $tableSpec) { $this->tripod->generateTableRows($tableId); } @@ -1043,6 +1047,7 @@ public function testDataLoadedInConfiguredDataSource() $lCollection->drop(); $lCollection->insertOne([_ID_KEY => [_ID_RESOURCE => 'foo', _ID_CONTEXT => 'bar'], _LOCKED_FOR_TRANS => 'foobar']); $lCollection->insertOne([_ID_KEY => [_ID_RESOURCE => 'baz', _ID_CONTEXT => 'bar'], _LOCKED_FOR_TRANS => 'wibble']); + $this->tripod->removeInertLocks('foobar', 'reason1'); $collectionsForDataSource = []; @@ -1063,6 +1068,7 @@ public function testDataLoadedInConfiguredDataSource() if (!isset($specsForDataSource[$spec['to_data_source']][$type])) { $specsForDataSource[$spec['to_data_source']][$type] = []; } + $specsForDataSource[$spec['to_data_source']][$type][] = $spec['_id']; } } @@ -1086,6 +1092,7 @@ public function testDataLoadedInConfiguredDataSource() if ($otherSource == $source) { continue; } + foreach ($specsForDataSource[$otherSource]['views'] as $view) { $this->assertEquals(0, $collection->count(['_id.type' => $view]), $view . ' had at least 1 document in data source ' . $source); } @@ -1102,6 +1109,7 @@ public function testDataLoadedInConfiguredDataSource() if ($otherSource == $source) { continue; } + foreach ($specsForDataSource[$otherSource]['search'] as $search) { $this->assertEquals(0, $collection->count(['_id.type' => $search]), $search . ' had at least 1 document in data source ' . $source); } @@ -1117,6 +1125,7 @@ public function testDataLoadedInConfiguredDataSource() if ($otherSource == $source) { continue; } + foreach ($specsForDataSource[$otherSource]['table_rows'] as $t) { $this->assertEquals(0, $collection->count(['_id.type' => $t]), $t . ' had at least 1 document in data source ' . $source); } @@ -1138,7 +1147,7 @@ public function testDataLoadedInConfiguredDataSource() } } - public function testTransactionLogIsWrittenToCorrectDBAndCollection() + public function testTransactionLogIsWrittenToCorrectDBAndCollection(): void { $storeName = 'tripod_php_testing'; $newConfig = Config::getConfig(); @@ -1180,10 +1189,12 @@ public function testTransactionLogIsWrittenToCorrectDBAndCollection() $labeller = new Labeller(); $graph->add_resource_triple($subject, RDF_TYPE, $labeller->qname_to_uri('foaf:Person')); $graph->add_literal_triple($subject, FOAF_NAME, 'Anne Example'); + $this->tripod->saveChanges(new ExtendedGraph(), $graph); $newGraph = $this->tripod->describeResource($subject); $newGraph->add_literal_triple($subject, $labeller->qname_to_uri('foaf:email'), 'anne@example.com'); + $this->tripod->saveChanges($graph, $newGraph); // Make sure the dbs do now exist @@ -1194,6 +1205,7 @@ public function testTransactionLogIsWrittenToCorrectDBAndCollection() $transactionDbExists = true; } } + $this->assertTrue($transactionDbExists); // Make sure the data in the dbs look right @@ -1201,10 +1213,10 @@ public function testTransactionLogIsWrittenToCorrectDBAndCollection() $transactionCount = $transactionColletion->count(); $transactionExampleDocument = $transactionColletion->findOne(); $this->assertEquals(26, $transactionCount); - $this->assertStringContainsString('transaction_', $transactionExampleDocument['_id']); + $this->assertStringContainsString('transaction_', (string) $transactionExampleDocument['_id']); } - public function testComputedFieldSpecValidationInvalidFunction() + public function testComputedFieldSpecValidationInvalidFunction(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1216,7 +1228,7 @@ public function testComputedFieldSpecValidationInvalidFunction() Config::getInstance(); } - public function testComputedFieldSpecValidationMultipleFunctions() + public function testComputedFieldSpecValidationMultipleFunctions(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1228,7 +1240,7 @@ public function testComputedFieldSpecValidationMultipleFunctions() Config::getInstance(); } - public function testComputedFieldSpecValidationMustBeAtBaseLevel() + public function testComputedFieldSpecValidationMustBeAtBaseLevel(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1240,7 +1252,7 @@ public function testComputedFieldSpecValidationMustBeAtBaseLevel() Config::getInstance(); } - public function testConditionalSpecValidationEmptyConditional() + public function testConditionalSpecValidationEmptyConditional(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1252,7 +1264,7 @@ public function testConditionalSpecValidationEmptyConditional() Config::getInstance(); } - public function testConditionalSpecValidationMissingThenElse() + public function testConditionalSpecValidationMissingThenElse(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1264,7 +1276,7 @@ public function testConditionalSpecValidationMissingThenElse() Config::getInstance(); } - public function testConditionalSpecValidationEmptyIf() + public function testConditionalSpecValidationEmptyIf(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1276,7 +1288,7 @@ public function testConditionalSpecValidationEmptyIf() Config::getInstance(); } - public function testConditionalSpecValidationIfNotArray() + public function testConditionalSpecValidationIfNotArray(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1288,7 +1300,7 @@ public function testConditionalSpecValidationIfNotArray() Config::getInstance(); } - public function testConditionalSpecValidationIfHasTwoValues() + public function testConditionalSpecValidationIfHasTwoValues(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1300,7 +1312,7 @@ public function testConditionalSpecValidationIfHasTwoValues() Config::getInstance(); } - public function testConditionalSpecValidationIfHasMoreThanThreeValues() + public function testConditionalSpecValidationIfHasMoreThanThreeValues(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1312,7 +1324,7 @@ public function testConditionalSpecValidationIfHasMoreThanThreeValues() Config::getInstance(); } - public function testConditionalSpecValidationIfHasInvalidConditionalOperator() + public function testConditionalSpecValidationIfHasInvalidConditionalOperator(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1324,7 +1336,7 @@ public function testConditionalSpecValidationIfHasInvalidConditionalOperator() Config::getInstance(); } - public function testConditionalSpecValidationIfHasInvalidVariableAsLeftOperand() + public function testConditionalSpecValidationIfHasInvalidVariableAsLeftOperand(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1336,7 +1348,7 @@ public function testConditionalSpecValidationIfHasInvalidVariableAsLeftOperand() Config::getInstance(); } - public function testConditionalSpecValidationIfHasInvalidVariableAsRightOperand() + public function testConditionalSpecValidationIfHasInvalidVariableAsRightOperand(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1348,7 +1360,7 @@ public function testConditionalSpecValidationIfHasInvalidVariableAsRightOperand( Config::getInstance(); } - public function testConditionalSpecValidationThenHasInvalidVariable() + public function testConditionalSpecValidationThenHasInvalidVariable(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1360,7 +1372,7 @@ public function testConditionalSpecValidationThenHasInvalidVariable() Config::getInstance(); } - public function testConditionalSpecValidationElseHasInvalidVariable() + public function testConditionalSpecValidationElseHasInvalidVariable(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1372,7 +1384,7 @@ public function testConditionalSpecValidationElseHasInvalidVariable() Config::getInstance(); } - public function testReplaceSpecValidationEmptyFunction() + public function testReplaceSpecValidationEmptyFunction(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1384,7 +1396,7 @@ public function testReplaceSpecValidationEmptyFunction() Config::getInstance(); } - public function testReplaceSpecValidationMissingReplace() + public function testReplaceSpecValidationMissingReplace(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1396,7 +1408,7 @@ public function testReplaceSpecValidationMissingReplace() Config::getInstance(); } - public function testReplaceSpecValidationMissingSubject() + public function testReplaceSpecValidationMissingSubject(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1408,7 +1420,7 @@ public function testReplaceSpecValidationMissingSubject() Config::getInstance(); } - public function testReplaceSpecValidationInvalidVariableInSearch() + public function testReplaceSpecValidationInvalidVariableInSearch(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1420,7 +1432,7 @@ public function testReplaceSpecValidationInvalidVariableInSearch() Config::getInstance(); } - public function testReplaceSpecValidationInvalidVariableInSearchArray() + public function testReplaceSpecValidationInvalidVariableInSearchArray(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1432,7 +1444,7 @@ public function testReplaceSpecValidationInvalidVariableInSearchArray() Config::getInstance(); } - public function testReplaceSpecValidationInvalidVariableInReplace() + public function testReplaceSpecValidationInvalidVariableInReplace(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1444,7 +1456,7 @@ public function testReplaceSpecValidationInvalidVariableInReplace() Config::getInstance(); } - public function testReplaceSpecValidationInvalidVariableInReplaceArray() + public function testReplaceSpecValidationInvalidVariableInReplaceArray(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1456,7 +1468,7 @@ public function testReplaceSpecValidationInvalidVariableInReplaceArray() Config::getInstance(); } - public function testReplaceSpecValidationInvalidVariableInSubject() + public function testReplaceSpecValidationInvalidVariableInSubject(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1468,7 +1480,7 @@ public function testReplaceSpecValidationInvalidVariableInSubject() Config::getInstance(); } - public function testReplaceSpecValidationInvalidVariableInSubjectArray() + public function testReplaceSpecValidationInvalidVariableInSubjectArray(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1480,7 +1492,7 @@ public function testReplaceSpecValidationInvalidVariableInSubjectArray() Config::getInstance(); } - public function testArithmeticSpecValidationEmptyFunction() + public function testArithmeticSpecValidationEmptyFunction(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1492,7 +1504,7 @@ public function testArithmeticSpecValidationEmptyFunction() Config::getInstance(); } - public function testArithmeticSpecValidationOneValue() + public function testArithmeticSpecValidationOneValue(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1504,7 +1516,7 @@ public function testArithmeticSpecValidationOneValue() Config::getInstance(); } - public function testArithmeticSpecValidationTwoValues() + public function testArithmeticSpecValidationTwoValues(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1516,7 +1528,7 @@ public function testArithmeticSpecValidationTwoValues() Config::getInstance(); } - public function testArithmeticSpecValidationFourValues() + public function testArithmeticSpecValidationFourValues(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1528,7 +1540,7 @@ public function testArithmeticSpecValidationFourValues() Config::getInstance(); } - public function testArithmeticSpecValidationInvalidArithmeticOperator() + public function testArithmeticSpecValidationInvalidArithmeticOperator(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1540,7 +1552,7 @@ public function testArithmeticSpecValidationInvalidArithmeticOperator() Config::getInstance(); } - public function testArithmeticSpecValidationInvalidVariableLeftOperand() + public function testArithmeticSpecValidationInvalidVariableLeftOperand(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1552,7 +1564,7 @@ public function testArithmeticSpecValidationInvalidVariableLeftOperand() Config::getInstance(); } - public function testArithmeticSpecValidationInvalidVariableRightOperand() + public function testArithmeticSpecValidationInvalidVariableRightOperand(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1564,7 +1576,7 @@ public function testArithmeticSpecValidationInvalidVariableRightOperand() Config::getInstance(); } - public function testArithmeticSpecValidationInvalidNestedVariable() + public function testArithmeticSpecValidationInvalidNestedVariable(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1576,7 +1588,7 @@ public function testArithmeticSpecValidationInvalidNestedVariable() Config::getInstance(); } - public function testArithmeticSpecValidationInvalidNestedOperator() + public function testArithmeticSpecValidationInvalidNestedOperator(): void { $newConfig = Config::getConfig(); Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); @@ -1588,18 +1600,19 @@ public function testArithmeticSpecValidationInvalidNestedOperator() Config::getInstance(); } - public function testGetResqueServer() + public function testGetResqueServer(): void { Tripod\Mongo\Config::setValidationLevel(Tripod\Mongo\Config::VALIDATE_MAX); if (!getenv(MONGO_TRIPOD_RESQUE_SERVER)) { putenv(MONGO_TRIPOD_RESQUE_SERVER . '=redis'); } + $this->assertEquals(getenv(MONGO_TRIPOD_RESQUE_SERVER), Tripod\Mongo\Config::getResqueServer()); } // MongoClient creation tests - public function testMongoConnectionNoExceptions() + public function testMongoConnectionNoExceptions(): void { $mockConfig = $this->getMockBuilder(TripodTestConfig::class) ->onlyMethods(['getMongoClient']) @@ -1608,17 +1621,15 @@ public function testMongoConnectionNoExceptions() $mockConfig->expects($this->exactly(1)) ->method('getMongoClient') ->with('mongodb://mongodb:27017/', ['connectTimeoutMS' => 20000]) - ->will($this->returnCallback( - function () { - return new Client(); - } - )); + ->willReturnCallback(function (): \MongoDB\Client { + return new Client(); + }); $mockConfig->getDatabase('tripod_php_testing', 'rs1', ReadPreference::RP_SECONDARY_PREFERRED); $mockConfig->getCollectionForCBD('tripod_php_testing', 'CBD_testing', ReadPreference::RP_SECONDARY_PREFERRED); $mockConfig->getCollectionForCBD('tripod_php_testing', 'CBD_testing', ReadPreference::RP_NEAREST); } - public function testMongoConnectionExceptionThrown() + public function testMongoConnectionExceptionThrown(): void { $this->expectException(ConnectionTimeoutException::class); $this->expectExceptionMessage('Exception thrown when connecting to Mongo'); @@ -1629,12 +1640,12 @@ public function testMongoConnectionExceptionThrown() $mockConfig->expects($this->exactly(30)) ->method('getMongoClient') ->with('mongodb://mongodb:27017/', ['connectTimeoutMS' => 20000]) - ->will($this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo'))); + ->willThrowException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')); $mockConfig->getDatabase('tripod_php_testing', 'rs1', ReadPreference::RP_SECONDARY_PREFERRED); } - public function testMongoConnectionNoExceptionThrownWhenConnectionThrowsSomeExceptions() + public function testMongoConnectionNoExceptionThrownWhenConnectionThrowsSomeExceptions(): void { $mockConfig = $this->getMockBuilder(TripodTestConfig::class) ->onlyMethods(['getMongoClient']) @@ -1642,18 +1653,11 @@ public function testMongoConnectionNoExceptionThrownWhenConnectionThrowsSomeExce $mockConfig->loadConfig(json_decode(file_get_contents(__DIR__ . '/data/config.json'), true)); $mockConfig->expects($this->exactly(5)) ->method('getMongoClient') - ->with('mongodb://mongodb:27017/', ['connectTimeoutMS' => 20000]) - ->will($this->onConsecutiveCalls( - $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), - $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), - $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), - $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), - $this->returnCallback( - function () { - return new Client(); - } - ) - )); + ->with('mongodb://mongodb:27017/', ['connectTimeoutMS' => 20000])->willReturnOnConsecutiveCalls($this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->returnCallback( + function (): \MongoDB\Client { + return new Client(); + } + )); $mockConfig->getDatabase('tripod_php_testing', 'rs1', ReadPreference::RP_SECONDARY_PREFERRED); $mockConfig->getCollectionForCBD('tripod_php_testing', 'CBD_testing', ReadPreference::RP_SECONDARY_PREFERRED); diff --git a/test/unit/mongo/MongoTripodDocumentStructureTest.php b/test/unit/mongo/MongoTripodDocumentStructureTest.php index 08199b36..ec821a6b 100644 --- a/test/unit/mongo/MongoTripodDocumentStructureTest.php +++ b/test/unit/mongo/MongoTripodDocumentStructureTest.php @@ -1,5 +1,7 @@ loadResourceDataViaTripod(); } - public function testDocumentContainsDefaultProperties() + public function testDocumentContainsDefaultProperties(): void { $id = ['r' => 'http://talisaspire.com/resources/testDocument', 'c' => 'http://talisaspire.com/']; $graph = new MongoGraph(); $graph->add_literal_triple($id['r'], $graph->qname_to_uri('searchterms:title'), 'TEST TITLE'); + $this->tripod->saveChanges(new MongoGraph(), $graph); $this->assertDocumentExists($id); @@ -50,13 +53,14 @@ public function testDocumentContainsDefaultProperties() $this->assertDocumentHasProperty($id, _CREATED_TS); } - public function testDocumentTimeStampsAreUpdatedCorrectlyAfterMultipleWritesAndDelete() + public function testDocumentTimeStampsAreUpdatedCorrectlyAfterMultipleWritesAndDelete(): void { // create an initial document $id = ['r' => 'http://talisaspire.com/resources/testDocument', 'c' => 'http://talisaspire.com/']; $graph = new MongoGraph(); $graph->add_literal_triple($id['r'], $graph->qname_to_uri('searchterms:title'), 'TEST TITLE'); + $this->tripod->saveChanges(new MongoGraph(), $graph); // assert that it is at version 0 $this->assertDocumentExists($id); @@ -72,6 +76,7 @@ public function testDocumentTimeStampsAreUpdatedCorrectlyAfterMultipleWritesAndD // change document through tripod $newGraph = new MongoGraph(); $newGraph->add_literal_triple($id['r'], $graph->qname_to_uri('searchterms:title'), 'CHANGED TITLE'); + $this->tripod->saveChanges($graph, $newGraph); // assert that it is at version 1 @@ -91,6 +96,7 @@ public function testDocumentTimeStampsAreUpdatedCorrectlyAfterMultipleWritesAndD // update again $finalGraph = new MongoGraph(); $finalGraph->add_literal_triple($id['r'], $graph->qname_to_uri('searchterms:title'), 'CHANGED TITLE AGAIN'); + $this->tripod->saveChanges($newGraph, $finalGraph); // assert that it is at version 2 @@ -125,7 +131,7 @@ public function testDocumentTimeStampsAreUpdatedCorrectlyAfterMultipleWritesAndD * This test verifies that if a document was previously added to mongo without any timestamps i.e. _UPDATED_TS and _CREATED_TS * then on a tripod write only the _UPDATED_TS will be added to the document. */ - public function testOnlyDocumentUpdatedTimestampIsAddedToDocumentThatDidntHaveTimestampsToBeginWith() + public function testOnlyDocumentUpdatedTimestampIsAddedToDocumentThatDidntHaveTimestampsToBeginWith(): void { // add the initial document, but not through Driver! $_id = ['r' => 'http://talisaspire.com/resources/testDocument2', 'c' => 'http://talisaspire.com/']; @@ -147,6 +153,7 @@ public function testOnlyDocumentUpdatedTimestampIsAddedToDocumentThatDidntHaveTi // change the document through tripod, for this im just doing a new addition $graph = new MongoGraph(); $graph->add_literal_triple($_id['r'], $graph->qname_to_uri('searchterms:title'), 'a new property'); + $this->tripod->saveChanges(new MongoGraph(), $graph); // Now assert, document should contain the additiona triple we added, an updated _version. diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index 77a3a9ae..b7cdff9a 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -1,5 +1,7 @@ loadResourceDataViaTripod(); } - public function testSelectMultiValue() + public function testSelectMultiValue(): void { $expectedResult = [ 'head' => [ @@ -90,7 +92,7 @@ public function testSelectMultiValue() $this->assertEquals($expectedResult, $actualResult); } - public function testSelectSingleValue() + public function testSelectSingleValue(): void { $expectedResult = [ 'head' => [ @@ -111,7 +113,7 @@ public function testSelectSingleValue() $this->assertEquals($expectedResult, $actualResult); } - public function testGraph() + public function testGraph(): void { $expectedResult = new ExtendedGraph(); $expectedResult->add_turtle( @@ -152,7 +154,7 @@ public function testGraph() $this->assertFalse($cs->has_changes()); } - public function testDescribeResource() + public function testDescribeResource(): void { $expectedResult = new ExtendedGraph(); $expectedResult->add_turtle( @@ -193,7 +195,7 @@ public function testDescribeResource() $this->assertFalse($cs->has_changes()); } - public function testDescribeResources() + public function testDescribeResources(): void { $expectedResult = new ExtendedGraph(); $expectedResult->add_turtle( @@ -241,13 +243,13 @@ public function testDescribeResources() $this->assertFalse($cs->has_changes()); } - public function testGetCount() + public function testGetCount(): void { $count = $this->tripod->getCount(['rdf:type.' . VALUE_URI => 'bibo:Book']); $this->assertEquals(9, $count); } - public function testGetCountWithGroupBy() + public function testGetCountWithGroupBy(): void { $count = $this->tripod->getCount(['rdf:type.' . VALUE_URI => 'bibo:Book'], 'bibo:isbn13.l'); @@ -259,7 +261,7 @@ public function testGetCountWithGroupBy() $this->assertEquals(1, $count['9780393929690']); } - public function testTripodSaveChangesRemovesLiteralTriple() + public function testTripodSaveChangesRemovesLiteralTriple(): void { $oG = $this->tripod->describeResource('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA'); $nG = new MongoGraph(); @@ -271,7 +273,7 @@ public function testTripodSaveChangesRemovesLiteralTriple() $this->assertEquals($nG, $uG, 'Updated does not match expected graph'); } - public function testTripodSaveChangesAddsLiteralTriple() + public function testTripodSaveChangesAddsLiteralTriple(): void { $oG = $this->tripod->describeResource('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA'); $nG = new MongoGraph(); @@ -288,10 +290,11 @@ public function testTripodSaveChangesAddsLiteralTriple() * we dont have to load the whole document in as the old graph, we just enumerate the single triple we want removed * what should happen is that the cs builder will translate that into a single removal. */ - public function testTripodSaveChangesRemovesLiteralTripleUsingEmptyNewGraphAndPartialOldGraph() + public function testTripodSaveChangesRemovesLiteralTripleUsingEmptyNewGraphAndPartialOldGraph(): void { $oG = new MongoGraph(); $oG->add_literal_triple('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', $oG->qname_to_uri('bibo:isbn13'), '9780393929690'); + $nG = new MongoGraph(); $this->tripod->saveChanges($oG, $nG, 'http://talisaspire.com/', 'my changes'); @@ -306,7 +309,7 @@ public function testTripodSaveChangesRemovesLiteralTripleUsingEmptyNewGraphAndPa * this test verifies that if we simply want to add some data to a document that exists in we dont need to specify an oldgraph; we just need to specify the new graph * the cs builder should translate that into a single addition statement and apply it. */ - public function testTripodSaveChangesAddsLiteralTripleUsingEmptyOldGraph() + public function testTripodSaveChangesAddsLiteralTripleUsingEmptyOldGraph(): void { $oG = new MongoGraph(); $nG = new MongoGraph(); @@ -318,7 +321,7 @@ public function testTripodSaveChangesAddsLiteralTripleUsingEmptyOldGraph() $this->assertHasLiteralTriple($uG, 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', $nG->qname_to_uri('searchterms:title'), 'TEST TITLE'); } - public function testTripodSaveChangesUpdatesLiteralTriple() + public function testTripodSaveChangesUpdatesLiteralTriple(): void { $oG = $this->tripod->describeResource('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA'); $nG = new MongoGraph(); @@ -335,13 +338,14 @@ public function testTripodSaveChangesUpdatesLiteralTriple() $this->assertFalse($uG->has_literal_triple('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', $nG->qname_to_uri('searchterms:title'), 'Physics 3rd Edition'), 'Graph should not contain literal triple we removed'); } - public function testSaveCompletelyNewGraph() + public function testSaveCompletelyNewGraph(): void { $uri = 'http://example.com/resources/1'; $g = new MongoGraph(); $g->add_resource_triple($uri, $g->qname_to_uri('rdf:type'), $g->qname_to_uri('acorn:Resource')); $g->add_literal_triple($uri, $g->qname_to_uri('dct:title'), 'wibble'); + $this->tripod->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/', 'something new'); $uG = $this->tripod->describeResource($uri); @@ -351,7 +355,7 @@ public function testSaveCompletelyNewGraph() $this->assertTrue($uG->has_literal_triple($uri, $g->qname_to_uri('dct:title'), 'wibble'), 'Graph should contain literal triple we added'); } - public function testRemoveGraphEntirely() + public function testRemoveGraphEntirely(): void { $uri = 'http://example.com/resources/1'; @@ -359,6 +363,7 @@ public function testRemoveGraphEntirely() $g = new MongoGraph(); $g->add_resource_triple($uri, $g->qname_to_uri('rdf:type'), $g->qname_to_uri('acorn:Resource')); $g->add_literal_triple($uri, $g->qname_to_uri('dct:title'), 'wibble'); + $this->tripod->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/', 'something new'); // retrieve it and make sure it was saved correctly @@ -374,7 +379,7 @@ public function testRemoveGraphEntirely() $this->assertTrue($g->is_empty()); } - public function testSaveFailsWhenOldGraphIsInvalidNoDataInStoreForObj() + public function testSaveFailsWhenOldGraphIsInvalidNoDataInStoreForObj(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('Error storing changes'); @@ -388,10 +393,10 @@ public function testSaveFailsWhenOldGraphIsInvalidNoDataInStoreForObj() $nG = new MongoGraph(); $nG->add_resource_triple($uri, $nG->qname_to_uri('rdf:type'), $nG->qname_to_uri('acorn:List')); - $result = $this->tripod->saveChanges($oG, $nG, 'http://talisaspire.com/'); + $this->tripod->saveChanges($oG, $nG, 'http://talisaspire.com/'); } - public function testInterleavingUpdateFailsIfUnderlyingDataHasChanged() + public function testInterleavingUpdateFailsIfUnderlyingDataHasChanged(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('Error storing changes'); @@ -419,22 +424,23 @@ public function testInterleavingUpdateFailsIfUnderlyingDataHasChanged() $mockTripodUpdate->expects($this->once()) ->method('getDocumentForUpdate') ->with($uri) - ->will($this->returnValue($doc)); + ->willReturn($doc); $mockTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdate)); + ->willReturn($mockTripodUpdate); $mockTripod->setTransactionLog($this->tripodTransactionLog); $oG = new MongoGraph(); $oG->add_resource_triple($uri, $oG->qname_to_uri('rdf:type'), $oG->qname_to_uri('acorn:Book')); + $nG = new MongoGraph(); $nG->add_resource_triple($uri, $nG->qname_to_uri('rdf:type'), $nG->qname_to_uri('acorn:Foo')); - $result = $mockTripod->saveChanges($oG, $nG, 'http://talisaspire.com/'); + $mockTripod->saveChanges($oG, $nG, 'http://talisaspire.com/'); } - public function testInterleavingUpdateFailsIfCriteriaIsNotValidAtPointOfSave() + public function testInterleavingUpdateFailsIfCriteriaIsNotValidAtPointOfSave(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('Error storing changes'); @@ -444,6 +450,7 @@ public function testInterleavingUpdateFailsIfCriteriaIsNotValidAtPointOfSave() $g = new MongoGraph(); $g->add_resource_triple($uri, $g->qname_to_uri('rdf:type'), $g->qname_to_uri('acorn:Book')); + $this->tripod->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/'); // canned response will simulate that the underlying data has changed @@ -466,11 +473,11 @@ public function testInterleavingUpdateFailsIfCriteriaIsNotValidAtPointOfSave() $mockTripodUpdate->expects($this->once()) ->method('getDocumentForUpdate') ->with($uri) - ->will($this->returnValue($doc)); + ->willReturn($doc); $mockTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdate)); + ->willReturn($mockTripodUpdate); $mockTripod->setTransactionLog($this->tripodTransactionLog); @@ -480,10 +487,10 @@ public function testInterleavingUpdateFailsIfCriteriaIsNotValidAtPointOfSave() $nG = new MongoGraph(); $nG->add_resource_triple($uri, $nG->qname_to_uri('rdf:type'), $nG->qname_to_uri('acorn:Foo')); - $result = $mockTripod->saveChanges($oG, $nG, 'http://talisaspire.com/'); + $mockTripod->saveChanges($oG, $nG, 'http://talisaspire.com/'); } - public function testAddMultipleTriplesForSameProperty() + public function testAddMultipleTriplesForSameProperty(): void { $uri = 'http://example.com/resources/1'; @@ -493,6 +500,7 @@ public function testAddMultipleTriplesForSameProperty() $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Some title'); $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Another title'); $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Yet another title'); + $this->tripod->saveChanges(new MongoGraph(), $oG, 'http://talisaspire.com/'); // retrieve it and make sure it was saved correctly @@ -504,7 +512,7 @@ public function testAddMultipleTriplesForSameProperty() $this->assertTrue($g->has_literal_triple($uri, $g->qname_to_uri('dct:title'), 'Yet another title'), 'Graph should contain literal triple we added'); } - public function testRemoveMultipleTriplesForSameProperty() + public function testRemoveMultipleTriplesForSameProperty(): void { $uri = 'http://example.com/resources/1'; @@ -514,11 +522,13 @@ public function testRemoveMultipleTriplesForSameProperty() $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Some title'); $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Another title'); $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Yet another title'); + $this->tripod->saveChanges(new MongoGraph(), $oG, 'http://talisaspire.com/'); // remove all three dct:title triples $g2 = new MongoGraph(); $g2->add_resource_triple($uri, $oG->qname_to_uri('rdf:type'), $oG->qname_to_uri('acorn:Resource')); + $this->tripod->saveChanges($oG, $g2, 'http://talisaspire.com/'); $g = $this->tripod->describeResource($uri); @@ -529,7 +539,7 @@ public function testRemoveMultipleTriplesForSameProperty() $this->assertFalse($g->has_literal_triple($uri, $g->qname_to_uri('dct:title'), 'Yet another title'), 'Graph should not contain literal triple we removed'); } - public function testChangeMultipleTriplesForSamePropertySimple() + public function testChangeMultipleTriplesForSamePropertySimple(): void { $uri = 'http://example.com/resources/1'; @@ -539,6 +549,7 @@ public function testChangeMultipleTriplesForSamePropertySimple() $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Some title'); $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Another title'); $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Yet another title'); + $this->tripod->saveChanges(new MongoGraph(), $oG, 'http://talisaspire.com/'); $g2 = new MongoGraph(); @@ -546,6 +557,7 @@ public function testChangeMultipleTriplesForSamePropertySimple() $g2->add_literal_triple($uri, $g2->qname_to_uri('dct:title'), 'Updated Some title'); $g2->add_literal_triple($uri, $g2->qname_to_uri('dct:title'), 'Updated Another title'); $g2->add_literal_triple($uri, $g2->qname_to_uri('dct:title'), 'Updated Yet another title'); + $this->tripod->saveChanges($oG, $g2, 'http://talisaspire.com/'); $g = $this->tripod->describeResource($uri); @@ -562,7 +574,7 @@ public function testChangeMultipleTriplesForSamePropertySimple() $this->assertTrue($g->has_literal_triple($uri, $g->qname_to_uri('dct:title'), 'Updated Yet another title'), 'Graph should contain literal triple we added'); } - public function testChangeMultipleTriplesForSamePropertyMoreComplex() + public function testChangeMultipleTriplesForSamePropertyMoreComplex(): void { $uri = 'http://example.com/resources/1'; @@ -574,6 +586,7 @@ public function testChangeMultipleTriplesForSamePropertyMoreComplex() $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Title three'); $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Title four'); $oG->add_literal_triple($uri, $oG->qname_to_uri('dct:title'), 'Title five'); + $this->tripod->saveChanges(new MongoGraph(), $oG, 'http://talisaspire.com/'); // new data @@ -583,6 +596,7 @@ public function testChangeMultipleTriplesForSamePropertyMoreComplex() $g2->add_literal_triple($uri, $g2->qname_to_uri('dct:title'), 'New Title two'); $g2->add_literal_triple($uri, $g2->qname_to_uri('dct:title'), 'Title five'); $g2->add_literal_triple($uri, $g2->qname_to_uri('dct:title'), 'New Title seven'); + $this->tripod->saveChanges($oG, $g2, 'http://talisaspire.com/'); $g = $this->tripod->describeResource($uri); @@ -601,7 +615,7 @@ public function testChangeMultipleTriplesForSamePropertyMoreComplex() $this->assertTrue($g->has_literal_triple($uri, $g->qname_to_uri('dct:title'), 'New Title seven'), 'Graph should contain literal triple we added'); } - public function testSetReadPreferenceWhenSavingChanges() + public function testSetReadPreferenceWhenSavingChanges(): void { $subjectOne = 'http://talisaspire.com/works/checkReadPreferencesWrite'; @@ -630,14 +644,15 @@ public function testSetReadPreferenceWhenSavingChanges() $tripodMock ->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdate)); + ->willReturn($tripodUpdate); $g = new MongoGraph(); $g->add_literal_triple($subjectOne, $g->qname_to_uri('dct:title'), 'Title one'); + $tripodMock->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/'); } - public function testReadPreferencesAreRestoredWhenErrorSavingChanges() + public function testReadPreferencesAreRestoredWhenErrorSavingChanges(): void { $subjectOne = 'http://talisaspire.com/works/checkReadPreferencesAreRestoredOnError'; $tripodMock = $this->getMockBuilder(Driver::class) @@ -657,7 +672,7 @@ public function testReadPreferencesAreRestoredWhenErrorSavingChanges() $tripodUpdate ->expects($this->once()) ->method('getContextAlias') - ->will($this->throwException(new Exception('A Test Exception'))); + ->willThrowException(new Exception('A Test Exception')); $tripodUpdate ->expects($this->once()) @@ -666,16 +681,17 @@ public function testReadPreferencesAreRestoredWhenErrorSavingChanges() $tripodMock ->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdate)); + ->willReturn($tripodUpdate); $this->expectException(Exception::class); $g = new MongoGraph(); $g->add_literal_triple($subjectOne, $g->qname_to_uri('dct:title'), 'Title one'); + $tripodMock->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/'); } - public function testReadPreferencesOverMultipleSaves() + public function testReadPreferencesOverMultipleSaves(): void { $subjectOne = 'http://talisaspire.com/works/checkReadPreferencesOverMultipleSaves'; @@ -692,47 +708,48 @@ public function testReadPreferencesOverMultipleSaves() $tripodUpdate ->expects($this->exactly(3)) - ->method('validateGraphCardinality') - ->will( - $this->onConsecutiveCalls(null, $this->throwException(new Exception('readPreferenceOverMultipleSavesTestException')), null) - ); + ->method('validateGraphCardinality')->willReturnOnConsecutiveCalls(null, $this->throwException(new Exception('readPreferenceOverMultipleSavesTestException')), null); $tripodMock ->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdate)); + ->willReturn($tripodUpdate); $expectedCollectionReadPreference = $tripodMock->getCollectionReadPreference(); - $this->assertEquals($expectedCollectionReadPreference->getMode(), ReadPreference::RP_SECONDARY_PREFERRED); + $this->assertEquals(ReadPreference::RP_SECONDARY_PREFERRED, $expectedCollectionReadPreference->getMode()); // Assert that a simple save results in read preferences being restored $g = new MongoGraph(); $g->add_literal_triple($subjectOne, $g->qname_to_uri('dct:title'), 'Title one'); + $tripodMock->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/'); $this->assertEquals($expectedCollectionReadPreference, $tripodMock->getCollectionReadPreference()); // Assert a thrown exception still results in read preferences being restored $g = new MongoGraph(); $g->add_literal_triple($subjectOne, $g->qname_to_uri('dct:title2'), 'Title two'); + $exceptionThrown = false; try { $tripodMock->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/'); } catch (Exception $e) { $exceptionThrown = true; - $this->assertEquals('readPreferenceOverMultipleSavesTestException', $e->getMessage()); + $this->assertSame('readPreferenceOverMultipleSavesTestException', $e->getMessage()); } + $this->assertTrue($exceptionThrown); $this->assertEquals($expectedCollectionReadPreference, $tripodMock->getCollectionReadPreference()); // Assert that a new save after the exception still results in read preferences being restored $g = new MongoGraph(); $g->add_literal_triple($subjectOne, $g->qname_to_uri('dct:title3'), 'Title three'); + $tripodMock->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/'); $this->assertEquals($expectedCollectionReadPreference, $tripodMock->getCollectionReadPreference()); } - public function testSaveChangesToLockedDocument() + public function testSaveChangesToLockedDocument(): void { $subjectOne = 'http://talisaspire.com/works/lockedDoc'; @@ -747,7 +764,7 @@ public function testSaveChangesToLockedDocument() $this->tripod->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/'); } - public function testSaveChangesToMultipleSubjects() + public function testSaveChangesToMultipleSubjects(): void { $subjectOne = 'http://example.com/resources/1'; $subjectTwo = 'http://example.com/resources/2'; @@ -760,6 +777,7 @@ public function testSaveChangesToMultipleSubjects() $oG->add_resource_triple($subjectTwo, $oG->qname_to_uri('rdf:type'), $oG->qname_to_uri('acorn:Book')); $oG->add_literal_triple($subjectTwo, $oG->qname_to_uri('dct:title'), 'Title three'); $oG->add_literal_triple($subjectTwo, $oG->qname_to_uri('dct:title'), 'Title four'); + $this->tripod->saveChanges(new MongoGraph(), $oG, 'http://talisaspire.com/'); // retrieve them both, assert they are as we expect @@ -802,7 +820,7 @@ public function testSaveChangesToMultipleSubjects() $this->assertTrue($uG->has_literal_triple($subjectTwo, $uG->qname_to_uri('dct:author'), 'James Brown')); } - public function testDocumentVersioning() + public function testDocumentVersioning(): void { $uri = 'http://example.com/resources/1'; @@ -810,6 +828,7 @@ public function testDocumentVersioning() $g = new MongoGraph(); $g->add_resource_triple($uri, $g->qname_to_uri('rdf:type'), $g->qname_to_uri('acorn:Resource')); $g->add_literal_triple($uri, $g->qname_to_uri('dct:title'), 'wibble'); + $this->tripod->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/', 'something new'); $uG = $this->tripod->describeResource($uri); $this->assertTrue($uG->has_triples_about($uri), 'new entity we created was not saved'); @@ -820,6 +839,7 @@ public function testDocumentVersioning() $nG = new MongoGraph(); $nG->add_graph($g); $nG->add_literal_triple($uri, $g->qname_to_uri('dct:title'), 'another title'); + $this->tripod->saveChanges($g, $nG, 'http://talisaspire.com/'); $uG = $this->tripod->describeResource($uri); $this->assertTrue($uG->has_resource_triple($uri, $g->qname_to_uri('rdf:type'), $g->qname_to_uri('acorn:Resource')), 'Graph should contain resource triple we added'); @@ -830,6 +850,7 @@ public function testDocumentVersioning() $nG = new MongoGraph(); // $nG->add_graph(); $nG->add_literal_triple($uri, $g->qname_to_uri('dct:title'), 'only a title'); + $this->tripod->saveChanges($uG, $nG, 'http://talisaspire.com/'); $uG = $this->tripod->describeResource($uri); @@ -844,7 +865,7 @@ public function testDocumentVersioning() $this->assertDocumentHasBeenDeleted(['r' => $uri, 'c' => 'http://talisaspire.com/']); } - public function testSaveChangesWithInvalidCardinality() + public function testSaveChangesWithInvalidCardinality(): void { $this->expectException(CardinalityException::class); $this->expectExceptionMessage("Cardinality failed on http://foo/bar/1 for 'rdf:type' - should only have 1 value and has: http://foo/bar#Class1, http://foo/bar#Class2"); @@ -890,7 +911,7 @@ public function testSaveChangesWithInvalidCardinality() $tripod->saveChanges($oldGraph, $newGraph, 'http://talisaspire.com/'); } - public function testDiscoverImpactedSubjectsAreDoneAllOperationsASync() + public function testDiscoverImpactedSubjectsAreDoneAllOperationsASync(): void { $uri_1 = 'http://example.com/1'; $uri_2 = 'http://example.com/2'; @@ -966,15 +987,15 @@ public function testDiscoverImpactedSubjectsAreDoneAllOperationsASync() ->method('getComposite'); $mockTripodUpdates->expects($this->once()) ->method('getDiscoverImpactedSubjects') - ->will($this->returnValue($mockDiscoverImpactedSubjects)); + ->willReturn($mockDiscoverImpactedSubjects); $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue(['subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange, 'transaction_id' => 't1234'])); + ->willReturn(['subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange, 'transaction_id' => 't1234']); $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockDiscoverImpactedSubjects->expects($this->once()) ->method('createJob') @@ -986,7 +1007,7 @@ public function testDiscoverImpactedSubjectsAreDoneAllOperationsASync() $mockTripod->saveChanges(new ExtendedGraph(), $oG, 'http://talisaspire.com/'); } - public function testDiscoverImpactedSubjectsForDeletionsSyncOpsAreDoneAsyncJobSubmitted() + public function testDiscoverImpactedSubjectsForDeletionsSyncOpsAreDoneAsyncJobSubmitted(): void { $uri_1 = 'http://example.com/1'; $uri_2 = 'http://example.com/2'; @@ -1108,7 +1129,7 @@ public function testDiscoverImpactedSubjectsForDeletionsSyncOpsAreDoneAsyncJobSu ]; $mockViews->expects($this->once()) ->method('getImpactedSubjects') - ->will($this->returnValue($impactedViewSubjects)); + ->willReturn($impactedViewSubjects); $impactedViewSubjects[0]->expects($this->once())->method('update'); $impactedViewSubjects[1]->expects($this->once())->method('update'); @@ -1150,7 +1171,7 @@ public function testDiscoverImpactedSubjectsForDeletionsSyncOpsAreDoneAsyncJobSu $mockTables->expects($this->once()) ->method('getImpactedSubjects') - ->will($this->returnValue($impactedTableSubjects)); + ->willReturn($impactedTableSubjects); $impactedTableSubjects[0]->expects($this->once())->method('update'); $impactedTableSubjects[1]->expects($this->once())->method('update'); @@ -1159,24 +1180,22 @@ public function testDiscoverImpactedSubjectsForDeletionsSyncOpsAreDoneAsyncJobSu $mockTripodUpdates->expects($this->once()) ->method('getDiscoverImpactedSubjects') - ->will($this->returnValue($mockDiscoverImpactedSubjects)); + ->willReturn($mockDiscoverImpactedSubjects); $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue(['subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange, 'transaction_id' => 't1234'])); + ->willReturn(['subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange, 'transaction_id' => 't1234']); $mockTripod->expects($this->exactly(2)) ->method('getComposite') - ->will($this->returnValueMap( - [ - [OP_TABLES, $mockTables], - [OP_VIEWS, $mockViews], - ] - )); + ->willReturnMap([ + [OP_TABLES, $mockTables], + [OP_VIEWS, $mockViews], + ]); $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockDiscoverImpactedSubjects->expects($this->once()) ->method('createJob') @@ -1188,7 +1207,7 @@ public function testDiscoverImpactedSubjectsForDeletionsSyncOpsAreDoneAsyncJobSu $mockTripod->saveChanges($oG, new ExtendedGraph(), 'http://talisaspire.com/'); } - public function testDiscoverImpactedSubjectsForDefaultOperationsSetting() + public function testDiscoverImpactedSubjectsForDefaultOperationsSetting(): void { $uri_1 = 'http://example.com/1'; $uri_2 = 'http://example.com/2'; @@ -1295,23 +1314,23 @@ public function testDiscoverImpactedSubjectsForDefaultOperationsSetting() $mockTripod->expects($this->once()) ->method('getComposite') ->with(OP_VIEWS) - ->will($this->returnValue($mockViews)); + ->willReturn($mockViews); $mockTripodUpdates->expects($this->once()) ->method('getDiscoverImpactedSubjects') - ->will($this->returnValue($mockDiscoverImpactedSubjects)); + ->willReturn($mockDiscoverImpactedSubjects); $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue(['subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange, 'transaction_id' => 't1234'])); + ->willReturn(['subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange, 'transaction_id' => 't1234']); $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockViews->expects($this->once()) ->method('getImpactedSubjects') - ->will($this->returnValue($impactedViewSubjects)); + ->willReturn($impactedViewSubjects); $impactedViewSubjects[0]->expects($this->once())->method('update'); $impactedViewSubjects[1]->expects($this->once())->method('update'); @@ -1329,7 +1348,7 @@ public function testDiscoverImpactedSubjectsForDefaultOperationsSetting() $mockTripod->saveChanges($oG, $nG, 'http://talisaspire.com/'); } - public function testSpecifyQueueForAsyncOperations() + public function testSpecifyQueueForAsyncOperations(): void { $uri_1 = 'http://example.com/1'; $uri_2 = 'http://example.com/2'; @@ -1440,23 +1459,23 @@ public function testSpecifyQueueForAsyncOperations() $mockTripod->expects($this->once()) ->method('getComposite') ->with(OP_VIEWS) - ->will($this->returnValue($mockViews)); + ->willReturn($mockViews); $mockTripodUpdates->expects($this->once()) ->method('getDiscoverImpactedSubjects') - ->will($this->returnValue($mockDiscoverImpactedSubjects)); + ->willReturn($mockDiscoverImpactedSubjects); $mockTripodUpdates->expects($this->once()) ->method('storeChanges') - ->will($this->returnValue(['subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange, 'transaction_id' => 't1234'])); + ->willReturn(['subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange, 'transaction_id' => 't1234']); $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockViews->expects($this->once()) ->method('getImpactedSubjects') - ->will($this->returnValue($impactedViewSubjects)); + ->willReturn($impactedViewSubjects); // This shouldn't be called because ImpactedSubject->update has been mocked and isn't doing anything $mockViews->expects($this->never())->method('update'); @@ -1474,11 +1493,11 @@ public function testSpecifyQueueForAsyncOperations() $mockTripod->saveChanges($oG, $nG, 'http://talisaspire.com/'); } - public function testWriteToUnconfiguredCollectionThrowsException() + public function testWriteToUnconfiguredCollectionThrowsException(): void { // Exception: testing:SOME_COLLECTION is not referenced within config, so cannot be written to $this->expectException(ConfigException::class); - $this->expectExceptionMessage('Collection name \'SOME_COLLECTION\' not in configuration'); + $this->expectExceptionMessage("Collection name 'SOME_COLLECTION' not in configuration"); $tripod = new Driver('SOME_COLLECTION', 'tripod_php_testing'); $tripod->saveChanges(new ExtendedGraph(), new ExtendedGraph(), 'http://talisaspire.com/'); @@ -1491,7 +1510,7 @@ public function testWriteToUnconfiguredCollectionThrowsException() * the cs builder should translate that into a single addition statement and apply it. * This builds on the previous test, by operating on data in mongo where _id.r and _id.c are namespaced. */ - public function testTripodSaveChangesAddsLiteralTripleUsingEmptyOldGraphWithNamespacableIDAndContext() + public function testTripodSaveChangesAddsLiteralTripleUsingEmptyOldGraphWithNamespacableIDAndContext(): void { $oG = new MongoGraph(); $nG = new MongoGraph(); @@ -1510,7 +1529,7 @@ public function testTripodSaveChangesAddsLiteralTripleUsingEmptyOldGraphWithName * the cs builder should translate that into a single addition statement and apply it. * This builds on the previous test, by operating on data in mongo where _id.r and _id.c are namespaced AND passing context into the save method. */ - public function testTripodSaveChangesAddsLiteralTripleUsingEmptyOldGraphWithNamespacedContext() + public function testTripodSaveChangesAddsLiteralTripleUsingEmptyOldGraphWithNamespacedContext(): void { $oG = new MongoGraph(); $nG = new MongoGraph(); @@ -1524,7 +1543,7 @@ public function testTripodSaveChangesAddsLiteralTripleUsingEmptyOldGraphWithName $this->assertHasLiteralTriple($uG, 'http://basedata.com/b/1', $nG->qname_to_uri('searchterms:title'), 'TEST TITLE'); } - public function testDescribeResourceWithNamespace() + public function testDescribeResourceWithNamespace(): void { $noNsG = $this->tripod->describeResource('http://basedata.com/b/1', 'http://basedata.com/b/DefaultGraph'); $nsResourceG = $this->tripod->describeResource('baseData:1', 'http://basedata.com/b/DefaultGraph'); @@ -1541,7 +1560,7 @@ public function testDescribeResourceWithNamespace() $this->assertFalse($nsBothCS->has_changes(), 'Non ns and nsBoth not equal'); } - public function testDescribeResourcesWithNamespace() + public function testDescribeResourcesWithNamespace(): void { $noNsG = $this->tripod->describeResources(['http://basedata.com/b/1'], 'http://basedata.com/b/DefaultGraph'); $nsResourceG = $this->tripod->describeResources(['baseData:1'], 'http://basedata.com/b/DefaultGraph'); @@ -1558,7 +1577,7 @@ public function testDescribeResourcesWithNamespace() $this->assertFalse($nsBothCS->has_changes(), 'Non ns and nsBoth not equal'); } - public function testSelectSingleValueWithNamespaceContextQueryDoesntContainID() + public function testSelectSingleValueWithNamespaceContextQueryDoesntContainID(): void { $expectedResult = [ 'head' => [ @@ -1585,7 +1604,7 @@ public function testSelectSingleValueWithNamespaceContextQueryDoesntContainID() $this->assertEquals($expectedResult, $actualResult); } - public function testSelectSingleValueWithNamespaceContextQueryDoesContainID() + public function testSelectSingleValueWithNamespaceContextQueryDoesContainID(): void { $expectedResult = [ 'head' => [ @@ -1613,7 +1632,7 @@ public function testSelectSingleValueWithNamespaceContextQueryDoesContainID() $this->assertEquals($expectedResult, $actualResult); } - public function testSelectWithOperandWithNamespaceContextQueryContainsID() + public function testSelectWithOperandWithNamespaceContextQueryContainsID(): void { $expectedResult = [ 'head' => [ @@ -1646,7 +1665,7 @@ public function testSelectWithOperandWithNamespaceContextQueryContainsID() $this->assertEquals($expectedResult, $actualResult); } - public function testSelectWithOperandWithNamespaceContextQueryDoesNotContainID() + public function testSelectWithOperandWithNamespaceContextQueryDoesNotContainID(): void { $expectedResult = [ 'head' => [ @@ -1680,7 +1699,7 @@ public function testSelectWithOperandWithNamespaceContextQueryDoesNotContainID() $this->assertEquals($expectedResult, $actualResult); } - public function testSelectDocumentWithSpecialFieldTypes() + public function testSelectDocumentWithSpecialFieldTypes(): void { $id = [ 'r' => 'http://talisaspire.com/resources/' . uniqid(), @@ -1707,7 +1726,6 @@ public function testSelectDocumentWithSpecialFieldTypes() // Special field types '_oid' => new ObjectId(), '_bin' => new Binary('foo', Binary::TYPE_OLD_BINARY), - '_fun' => new Javascript('function() { return 42; }'), '_fun' => new Regex('foo', 'i'), ]); @@ -1736,7 +1754,7 @@ public function testSelectDocumentWithSpecialFieldTypes() /** * Return the distinct values of a table column. */ - public function testGetDistinctTableValues() + public function testGetDistinctTableValues(): void { // Get table rows $table = 't_distinct'; @@ -1749,7 +1767,7 @@ public function testGetDistinctTableValues() $this->assertArrayHasKey('count', $results['head']); $this->assertEquals(4, $results['head']['count']); $this->assertArrayHasKey('results', $results); - $this->assertEquals(4, count($results['results'])); + $this->assertCount(4, $results['results']); $this->assertContains('Physics 3rd Edition: Physics for Engineers and Scientists', $results['results']); $this->assertContains('A document title', $results['results']); $this->assertContains('Another document title', $results['results']); @@ -1760,7 +1778,7 @@ public function testGetDistinctTableValues() $this->assertArrayHasKey('count', $results['head']); $this->assertEquals(2, $results['head']['count']); $this->assertArrayHasKey('results', $results); - $this->assertEquals(2, count($results['results'])); + $this->assertCount(2, $results['results']); $this->assertNotContains('Physics 3rd Edition: Physics for Engineers and Scientists', $results['results']); $this->assertContains('A document title', $results['results']); $this->assertContains('Another document title', $results['results']); @@ -1770,7 +1788,7 @@ public function testGetDistinctTableValues() $this->assertArrayHasKey('count', $results['head']); $this->assertEquals(7, $results['head']['count']); $this->assertArrayHasKey('results', $results); - $this->assertEquals(7, count($results['results'])); + $this->assertCount(7, $results['results']); $this->assertContains('acorn:Resource', $results['results']); $this->assertContains('acorn:Work', $results['results']); $this->assertContains('bibo:Book', $results['results']); @@ -1780,19 +1798,19 @@ public function testGetDistinctTableValues() /** * Return no results for tablespec that doesn't exist. */ - public function testDistinctOnTableSpecThatDoesNotExist() + public function testDistinctOnTableSpecThatDoesNotExist(): void { $table = 't_nothing_to_see_here'; $this->expectException(ConfigException::class); - $this->expectExceptionMessage('Table id \'t_nothing_to_see_here\' not in configuration'); - $results = $this->tripod->getDistinctTableColumnValues($table, 'value.foo'); + $this->expectExceptionMessage("Table id 't_nothing_to_see_here' not in configuration"); + $this->tripod->getDistinctTableColumnValues($table, 'value.foo'); } /** * Return no results for distinct on a fieldname that is not defined in tableSpec. */ - public function testDistinctOnFieldNameThatIsNotInTableSpec() + public function testDistinctOnFieldNameThatIsNotInTableSpec(): void { // Get table rows $table = 't_distinct'; @@ -1806,7 +1824,7 @@ public function testDistinctOnFieldNameThatIsNotInTableSpec() /** * Return no results for filters that match no table rows. */ - public function testDistinctForFilterWithNoMatches() + public function testDistinctForFilterWithNoMatches(): void { // Get table rows $table = 't_distinct'; @@ -1818,62 +1836,62 @@ public function testDistinctForFilterWithNoMatches() } /** START: getLockedDocuments tests */ - public function testGetLockedDocuments() + public function testGetLockedDocuments(): void { $subject = 'http://talisaspire.com/works/lockedDoc'; $this->lockDocument($subject, 'transaction_100'); $docs = $this->tripod->getLockedDocuments(); - $this->assertEquals(1, count($docs)); + $this->assertCount(1, $docs); $this->assertEquals($docs[0]['_id']['r'], $subject); - $this->assertEquals($docs[0][_LOCKED_FOR_TRANS], 'transaction_100'); + $this->assertEquals('transaction_100', $docs[0][_LOCKED_FOR_TRANS]); } - public function testGetLockedDocumentsWithFromDateOnly() + public function testGetLockedDocumentsWithFromDateOnly(): void { $subject = 'http://talisaspire.com/works/lockedDoc'; $this->lockDocument($subject, 'transaction_100'); $docs = $this->tripod->getLockedDocuments(date('y-m-d H:i:s', strtotime('+1 min'))); - $this->assertEquals(0, count($docs)); + $this->assertCount(0, $docs); $docs = $this->tripod->getLockedDocuments(date('y-m-d H:i:s', strtotime('-1 min'))); - $this->assertEquals(1, count($docs)); + $this->assertCount(1, $docs); } - public function testGetLockedDocumentsWithTillDateOnly() + public function testGetLockedDocumentsWithTillDateOnly(): void { $subject = 'http://talisaspire.com/works/lockedDoc'; $this->lockDocument($subject, 'transaction_100'); $docs = $this->tripod->getLockedDocuments(null, date('y-m-d H:i:s', strtotime('+1 min'))); - $this->assertEquals(1, count($docs)); + $this->assertCount(1, $docs); $docs = $this->tripod->getLockedDocuments(null, date('y-m-d H:i:s', strtotime('-1 min'))); - $this->assertEquals(0, count($docs)); + $this->assertCount(0, $docs); } - public function testGetLockedDocumentsWithDateRange() + public function testGetLockedDocumentsWithDateRange(): void { $subject = 'http://talisaspire.com/works/lockedDoc'; $this->lockDocument($subject, 'transaction_100'); $docs = $this->tripod->getLockedDocuments(date('y-m-d H:i:s', strtotime('-1 min')), date('y-m-d H:i:s', strtotime('+1 min'))); - $this->assertEquals(1, count($docs)); + $this->assertCount(1, $docs); $docs = $this->tripod->getLockedDocuments(date('y-m-d H:i:s', strtotime('+1 min')), date('y-m-d H:i:s', strtotime('+2 min'))); - $this->assertEquals(0, count($docs)); + $this->assertCount(0, $docs); } /** END: getLockedDocuments tests */ /** START: removeInertLocks tests */ - public function testRemoveInertLocksNoLocksFound() + public function testRemoveInertLocksNoLocksFound(): void { $this->assertFalse($this->tripod->removeInertLocks('transaction_100', 'Unit tests')); } - public function testRemoveInertLocksNotAllLocksAreRemoved() + public function testRemoveInertLocksNotAllLocksAreRemoved(): void { $subjectOne = 'http://talisaspire.com/works/lockedDoc'; $subjectTwo = 'http://basedata.com/b/1'; @@ -1882,14 +1900,14 @@ public function testRemoveInertLocksNotAllLocksAreRemoved() $this->lockDocument($subjectTwo, 'transaction_200'); $docs = $this->tripod->getLockedDocuments(); - $this->assertEquals(2, count($docs)); + $this->assertCount(2, $docs); $this->tripod->removeInertLocks('transaction_200', 'Unit tests'); $docs = $this->tripod->getLockedDocuments(); - $this->assertEquals(1, count($docs)); + $this->assertCount(1, $docs); } - public function testRemoveInertLocksCreateAuditEntryThrowsException() + public function testRemoveInertLocksCreateAuditEntryThrowsException(): void { $subject = 'http://basedata.com/b/1'; $this->lockDocument($subject, 'transaction_400'); @@ -1903,7 +1921,7 @@ public function testRemoveInertLocksCreateAuditEntryThrowsException() ->getMock(); $auditManualRollbackCollection->expects($this->once()) ->method('insertOne') - ->will($this->throwException(new Exception('Some unexpected error occurred.'))); + ->willThrowException(new Exception('Some unexpected error occurred.')); $tripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) @@ -1917,16 +1935,16 @@ public function testRemoveInertLocksCreateAuditEntryThrowsException() $tripodUpdate ->expects($this->once()) ->method('getAuditManualRollbacksCollection') - ->will($this->returnValue($auditManualRollbackCollection)); + ->willReturn($auditManualRollbackCollection); $tripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdate)); + ->willReturn($tripodUpdate); $tripod->removeInertLocks('transaction_400', 'Unit tests'); } - public function testRemoveInertLocksUnlockAllDocumentsFailsVerifyErrorEntryInAuditLog() + public function testRemoveInertLocksUnlockAllDocumentsFailsVerifyErrorEntryInAuditLog(): void { $subject = 'http://basedata.com/b/1'; $this->lockDocument($subject, 'transaction_400'); @@ -1949,11 +1967,11 @@ public function testRemoveInertLocksUnlockAllDocumentsFailsVerifyErrorEntryInAud $mockInsert ->expects($this->once()) ->method('isAcknowledged') - ->will($this->returnValue(true)); + ->willReturn(true); $auditManualRollbackCollection->expects($this->once()) ->method('insertOne') - ->will($this->returnValue($mockInsert)); + ->willReturn($mockInsert); $mockUpdate = $this->getMockBuilder(UpdateResult::class) ->disableOriginalConstructor() @@ -1962,12 +1980,12 @@ public function testRemoveInertLocksUnlockAllDocumentsFailsVerifyErrorEntryInAud $mockUpdate ->expects($this->once()) ->method('isAcknowledged') - ->will($this->returnValue(true)); + ->willReturn(true); $auditManualRollbackCollection->expects($this->once()) ->method('updateOne') ->with(['_id' => $mongoDocumentId], ['$set' => ['status' => AUDIT_STATUS_ERROR, _UPDATED_TS => $mongoDate, 'error' => 'Some unexpected error occurred.']]) - ->will($this->returnValue($mockUpdate)); + ->willReturn($mockUpdate); $tripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) @@ -1980,28 +1998,28 @@ public function testRemoveInertLocksUnlockAllDocumentsFailsVerifyErrorEntryInAud $tripodUpdate->expects($this->once()) ->method('generateIdForNewMongoDocument') - ->will($this->returnValue($mongoDocumentId)); + ->willReturn($mongoDocumentId); $tripodUpdate->expects($this->exactly(2)) ->method('getMongoDate') - ->will($this->returnValue($mongoDate)); + ->willReturn($mongoDate); $tripodUpdate->expects($this->once()) ->method('getAuditManualRollbacksCollection') - ->will($this->returnValue($auditManualRollbackCollection)); + ->willReturn($auditManualRollbackCollection); $tripodUpdate->expects($this->once()) ->method('unlockAllDocuments') - ->will($this->throwException(new Exception('Some unexpected error occurred.'))); + ->willThrowException(new Exception('Some unexpected error occurred.')); $tripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdate)); + ->willReturn($tripodUpdate); $tripod->removeInertLocks('transaction_400', 'Unit tests'); } - public function testRemoveInertLocksUnlockSuccessfulVerifyAuditLog() + public function testRemoveInertLocksUnlockSuccessfulVerifyAuditLog(): void { $subject = 'http://basedata.com/b/1'; $subject2 = 'tenantData:1'; @@ -2023,7 +2041,7 @@ public function testRemoveInertLocksUnlockSuccessfulVerifyAuditLog() $mockInsert ->expects($this->once()) ->method('isAcknowledged') - ->will($this->returnValue(true)); + ->willReturn(true); $mockUpdate = $this->getMockBuilder(UpdateResult::class) ->disableOriginalConstructor() @@ -2032,7 +2050,7 @@ public function testRemoveInertLocksUnlockSuccessfulVerifyAuditLog() $mockUpdate ->expects($this->once()) ->method('isAcknowledged') - ->will($this->returnValue(true)); + ->willReturn(true); $auditManualRollbackCollection->expects($this->once()) ->method('insertOne') @@ -2045,12 +2063,12 @@ public function testRemoveInertLocksUnlockSuccessfulVerifyAuditLog() 'documents' => ['baseData:1', 'tenantData:1'], _CREATED_TS => $mongoDate, ]) - ->will($this->returnValue($mockInsert)); + ->willReturn($mockInsert); $auditManualRollbackCollection->expects($this->once()) ->method('updateOne') ->with(['_id' => $mongoDocumentId], ['$set' => ['status' => AUDIT_STATUS_COMPLETED, _UPDATED_TS => $mongoDate]]) - ->will($this->returnValue($mockUpdate)); + ->willReturn($mockUpdate); $tripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) @@ -2063,38 +2081,38 @@ public function testRemoveInertLocksUnlockSuccessfulVerifyAuditLog() $tripodUpdate->expects($this->once()) ->method('generateIdForNewMongoDocument') - ->will($this->returnValue($mongoDocumentId)); + ->willReturn($mongoDocumentId); $tripodUpdate->expects($this->once()) ->method('getAuditManualRollbacksCollection') - ->will($this->returnValue($auditManualRollbackCollection)); + ->willReturn($auditManualRollbackCollection); $tripodUpdate->expects($this->exactly(2)) ->method('getMongoDate') - ->will($this->returnValue($mongoDate)); + ->willReturn($mongoDate); $tripodUpdate->expects($this->once()) ->method('unlockAllDocuments') - ->will($this->returnValue(true)); + ->willReturn(true); $tripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdate)); + ->willReturn($tripodUpdate); $this->assertTrue($tripod->removeInertLocks('transaction_400', 'Unit tests')); } - public function testRemoveInertLocks() + public function testRemoveInertLocks(): void { $subject = 'http://basedata.com/b/1'; $this->lockDocument($subject, 'transaction_100'); $this->tripod->removeInertLocks('transaction_100', 'Unit tests'); $docs = $this->tripod->getLockedDocuments(); - $this->assertEquals(0, count($docs)); + $this->assertCount(0, $docs); } - public function testStatsD() + public function testStatsD(): void { $mockStatsD = $this->getMockBuilder(StatsD::class) ->onlyMethods(['send']) @@ -2106,9 +2124,9 @@ public function testStatsD() ->onlyMethods(['getStat']) ->setConstructorArgs(['CBD_testing', 'tripod_php_testing', ['defaultContext' => 'http://talisaspire.com/', 'statsDHost' => 'localhost', 'statsDPort' => '2012', 'statsDPrefix' => 'myapp']]) ->getMock(); - $mockTripod->expects($this->any()) + $mockTripod ->method('getStat') - ->will($this->returnValue($mockStatsD)); + ->willReturn($mockStatsD); $mockStatsD->expects($this->once()) ->method('send') @@ -2124,7 +2142,7 @@ public function testStatsD() /** END: removeInertLocks tests */ /** START: saveChangesHooks tests */ - public function testRegisteredHooksAreCalled() + public function testRegisteredHooksAreCalled(): void { $mockHookA = $this->getMockBuilder(TestSaveChangesHookA::class) ->onlyMethods(['pre', 'success', 'failure']) @@ -2148,7 +2166,7 @@ public function testRegisteredHooksAreCalled() $this->tripod->saveChanges(new ExtendedGraph(), new ExtendedGraph()); } - public function testRegisteredSuccessHooksAreNotCalledOnException() + public function testRegisteredSuccessHooksAreNotCalledOnException(): void { $this->expectException(Tripod\Exceptions\Exception::class); $this->expectExceptionMessage('Could not validate'); @@ -2182,7 +2200,7 @@ public function testRegisteredSuccessHooksAreNotCalledOnException() $tripodUpdate->saveChanges(new ExtendedGraph(), new ExtendedGraph()); } - public function testMisbehavingHookDoesNotPreventSaveOrInterfereWithOtherHooks() + public function testMisbehavingHookDoesNotPreventSaveOrInterfereWithOtherHooks(): void { $mockHookA = $this->getMockBuilder(TestSaveChangesHookA::class) ->onlyMethods(['pre', 'success', 'failure']) @@ -2193,8 +2211,8 @@ public function testMisbehavingHookDoesNotPreventSaveOrInterfereWithOtherHooks() ->disableOriginalConstructor() ->getMock(); - $mockHookA->expects($this->once())->method('pre')->will($this->throwException(new Exception('Misbehaving hook'))); - $mockHookA->expects($this->once())->method('success')->will($this->throwException(new Exception('Misbehaving hook'))); + $mockHookA->expects($this->once())->method('pre')->willThrowException(new Exception('Misbehaving hook')); + $mockHookA->expects($this->once())->method('success')->willThrowException(new Exception('Misbehaving hook')); $mockHookA->expects($this->never())->method('failure'); $mockHookB->expects($this->once())->method('pre'); $mockHookB->expects($this->once())->method('success'); @@ -2207,7 +2225,7 @@ public function testMisbehavingHookDoesNotPreventSaveOrInterfereWithOtherHooks() } /** END: saveChangesHooks tests */ - public function testPassStatConfigToTripodConstructor() + public function testPassStatConfigToTripodConstructor(): void { $statsDConfig = $this->getStatsDConfig(); $opts = ['statsConfig' => $statsDConfig]; @@ -2221,7 +2239,7 @@ public function testPassStatConfigToTripodConstructor() $tripod->expects($this->once()) ->method('getStatFromStatFactory') ->with($opts['statsConfig']) - ->will($this->returnValue($mockStat)); + ->willReturn($mockStat); /** @var StatsD */ $stat = $tripod->getStat(); @@ -2254,7 +2272,7 @@ public function testPassStatConfigToTripodConstructor() } /** START: getETag tests */ - public function testEtagIsMicrotimeFormat() + public function testEtagIsMicrotimeFormat(): void { $config = Config::getInstance(); $updatedAt = DateUtil::getMongoDate(); @@ -2275,11 +2293,12 @@ public function testEtagIsMicrotimeFormat() )->insertOne($doc, ['w' => 1]); $tripod = new Driver('CBD_testing', 'tripod_php_testing', ['defaultContext' => 'http://talisaspire.com/']); - $this->assertMatchesRegularExpression('/^0.[0-9]{8} [0-9]{10}/', $tripod->getETag($_id['r'])); + $this->assertMatchesRegularExpression('/^0.\d{8} \d{10}/', $tripod->getETag($_id['r'])); } // END: getETag tests } + class TestSaveChangesHookA implements IEventHook { /** @@ -2288,7 +2307,7 @@ class TestSaveChangesHookA implements IEventHook * * @param $args array of arguments */ - public function pre(array $args) + public function pre(array $args): void { // do nothing } @@ -2300,17 +2319,15 @@ public function pre(array $args) * * @param $args array of arguments */ - public function success(array $args) + public function success(array $args): void { // do nothing } /** * This method gets called if the event failed for any reason. The arguments passed should be the same as IEventHook::pre. - * - * @return mixed */ - public function failure(array $args) + public function failure(array $args): void { // do nothing } @@ -2329,7 +2346,7 @@ class TripodDriverTestConfig extends Tripod\Mongo\Config */ public function __construct() {} - public function loadConfig(array $config) + protected function loadConfig(array $config) { parent::loadConfig($config); } diff --git a/test/unit/mongo/MongoTripodNQuadSerializerTest.php b/test/unit/mongo/MongoTripodNQuadSerializerTest.php index bbf715a1..53ac2c37 100644 --- a/test/unit/mongo/MongoTripodNQuadSerializerTest.php +++ b/test/unit/mongo/MongoTripodNQuadSerializerTest.php @@ -1,5 +1,7 @@ add_literal_triple('http://example.com/1', $g->qname_to_uri('dct:title'), 'some literal title'); @@ -26,7 +28,7 @@ public function testSerializerSimple() $this->assertEquals($expected, $actual); } - public function testSerializerWithMultipleSubjects() + public function testSerializerWithMultipleSubjects(): void { $g = new MongoGraph(); $docs = json_decode(file_get_contents(__DIR__ . '/data/resources.json'), true); @@ -172,7 +174,7 @@ public function testSerializerWithMultipleSubjects() // this test now asserts that each line in $expected has been serialised correctly, without failing // due to new test data. foreach (preg_split("/((\r?\n)|(\r\n?))/", $expected) as $expectedLine) { - $this->assertTrue(strpos($actual, rtrim($expectedLine)) !== false, 'Failed checking for line: ' . rtrim($expectedLine)); + $this->assertStringContainsString(rtrim($expectedLine), $actual, 'Failed checking for line: ' . rtrim($expectedLine)); } } } diff --git a/test/unit/mongo/MongoTripodQueueOperationsTest.php b/test/unit/mongo/MongoTripodQueueOperationsTest.php index ec0ce515..592094ff 100644 --- a/test/unit/mongo/MongoTripodQueueOperationsTest.php +++ b/test/unit/mongo/MongoTripodQueueOperationsTest.php @@ -1,5 +1,7 @@ getMockBuilder(Driver::class) @@ -66,7 +68,7 @@ public function testSingleItemIsAddedToQueueForChangeToSingleSubject() $tripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdates)); + ->willReturn($tripodUpdates); $subjectsAndPredicatesOfChange = [ 'http://talisaspire.com/resources/doc1' => ['dct:subject'], @@ -86,7 +88,7 @@ public function testSingleItemIsAddedToQueueForChangeToSingleSubject() $tripodUpdates->expects($this->once()) ->method('getDiscoverImpactedSubjects') - ->will($this->returnValue($discoverImpactedSubjects)); + ->willReturn($discoverImpactedSubjects); $discoverImpactedSubjects->expects($this->once()) ->method('createJob') @@ -109,7 +111,7 @@ public function testSingleItemIsAddedToQueueForChangeToSingleSubject() /** * Saving a change to a single resource that does not impact any other resources should result in just a single item being added to the queue. */ - public function testSingleItemWithViewsOpIsAddedToQueueForChangeToSingleSubject() + public function testSingleItemWithViewsOpIsAddedToQueueForChangeToSingleSubject(): void { // create a tripod instance that will send all operations to the queue $tripod = $this->getMockBuilder(Driver::class) @@ -141,7 +143,7 @@ public function testSingleItemWithViewsOpIsAddedToQueueForChangeToSingleSubject( $tripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdates)); + ->willReturn($tripodUpdates); $subjectsAndPredicatesOfChange = [ 'http://talisaspire.com/resources/doc1' => ['dct:subject'], @@ -165,7 +167,7 @@ public function testSingleItemWithViewsOpIsAddedToQueueForChangeToSingleSubject( $tripodUpdates->expects($this->once()) ->method('getDiscoverImpactedSubjects') - ->will($this->returnValue($discoverImpactedSubjects)); + ->willReturn($discoverImpactedSubjects); $discoverImpactedSubjects->expects($this->once()) ->method('createJob') @@ -185,7 +187,7 @@ public function testSingleItemWithViewsOpIsAddedToQueueForChangeToSingleSubject( $tripod->saveChanges($g1, $g2); } - public function testNoItemIsAddedToQueueForChangeToSingleSubjectWithNoAsyncOps() + public function testNoItemIsAddedToQueueForChangeToSingleSubjectWithNoAsyncOps(): void { // create a tripod instance that will send all operations to the queue $tripod = $this->getMockBuilder(Driver::class) @@ -213,7 +215,7 @@ public function testNoItemIsAddedToQueueForChangeToSingleSubjectWithNoAsyncOps() $tripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdates)); + ->willReturn($tripodUpdates); $subjectsAndPredicatesOfChange = [ 'http://talisaspire.com/resources/doc1' => ['dct:subject'], @@ -245,7 +247,7 @@ public function testNoItemIsAddedToQueueForChangeToSingleSubjectWithNoAsyncOps() * 4 items being placed on the queue, with the operations for each relevant to the configured operations based on the specifications * todo: new test in composite for one subject that impacts another. */ - public function testSingleJobSubmittedToQueueForChangeToSeveralSubjects() + public function testSingleJobSubmittedToQueueForChangeToSeveralSubjects(): void { $tripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater', 'getComposite']) @@ -276,7 +278,7 @@ public function testSingleJobSubmittedToQueueForChangeToSeveralSubjects() $tripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdates)); + ->willReturn($tripodUpdates); $subjectsAndPredicatesOfChange = [ 'http://talisaspire.com/resources/doc1' => ['dct:date'], @@ -298,7 +300,7 @@ public function testSingleJobSubmittedToQueueForChangeToSeveralSubjects() $tripodUpdates->expects($this->once()) ->method('getDiscoverImpactedSubjects') - ->will($this->returnValue($discoverImpactedSubjects)); + ->willReturn($discoverImpactedSubjects); $discoverImpactedSubjects->expects($this->once()) ->method('createJob') diff --git a/test/unit/mongo/MongoTripodSearchDocumentsTest.php b/test/unit/mongo/MongoTripodSearchDocumentsTest.php index 6ff3fcc2..2383847b 100644 --- a/test/unit/mongo/MongoTripodSearchDocumentsTest.php +++ b/test/unit/mongo/MongoTripodSearchDocumentsTest.php @@ -1,5 +1,7 @@ expectException(Exception::class); $this->expectExceptionMessage('Resource must be specified'); @@ -37,7 +39,7 @@ public function testGenerateSearchDocumentBasedOnSpecIdThrowsExceptionWithEmptyR $searchDocuments->generateSearchDocumentBasedOnSpecId('i_search_resource', null, 'http://talisaspire.com/'); } - public function testGenerateSearchDocumentBasedOnSpecIdThrowsExceptionWithEmptyContext() + public function testGenerateSearchDocumentBasedOnSpecIdThrowsExceptionWithEmptyContext(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('Context must be specified'); @@ -45,7 +47,7 @@ public function testGenerateSearchDocumentBasedOnSpecIdThrowsExceptionWithEmptyC $searchDocuments->generateSearchDocumentBasedOnSpecId('i_search_resource', 'http://talisaspire.com/resource/1', null); } - public function testGenerateSearchDocumentBasedOnSpecIdReturnNullForInvalidSearchSpecId() + public function testGenerateSearchDocumentBasedOnSpecIdReturnNullForInvalidSearchSpecId(): void { $mockSearchDocuments = $this->getMockBuilder(SearchDocuments::class) ->onlyMethods(['getSearchDocumentSpecification']) @@ -54,26 +56,26 @@ public function testGenerateSearchDocumentBasedOnSpecIdReturnNullForInvalidSearc $mockSearchDocuments->expects($this->once()) ->method('getSearchDocumentSpecification') - ->will($this->returnValue(null)); + ->willReturn(null); $generatedDocuments = $mockSearchDocuments->generateSearchDocumentBasedOnSpecId('i_search_something', 'http://talisaspire.com/resource/1', 'http://talisaspire.com/'); $this->assertNull($generatedDocuments); } - public function testGenerateSearchDocumentBasedOnSpecIdReturnNullIfNoMatchForResourceFound() + public function testGenerateSearchDocumentBasedOnSpecIdReturnNullIfNoMatchForResourceFound(): void { $searchDocuments = $this->getSearchDocuments($this->tripod); $generatedDocuments = $searchDocuments->generateSearchDocumentBasedOnSpecId('i_search_resource', 'http://talisaspire.com/resource/1', 'http://talisaspire.com/'); $this->assertNull($generatedDocuments); } - public function testGenerateSearchDocumentBasedOnSpecId() + public function testGenerateSearchDocumentBasedOnSpecId(): void { $searchDocuments = $this->getSearchDocuments($this->tripod); $generatedDocuments = $searchDocuments->generateSearchDocumentBasedOnSpecId('i_search_resource', 'http://talisaspire.com/resources/doc1', 'http://talisaspire.com/'); $this->assertEquals('http://talisaspire.com/resources/doc1', $generatedDocuments['_id']['r']); } - public function testGenerateSearchDocumentPreservesDiacritics() + public function testGenerateSearchDocumentPreservesDiacritics(): void { $searchDocuments = $this->getSearchDocuments($this->tripod); $generatedDocuments = $searchDocuments->generateSearchDocumentBasedOnSpecId('i_search_resource', 'http://talisaspire.com/resources/doc13', 'http://talisaspire.com/'); @@ -82,7 +84,7 @@ public function testGenerateSearchDocumentPreservesDiacritics() $this->assertEquals('http://talisaspire.com/resources/doc13', $generatedDocuments['_id']['r']); } - public function testGenerateSearchDocumentBasedOnSpecIdWithFieldNamePredicatesHavingNoValueInCollection() + public function testGenerateSearchDocumentBasedOnSpecIdWithFieldNamePredicatesHavingNoValueInCollection(): void { $searchSpecs = json_decode('{"_id":"i_search_resource","type":["bibo:Book"],"from":"CBD_testing","filter":[{"condition":{"dct:title.l":{"$exists":true}}}],"indices":[{"fieldName":"search_terms","predicates":["dct:title","dct:subject"]},{"fieldName":"other_terms","predicates":["rdf:type"]}],"fields":[{"fieldName":"result.title","predicates":["dct:title"],"limit":1},{"fieldName":"result.link","value":"link"},{"fieldName":"rdftype","predicates":["rdf:type"],"limit":1}],"joins":{"dct:creator":{"indices":[{"fieldName":"search_terms","predicates":["foaf:name"]}],"fields":[{"fieldName":"result.author","predicates":["foaf:name"],"limit":1}, {"fieldName":"result.role","predicates":["siocAccess:Role"], "limit":1}] } }}', true); @@ -93,14 +95,14 @@ public function testGenerateSearchDocumentBasedOnSpecIdWithFieldNamePredicatesHa $mockSearchDocuments->expects($this->once()) ->method('getSearchDocumentSpecification') - ->will($this->returnValue($searchSpecs)); + ->willReturn($searchSpecs); $generatedDocuments = $mockSearchDocuments->generateSearchDocumentBasedOnSpecId('i_search_resource', 'http://talisaspire.com/resources/doc1', 'http://talisaspire.com/'); $this->assertNotNull($generatedDocuments); $this->assertEquals('http://talisaspire.com/resources/doc1', $generatedDocuments['_id']['r']); } - public function testSearchDocumentsGenerateWhenDefinedPredicateChanges() + public function testSearchDocumentsGenerateWhenDefinedPredicateChanges(): void { $uri = 'http://talisaspire.com/resources/doc1'; @@ -128,7 +130,7 @@ public function testSearchDocumentsGenerateWhenDefinedPredicateChanges() $searchIndexer->expects($this->once()) ->method('getSearchDocumentGenerator') - ->will($this->returnValue($searchDocuments)); + ->willReturn($searchDocuments); $searchDocuments->expects($this->once()) ->method('generateSearchDocumentBasedOnSpecId') @@ -156,7 +158,7 @@ public function testSearchDocumentsGenerateWhenDefinedPredicateChanges() } } - public function testSearchDocsShouldRegenerateWhenUndefinedPredicateChangesButFilterExistsInSpec() + public function testSearchDocsShouldRegenerateWhenUndefinedPredicateChangesButFilterExistsInSpec(): void { $uri = 'http://talisaspire.com/resources/doc1'; @@ -180,7 +182,7 @@ public function testSearchDocsShouldRegenerateWhenUndefinedPredicateChangesButFi $this->assertEmpty($impactedSubjects[0]->getSpecTypes()); } - public function testUpdateOfResourceInImpactIndexTriggersRegenerationOfSearchDocs() + public function testUpdateOfResourceInImpactIndexTriggersRegenerationOfSearchDocs(): void { $uri = 'http://talisaspire.com/authors/2'; $labeller = new Labeller(); @@ -212,7 +214,7 @@ public function testUpdateOfResourceInImpactIndexTriggersRegenerationOfSearchDoc $searchIndexer->expects($this->once()) ->method('getSearchDocumentGenerator') - ->will($this->returnValue($searchDocuments)); + ->willReturn($searchDocuments); $searchDocuments->expects($this->once()) ->method('generateSearchDocumentBasedOnSpecId') @@ -240,7 +242,7 @@ public function testUpdateOfResourceInImpactIndexTriggersRegenerationOfSearchDoc } } - public function testRdfTypeTriggersGenerationOfSearchDocuments() + public function testRdfTypeTriggersGenerationOfSearchDocuments(): void { $uri = 'http://example.com/resources/' . uniqid(); @@ -293,7 +295,7 @@ public function testRdfTypeTriggersGenerationOfSearchDocuments() $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockTripodUpdates->expects($this->once()) ->method('processSyncOperations') @@ -326,7 +328,7 @@ public function testRdfTypeTriggersGenerationOfSearchDocuments() $searchIndexer->expects($this->once()) ->method('getSearchDocumentGenerator') - ->will($this->returnValue($searchDocuments)); + ->willReturn($searchDocuments); $searchDocuments->expects($this->once()) ->method('generateSearchDocumentBasedOnSpecId') @@ -356,7 +358,7 @@ public function testRdfTypeTriggersGenerationOfSearchDocuments() } } - public function testNewResourceThatDoesNotMatchAnythingCreatesNoImpactedSubjects() + public function testNewResourceThatDoesNotMatchAnythingCreatesNoImpactedSubjects(): void { $uri = 'http://example.com/resources/' . uniqid(); $labeller = new Labeller(); @@ -405,7 +407,7 @@ public function testNewResourceThatDoesNotMatchAnythingCreatesNoImpactedSubjects $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockTripodUpdates->expects($this->once()) ->method('processSyncOperations') @@ -428,7 +430,7 @@ public function testNewResourceThatDoesNotMatchAnythingCreatesNoImpactedSubjects $this->assertEmpty($searchIndexer->getImpactedSubjects($subjectsAndPredicatesOfChange, $this->defaultContext)); } - public function testDeleteResourceCreatesImpactedSubjects() + public function testDeleteResourceCreatesImpactedSubjects(): void { $uri = 'http://example.com/resources/' . uniqid(); $labeller = new Labeller(); @@ -586,7 +588,7 @@ public function testDeleteResourceCreatesImpactedSubjects() $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $expectedSubjectsAndPredicatesOfChange = [ $creatorUriAlias => ['rdf:type', 'foaf:name'], @@ -664,10 +666,7 @@ public function testDeleteResourceCreatesImpactedSubjects() $this->assertEquals(0, $collection->count($impactQuery)); } - /** - * @return SearchDocuments - */ - protected function getSearchDocuments(Driver $tripod) + protected function getSearchDocuments(Driver $tripod): \Tripod\Mongo\SearchDocuments { return new SearchDocuments( $tripod->getStoreName(), diff --git a/test/unit/mongo/MongoTripodSearchIndexerTest.php b/test/unit/mongo/MongoTripodSearchIndexerTest.php index a2cb922f..31c664a5 100644 --- a/test/unit/mongo/MongoTripodSearchIndexerTest.php +++ b/test/unit/mongo/MongoTripodSearchIndexerTest.php @@ -1,5 +1,7 @@ getCollectionsForSearch($this->tripod->getStoreName()) as $collection) { $collection->drop(); } + $this->loadResourceDataViaTripod(); $this->loadBaseSearchDataViaTripod(); } - public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() + public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged(): void { // First make a change that affects a search document $tripod = $this->getMockBuilder(Driver::class) @@ -68,11 +71,11 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() $tripodUpdate->expects($this->atLeastOnce()) ->method('storeChanges') - ->will($this->returnValue(['subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange, 'transaction_id' => 't1234'])); + ->willReturn(['subjectsAndPredicatesOfChange' => $subjectsAndPredicatesOfChange, 'transaction_id' => 't1234']); $tripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdate)); + ->willReturn($tripodUpdate); $searchIndexer = $this->getMockBuilder(SearchIndexer::class) ->onlyMethods(['getSearchProvider', 'getImpactedSubjects']) @@ -89,7 +92,7 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() ->with( $this->matchesRegularExpression('/http:\/\/talisaspire\.com\/resources\/doc(1|2|3)$/'), 'http://talisaspire.com/', - $this->equalTo(['i_search_resource']) + ['i_search_resource'] ); $searchProvider->expects($this->exactly(3)) @@ -97,7 +100,7 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() $searchIndexer->expects($this->atLeastOnce()) ->method('getSearchProvider') - ->will($this->returnValue($searchProvider)); + ->willReturn($searchProvider); $impactedSubjects = [ $this->getMockBuilder(ImpactedSubject::class) @@ -147,18 +150,18 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() ->getMock(), ]; - $impactedSubjects[0]->expects($this->once())->method('getTripod')->will($this->returnValue($tripod)); - $impactedSubjects[1]->expects($this->once())->method('getTripod')->will($this->returnValue($tripod)); - $impactedSubjects[2]->expects($this->once())->method('getTripod')->will($this->returnValue($tripod)); + $impactedSubjects[0]->expects($this->once())->method('getTripod')->willReturn($tripod); + $impactedSubjects[1]->expects($this->once())->method('getTripod')->willReturn($tripod); + $impactedSubjects[2]->expects($this->once())->method('getTripod')->willReturn($tripod); $searchIndexer->expects($this->once()) ->method('getImpactedSubjects') ->with($subjectsAndPredicatesOfChange, 'http://talisaspire.com/') - ->will($this->returnValue($impactedSubjects)); + ->willReturn($impactedSubjects); $tripod->expects($this->atLeastOnce()) ->method('getSearchIndexer') - ->will($this->returnValue($searchIndexer)); + ->willReturn($searchIndexer); $g1 = $tripod->describeResource('http://talisaspire.com/authors/1'); $g2 = $tripod->describeResource('http://talisaspire.com/authors/1'); @@ -196,7 +199,7 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() $searchProvider->expects($this->exactly(1)) ->method('deleteDocument') ->with( - $this->equalTo('http://talisaspire.com/lists/1234'), + 'http://talisaspire.com/lists/1234', 'http://talisaspire.com/', $this->isEmpty() ); @@ -206,7 +209,7 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() $searchIndexer->expects($this->atLeastOnce()) ->method('getSearchProvider') - ->will($this->returnValue($searchProvider)); + ->willReturn($searchProvider); $impactedSubject = $this->getMockBuilder(ImpactedSubject::class) ->setConstructorArgs( @@ -223,13 +226,13 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() ->onlyMethods(['getTripod']) ->getMock(); - $impactedSubject->expects($this->once())->method('getTripod')->will($this->returnValue($tripod)); + $impactedSubject->expects($this->once())->method('getTripod')->willReturn($tripod); - $searchIndexer->expects($this->once())->method('getImpactedSubjects')->will($this->returnValue([$impactedSubject])); + $searchIndexer->expects($this->once())->method('getImpactedSubjects')->willReturn([$impactedSubject]); $tripod->expects($this->atLeastOnce()) ->method('getSearchIndexer') - ->will($this->returnValue($searchIndexer)); + ->willReturn($searchIndexer); $list = new ExtendedGraph(); $list->add_resource_triple('http://talisaspire.com/lists/1234', RDF_TYPE, 'http://purl.org/vocab/resourcelist/schema#List'); @@ -287,12 +290,12 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() ->onlyMethods(['getTripod']) ->getMock(); - $impactedSubject->expects($this->once())->method('getTripod')->will($this->returnValue($tripod)); + $impactedSubject->expects($this->once())->method('getTripod')->willReturn($tripod); $searchProvider->expects($this->exactly(1)) ->method('deleteDocument') ->with( - $this->equalTo('http://talisaspire.com/lists/1234'), + 'http://talisaspire.com/lists/1234', 'http://talisaspire.com/', ['i_search_list'] ); @@ -302,13 +305,13 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() $searchIndexer->expects($this->atLeastOnce()) ->method('getSearchProvider') - ->will($this->returnValue($searchProvider)); + ->willReturn($searchProvider); - $searchIndexer->expects($this->once())->method('getImpactedSubjects')->will($this->returnValue([$impactedSubject])); + $searchIndexer->expects($this->once())->method('getImpactedSubjects')->willReturn([$impactedSubject]); $tripod->expects($this->atLeastOnce()) ->method('getSearchIndexer') - ->will($this->returnValue($searchIndexer)); + ->willReturn($searchIndexer); $oldList = $tripod->describeResource('http://talisaspire.com/lists/1234'); $list = $tripod->describeResource('http://talisaspire.com/lists/1234'); @@ -325,7 +328,7 @@ public function testSearchDocumentsRegenerateWhenDefinedPredicateChanged() ); } - public function testSearchDocumentsNotRegeneratedIfChangeIsNotInSearchSpec() + public function testSearchDocumentsNotRegeneratedIfChangeIsNotInSearchSpec(): void { // Now make a change that shouldn't affect any search docs $tripod = $this->getMockBuilder(Driver::class) @@ -360,11 +363,11 @@ public function testSearchDocumentsNotRegeneratedIfChangeIsNotInSearchSpec() ->getMock(); $tripodUpdate->expects($this->atLeastOnce()) ->method('storeChanges') - ->will($this->returnValue(['deletedSubjects' => [], 'subjectsAndPredicatesOfChange' => [], 'transaction_id' => 't1234'])); + ->willReturn(['deletedSubjects' => [], 'subjectsAndPredicatesOfChange' => [], 'transaction_id' => 't1234']); $tripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdate)); + ->willReturn($tripodUpdate); $searchIndexer = $this->getMockBuilder(SearchIndexer::class) ->onlyMethods(['getSearchProvider', 'update']) @@ -382,20 +385,21 @@ public function testSearchDocumentsNotRegeneratedIfChangeIsNotInSearchSpec() $searchProvider->expects($this->never()) ->method('indexDocument'); - $searchIndexer->expects($this->any()) + $searchIndexer ->method('getSearchProvider') - ->will($this->returnValue($searchProvider)); + ->willReturn($searchProvider); $searchIndexer->expects($this->never()) ->method('update'); $tripod->expects($this->atLeastOnce()) ->method('getSearchIndexer') - ->will($this->returnValue($searchIndexer)); + ->willReturn($searchIndexer); $g1 = $tripod->describeResource('http://talisaspire.com/authors/1'); $g2 = $tripod->describeResource('http://talisaspire.com/authors/1'); $g2->add_literal_triple('http://talisaspire.com/authors/1', $g2->qname_to_uri('foaf:dob'), '1564-04-26'); + $tripod->saveChanges($g1, $g2); } @@ -403,7 +407,7 @@ public function testSearchDocumentsNotRegeneratedIfChangeIsNotInSearchSpec() * Save several new resources in a single operation. Only one of the resources has a type that is applicable based on specifications, * therefore only one ImpactedSubject should be created. */ - public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() + public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject(): void { $tripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) @@ -440,7 +444,7 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() $tripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdates)); + ->willReturn($tripodUpdates); // first lets add a book, which should trigger a search doc, view and table gen for a single item $g = new MongoGraph(); @@ -466,6 +470,7 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri('dct:title'), 'This is yet another new resource'); $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri('dct:subject'), 'art'); $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri('dct:subject'), 'design'); + $subjectsAndPredicatesOfChange = [ $newSubjectUri1 => ['rdf:type', 'dct:creator', 'dct:title', 'dct:subject'], $newSubjectUri2 => ['rdf:type', 'dct:creator', 'dct:title', 'dct:subject'], @@ -492,7 +497,7 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() $this->assertEquals($expectedImpactedSubjects, $impactedSubjects); } - public function testBatchSearchDocumentsGeneration() + public function testBatchSearchDocumentsGeneration(): void { $count = 234; $docs = []; diff --git a/test/unit/mongo/MongoTripodStatTest.php b/test/unit/mongo/MongoTripodStatTest.php index 457b8dfc..496e8d20 100644 --- a/test/unit/mongo/MongoTripodStatTest.php +++ b/test/unit/mongo/MongoTripodStatTest.php @@ -1,12 +1,14 @@ getStatsDConfig(); @@ -21,7 +23,7 @@ public function testStatFactory() $this->assertInstanceOf(NoStat::class, $noStat); } - public function testStatsDSettersAndGetters() + public function testStatsDSettersAndGetters(): void { $stat = StatsD::createFromConfig($this->getStatsDConfig()); @@ -49,7 +51,7 @@ public function testStatsDSettersAndGetters() $this->assertEquals(['class' => StatsD::class, 'config' => ['host' => 'bar.baz', 'port' => 4567, 'prefix' => 'FOO_BAR']], $stat->getConfig()); } - public function testStatsDIncrementNoPrefix() + public function testStatsDIncrementNoPrefix(): void { $statConfig = $this->getStatsDConfig(); @@ -64,7 +66,7 @@ public function testStatsDIncrementNoPrefix() $stat->increment('FOO.BAR'); } - public function testStatsDIncrementWithPivotValueNoPrefix() + public function testStatsDIncrementWithPivotValueNoPrefix(): void { $statConfig = $this->getStatsDConfig(); @@ -84,7 +86,7 @@ public function testStatsDIncrementWithPivotValueNoPrefix() $stat->increment('FOO.BAR'); } - public function testStatsDIncrementWithPrefix() + public function testStatsDIncrementWithPrefix(): void { $statConfig = $this->getStatsDConfig(); @@ -99,7 +101,7 @@ public function testStatsDIncrementWithPrefix() $stat->increment('FOO.BAR'); } - public function testStatsDIncrementWithPivotValueAndPrefix() + public function testStatsDIncrementWithPivotValueAndPrefix(): void { $statConfig = $this->getStatsDConfig(); @@ -117,7 +119,7 @@ public function testStatsDIncrementWithPivotValueAndPrefix() $stat->increment('FOO.BAR', 5); } - public function testStatsDTimerNoPrefix() + public function testStatsDTimerNoPrefix(): void { $statConfig = $this->getStatsDConfig(); @@ -132,7 +134,7 @@ public function testStatsDTimerNoPrefix() $stat->timer('FOO.BAR', 1234); } - public function testStatsDTimerWithPivotValueNoPrefix() + public function testStatsDTimerWithPivotValueNoPrefix(): void { $statConfig = $this->getStatsDConfig(); @@ -150,7 +152,7 @@ public function testStatsDTimerWithPivotValueNoPrefix() $stat->timer('FOO.BAR', 1234); } - public function testStatsDTimerWithPrefix() + public function testStatsDTimerWithPrefix(): void { $statConfig = $this->getStatsDConfig(); @@ -165,7 +167,7 @@ public function testStatsDTimerWithPrefix() $stat->timer('FOO.BAR', 4567); } - public function testStatsDTimerWithPrefixAndPivotValue() + public function testStatsDTimerWithPrefixAndPivotValue(): void { $statConfig = $this->getStatsDConfig(); @@ -183,7 +185,7 @@ public function testStatsDTimerWithPrefixAndPivotValue() $stat->timer('FOO.BAR', 4567); } - public function testStatsDGaugeNoPrefix() + public function testStatsDGaugeNoPrefix(): void { $statConfig = $this->getStatsDConfig(); @@ -198,7 +200,7 @@ public function testStatsDGaugeNoPrefix() $stat->gauge('FOO.BAR', 'xyz'); } - public function testStatsDGaugeWithPivotValueNoPrefix() + public function testStatsDGaugeWithPivotValueNoPrefix(): void { $statConfig = $this->getStatsDConfig(); @@ -216,7 +218,7 @@ public function testStatsDGaugeWithPivotValueNoPrefix() $stat->gauge('FOO.BAR', 'xyz'); } - public function testStatsDGaugeWithPrefix() + public function testStatsDGaugeWithPrefix(): void { $statConfig = $this->getStatsDConfig(); @@ -231,7 +233,7 @@ public function testStatsDGaugeWithPrefix() $stat->gauge('FOO.BAR', 'abc'); } - public function testStatsDGaugeWithPrefixAndPivotValue() + public function testStatsDGaugeWithPrefixAndPivotValue(): void { $statConfig = $this->getStatsDConfig(); @@ -249,31 +251,31 @@ public function testStatsDGaugeWithPrefixAndPivotValue() $stat->gauge('FOO.BAR', 'abc'); } - public function testPrefixCannotStartWithDot() + public function testPrefixCannotStartWithDot(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid prefix supplied'); - $stat = new StatsD('foo.bar', 4567, '.some_prefix'); + new StatsD('foo.bar', 4567, '.some_prefix'); } - public function testPrefixCannotEndWithDot() + public function testPrefixCannotEndWithDot(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid prefix supplied'); - $stat = new StatsD('foo.bar', 4567, 'some_prefix.'); + new StatsD('foo.bar', 4567, 'some_prefix.'); } - public function testPrefixCannotContainConsecutiveDot() + public function testPrefixCannotContainConsecutiveDot(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid prefix supplied'); - $stat = new StatsD('foo.bar', 4567, 'some..prefix'); + new StatsD('foo.bar', 4567, 'some..prefix'); } - public function testPivotValueCannotStartWithDot() + public function testPivotValueCannotStartWithDot(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid pivot value supplied'); @@ -282,7 +284,7 @@ public function testPivotValueCannotStartWithDot() $stat->setPivotValue('.someValue'); } - public function testPivotValueCannotEndWithDot() + public function testPivotValueCannotEndWithDot(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid pivot value supplied'); @@ -291,7 +293,7 @@ public function testPivotValueCannotEndWithDot() $stat->setPivotValue('someValue.'); } - public function testPivotValueCannotContainConsecutiveDot() + public function testPivotValueCannotContainConsecutiveDot(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid pivot value supplied'); diff --git a/test/unit/mongo/MongoTripodTablesTest.php b/test/unit/mongo/MongoTripodTablesTest.php index 0ad9a914..81b7e3f4 100644 --- a/test/unit/mongo/MongoTripodTablesTest.php +++ b/test/unit/mongo/MongoTripodTablesTest.php @@ -1,5 +1,7 @@ tripodTables->generateTableRows('t_resource', 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA-2'); @@ -89,6 +91,7 @@ public function testTripodSaveChangesUpdatesLiteralTripleInTable() $g2 = $this->tripod->describeResource('http://talisaspire.com/works/4d101f63c10a6'); $g2->add_literal_triple('http://talisaspire.com/works/4d101f63c10a6', $g2->qname_to_uri('bibo:isbn13'), '9780393929691-3'); + $this->tripod->saveChanges($g1, $g2, 'http://talisaspire.com/'); $t2 = $this->tripodTables->getTableRows('t_resource', ['_id.r' => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA-2']); @@ -97,14 +100,14 @@ public function testTripodSaveChangesUpdatesLiteralTripleInTable() $this->assertEquals($expectedIsbn13s, $t2['results'][0]['isbn13']); } - public function testGenerateTableRowsWithCounts() + public function testGenerateTableRowsWithCounts(): void { $this->tripodTables->generateTableRows('t_source_count'); $t1 = $this->tripodTables->getTableRows('t_source_count'); // expecting two rows - $this->assertEquals(count($t1['results']), 3); + $this->assertCount(3, $t1['results']); $result = $t1['results'][0]; // check out the columns @@ -115,14 +118,14 @@ public function testGenerateTableRowsWithCounts() $this->assertArrayHasKey('isbn13', $result, 'Result does not contain isbn13'); } - public function testGenerateTableRowsWithCountUpdateAndRequery() + public function testGenerateTableRowsWithCountUpdateAndRequery(): void { $this->tripodTables->generateTableRows('t_source_count'); $t1 = $this->tripodTables->getTableRows('t_source_count'); // expecting two rows - $this->assertEquals(count($t1['results']), 3); + $this->assertCount(3, $t1['results']); $result = $t1['results'][0]; // check out the columns @@ -143,14 +146,14 @@ public function testGenerateTableRowsWithCountUpdateAndRequery() $t2 = $this->tripodTables->getTableRows('t_source_count'); $result = null; - $this->assertEquals(count($t2['results']), 3); + $this->assertCount(3, $t2['results']); foreach ($t2['results'] as $r) { if ($r['_id']['r'] == $subject) { $result = $r; } } - $this->assertNotNull($result, "Cound not find table row for {$subject}"); + $this->assertNotNull($result, 'Cound not find table row for ' . $subject); // check out the columns $this->assertArrayHasKey('type', $result, 'Result does not contain type'); $this->assertArrayHasKey('source_count', $result, 'Result does not contain source_count'); @@ -158,14 +161,14 @@ public function testGenerateTableRowsWithCountUpdateAndRequery() $this->assertArrayHasKey('isbn13', $result, 'Result does not contain isbn13'); } - public function testGenerateTableRowsWithCountAndRegexUpdateAndRequery() + public function testGenerateTableRowsWithCountAndRegexUpdateAndRequery(): void { $this->tripodTables->generateTableRows('t_source_count_regex'); $t1 = $this->tripodTables->getTableRows('t_source_count_regex'); // expecting two rows - $this->assertEquals(count($t1['results']), 3); + $this->assertCount(3, $t1['results']); $result = $t1['results'][0]; // check out the columns @@ -188,14 +191,14 @@ public function testGenerateTableRowsWithCountAndRegexUpdateAndRequery() $t2 = $this->tripodTables->getTableRows('t_source_count_regex'); $result = null; - $this->assertEquals(count($t2['results']), 3); + $this->assertCount(3, $t2['results']); foreach ($t2['results'] as $r) { if ($r['_id']['r'] == $subject) { $result = $r; } } - $this->assertNotNull($result, "Could not find table row for {$subject}"); + $this->assertNotNull($result, 'Could not find table row for ' . $subject); // check out the columns $this->assertArrayHasKey('type', $result, 'Result does not contain type'); $this->assertArrayHasKey('source_count', $result, 'Result does not contain source_count'); @@ -204,14 +207,14 @@ public function testGenerateTableRowsWithCountAndRegexUpdateAndRequery() $this->assertArrayHasKey('isbn13', $result, 'Result does not contain isbn13'); } - public function testGenerateTableRowsWithCountOnJoinAndRegexUpdateAndRequery() + public function testGenerateTableRowsWithCountOnJoinAndRegexUpdateAndRequery(): void { $this->tripodTables->generateTableRows('t_join_source_count_regex'); $t1 = $this->tripodTables->getTableRows('t_join_source_count_regex', ['_id.r' => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA-2']); // expecting two rows - $this->assertEquals(count($t1['results']), 1); + $this->assertCount(1, $t1['results']); $result = $t1['results'][0]; // check out the columns @@ -228,7 +231,7 @@ public function testGenerateTableRowsWithCountOnJoinAndRegexUpdateAndRequery() $t2 = $this->tripodTables->getTableRows('t_join_source_count_regex', ['_id.r' => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA-2']); - $this->assertEquals(count($t2['results']), 1); + $this->assertCount(1, $t2['results']); $result = $t2['results'][0]; // check out the columns @@ -236,7 +239,7 @@ public function testGenerateTableRowsWithCountOnJoinAndRegexUpdateAndRequery() $this->assertEquals(4, $result['titles_count']); } - public function testUpdateWillDeleteItem() + public function testUpdateWillDeleteItem(): void { $mockTables = $this->getMockBuilder(Tripod\Mongo\Composites\Tables::class) ->onlyMethods(['deleteTableRowsForResource', 'generateTableRowsForType']) @@ -248,7 +251,7 @@ public function testUpdateWillDeleteItem() $mockTables->update(new ImpactedSubject(['r' => 'http://foo', 'c' => 'context'], OP_TABLES, 'foo', 'bar', ['t_table'])); } - public function testUpdateWillGenerateRows() + public function testUpdateWillGenerateRows(): void { $mockTables = $this->getMockBuilder(Tripod\Mongo\Composites\Tables::class) ->onlyMethods(['deleteTableRowsForResource', 'generateTableRowsForResource']) @@ -260,23 +263,23 @@ public function testUpdateWillGenerateRows() $mockTables->update(new ImpactedSubject(['r' => 'http://foo', 'c' => 'context'], OP_TABLES, 'foo', 'bar', ['t_table'])); } - public function testGenerateTableRows() + public function testGenerateTableRows(): void { $this->tripodTables->generateTableRows('t_resource'); $t1 = $this->tripodTables->getTableRows('t_resource'); // expecting two rows - $this->assertEquals(count($t1['results']), 3); + $this->assertCount(3, $t1['results']); $result = $t1['results'][0]; // check out the columns - $this->assertTrue(isset($result['type']), 'Result does not contain type'); - $this->assertTrue(isset($result['isbn']), 'Result does not contain isbn'); - $this->assertTrue(isset($result['isbn13']), 'Result does not contain isbn13'); + $this->assertArrayHasKey('type', $result, 'Result does not contain type'); + $this->assertArrayHasKey('isbn', $result, 'Result does not contain isbn'); + $this->assertArrayHasKey('isbn13', $result, 'Result does not contain isbn13'); } - public function testBatchTableRowGeneration() + public function testBatchTableRowGeneration(): void { $count = 234; $docs = []; @@ -341,7 +344,7 @@ public function testBatchTableRowGeneration() $tables->generateTableRows('t_resource', null, null, 'TESTQUEUE'); } - public function testGetTableRowsSort() + public function testGetTableRowsSort(): void { $this->tripodTables->generateTableRows('t_resource'); @@ -355,77 +358,77 @@ public function testGetTableRowsSort() $this->assertEquals('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', $t1['results'][0]['_id']['r']); } - public function testGetTableRowsFilter() + public function testGetTableRowsFilter(): void { $this->tripodTables->generateTableRows('t_resource'); $t1 = $this->tripodTables->getTableRows('t_resource', ['value.isbn' => '9780393929690']); // only bring back rows with isbn = 9780393929690 // expecting one row - $this->assertTrue(count($t1['results']) == 1); + $this->assertCount(1, $t1['results']); $this->assertEquals('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', $t1['results'][0]['_id']['r']); } - public function testGetTableRowsLimitOffset() + public function testGetTableRowsLimitOffset(): void { $this->tripodTables->generateTableRows('t_resource'); $t1 = $this->tripodTables->getTableRows('t_resource', [], ['value.isbn' => 1], 0, 1); // expecting http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA - $this->assertTrue(count($t1['results']) == 1); + $this->assertCount(1, $t1['results']); $this->assertEquals('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', $t1['results'][0]['_id']['r']); $t2 = $this->tripodTables->getTableRows('t_resource', [], ['value.isbn' => 1], 1, 1); // expecting http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA-2 - $this->assertTrue(count($t2['results']) == 1); + $this->assertCount(1, $t2['results']); $this->assertEquals('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA-2', $t2['results'][0]['_id']['r']); } - public function testGenerateTableRowsForResourceUnnamespaced() + public function testGenerateTableRowsForResourceUnnamespaced(): void { $this->tripodTables->update(new ImpactedSubject(['r' => 'http://basedata.com/b/2', 'c' => 'http://basedata.com/b/DefaultGraph'], OP_TABLES, $this->tripodTables->getStoreName(), $this->tripodTables->getPodName(), ['t_work2'])); $rows = $this->tripodTables->getTableRows('t_work2'); - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); } - public function testGenerateTableRowsForResourceNamespaced() + public function testGenerateTableRowsForResourceNamespaced(): void { $this->tripodTables->update(new ImpactedSubject(['r' => 'baseData:2', 'c' => 'baseData:DefaultGraph'], OP_TABLES, $this->tripodTables->getStoreName(), $this->tripodTables->getPodName(), ['t_work2'])); $rows = $this->tripodTables->getTableRows('t_work2'); - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); } - public function testGenerateTableRowsForResourceContextNamespaced() + public function testGenerateTableRowsForResourceContextNamespaced(): void { $this->tripodTables->update(new ImpactedSubject(['r' => 'http://basedata.com/b/2', 'c' => 'baseData:DefaultGraph'], OP_TABLES, $this->tripodTables->getStoreName(), $this->tripodTables->getPodName(), ['t_work2'])); $rows = $this->tripodTables->getTableRows('t_work2'); - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); } - public function testGenerateTableRowsForResourceResourceNamespaced() + public function testGenerateTableRowsForResourceResourceNamespaced(): void { $this->tripodTables->update(new ImpactedSubject(['r' => 'baseData:2', 'c' => 'http://basedata.com/b/DefaultGraph'], OP_TABLES, $this->tripodTables->getStoreName(), $this->tripodTables->getPodName(), ['t_work2'])); $rows = $this->tripodTables->getTableRows('t_work2'); - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); } - public function testGenerateTableRowsForResourcesOfTypeWithNamespace() + public function testGenerateTableRowsForResourcesOfTypeWithNamespace(): void { $mockTripodTables = $this->getMockBuilder(Tripod\Mongo\Composites\Tables::class) ->onlyMethods(['generateTableRows']) ->setConstructorArgs([$this->tripod->getStoreName(), $this->getTripodCollection($this->tripod), 'http://talisaspire.com/']) ->getMock(); - $mockTripodTables->expects($this->atLeastOnce())->method('generateTableRows')->will($this->returnValue(['ok' => true])); + $mockTripodTables->expects($this->atLeastOnce())->method('generateTableRows')->willReturn(['ok' => true]); // check where referred to as acorn:Work2 in spec... $mockTripodTables->generateTableRowsForType('http://talisaspire.com/schema#Work2'); @@ -434,7 +437,7 @@ public function testGenerateTableRowsForResourcesOfTypeWithNamespace() ->onlyMethods(['generateTableRows']) ->setConstructorArgs([$this->tripod->getStoreName(), $this->getTripodCollection($this->tripod), 'http://talisaspire.com/']) ->getMock(); - $mockTripodTables->expects($this->atLeastOnce())->method('generateTableRows')->will($this->returnValue(['ok' => true])); + $mockTripodTables->expects($this->atLeastOnce())->method('generateTableRows')->willReturn(['ok' => true]); // check where referred to as http://talisaspire.com/schema#Resource in spec... $mockTripodTables->generateTableRowsForType('acorn:Resource'); @@ -443,7 +446,7 @@ public function testGenerateTableRowsForResourcesOfTypeWithNamespace() /** * Test table specification predicate modifier config. */ - public function testGenerateTableRowsForUsersWithModifiersValidConfig() + public function testGenerateTableRowsForUsersWithModifiersValidConfig(): void { $this->expectNotToPerformAssertions(); @@ -506,7 +509,7 @@ public function testGenerateTableRowsForUsersWithModifiersValidConfig() /** * Test invalid table specification predicate modifier config - use a bad attribute. */ - public function testGenerateTableRowsForUsersWithModifiersInvalidConfigBadGlue() + public function testGenerateTableRowsForUsersWithModifiersInvalidConfigBadGlue(): void { $this->expectException(ConfigException::class); $this->expectExceptionMessage("Invalid modifier: 'glue2' in key 'join'"); @@ -536,13 +539,13 @@ public function testGenerateTableRowsForUsersWithModifiersInvalidConfigBadGlue() /** * Test table rows have been generated successfully for a "join" modifier. */ - public function testGenerateTableRowsForUsersWithModifiersJoin() + public function testGenerateTableRowsForUsersWithModifiersJoin(): void { // Get table rows $rows = $this->generateTableRows('t_users'); // We should have 1 result and it should have modified fields - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); $this->assertEquals('Harry Potter', $rows['results'][0]['join']); } @@ -550,13 +553,13 @@ public function testGenerateTableRowsForUsersWithModifiersJoin() /** * Test table rows have been generated for a "join" modifier but with a single value rather than an array. */ - public function testGenerateTableRowsForUsersWithModifiersJoinSingle() + public function testGenerateTableRowsForUsersWithModifiersJoinSingle(): void { // Get table rows $rows = $this->generateTableRows('t_users'); // We should have 1 result and it should have modified fields - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); $this->assertEquals('Harry', $rows['results'][0]['joinSingle']); } @@ -564,13 +567,13 @@ public function testGenerateTableRowsForUsersWithModifiersJoinSingle() /** * Test table rows have been generated for a "lowercase" modifier with a "join" inside it. */ - public function testGenerateTableRowsForUsersWithModifiersJoinLowerCase() + public function testGenerateTableRowsForUsersWithModifiersJoinLowerCase(): void { // Get table rows $rows = $this->generateTableRows('t_users'); // We should have 1 result and it should have modified fields - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); $this->assertEquals('harry potter', $rows['results'][0]['joinLowerCase']); } @@ -578,13 +581,13 @@ public function testGenerateTableRowsForUsersWithModifiersJoinLowerCase() /** * Test table rows have been generated for a "date" modifier. */ - public function testGenerateTableRowsForUsersWithModifiersMongoDate() + public function testGenerateTableRowsForUsersWithModifiersMongoDate(): void { // Get table rows $rows = $this->generateTableRows('t_users'); // We should have 1 result and it should have modified fields - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); $this->assertInstanceOf(UTCDateTime::class, $rows['results'][0]['mongoDate']); } @@ -592,13 +595,13 @@ public function testGenerateTableRowsForUsersWithModifiersMongoDate() /** * Test table rows have been generated for a "date" modifier but with a value that does not exist. */ - public function testGenerateTableRowsForUsersWithModifiersMongoDateDoesNotExist() + public function testGenerateTableRowsForUsersWithModifiersMongoDateDoesNotExist(): void { // Get table rows $rows = $this->generateTableRows('t_users'); // We should have 1 result and it should have modified fields - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); // Test for data that doesn't exist $this->assertArrayNotHasKey('mongoDateDoesNotExist', $rows['results'][0]); @@ -608,13 +611,13 @@ public function testGenerateTableRowsForUsersWithModifiersMongoDateDoesNotExist( * Test table rows have been generated for a "lowercase" modifier wtih a "join" modifier inside. It also has an * extra field attached to the row as well. */ - public function testGenerateTableRowsForUsersWithModifiersJoinLowerCaseAndExtraField() + public function testGenerateTableRowsForUsersWithModifiersJoinLowerCaseAndExtraField(): void { // Get table rows $rows = $this->generateTableRows('t_users'); // We should have 1 result and it should have modified fields - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); $this->assertArrayHasKey('joinLowerCaseANDExtraField', $rows['results'][0]); $this->assertIsArray($rows['results'][0]['joinLowerCaseANDExtraField']); @@ -625,13 +628,13 @@ public function testGenerateTableRowsForUsersWithModifiersJoinLowerCaseAndExtraF /** * Test table rows have been generated for a "date" modifier but with an invalid date string. */ - public function testGenerateTableRowsForUsersWithModifiersDateInvalid() + public function testGenerateTableRowsForUsersWithModifiersDateInvalid(): void { // Get table rows $rows = $this->generateTableRows('t_users'); // We should have 1 result and it should have modified fields - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); // Check borked data // Trying to use date but passed in a string - should default to 0 for sec and usec @@ -642,13 +645,13 @@ public function testGenerateTableRowsForUsersWithModifiersDateInvalid() /** * Test table rows have been generated for a "lowercase" modifier around a "date" modifier. */ - public function testGenerateTableRowsForUsersWithModifiersLowercaseDate() + public function testGenerateTableRowsForUsersWithModifiersLowercaseDate(): void { // Get table rows $rows = $this->generateTableRows('t_users'); // We should have 1 result and it should have modified fields - $this->assertTrue($rows['head']['count'] == 1, 'Expected one row'); + $this->assertEquals(1, $rows['head']['count'], 'Expected one row'); // Lowercasing a mongodate object should be the same as running a __toString() on the date object $this->assertEquals($rows['results'][0]['mongoDate']->__toString(), $rows['results'][0]['lowercaseDate']); @@ -657,7 +660,7 @@ public function testGenerateTableRowsForUsersWithModifiersLowercaseDate() /** * Test table rows are tuncated if they are too large to index. */ - public function testGenerateTableRowsTruncatesFieldsTooLargeToIndex() + public function testGenerateTableRowsTruncatesFieldsTooLargeToIndex(): void { $fullTitle = 'Mahommah Gardo Baquaqua. Biography of Mahommah G. Baquaqua, a Native of Zoogoo, in the Interior of Africa. (A Convert to Christianity,) With a Description of That Part of the World; Including the Manners and Customs of the Inhabitants, Their Religious Notions, Form of Government, Laws, Appearance of the Country, Buildings, Agriculture, Manufactures, Shepherds and Herdsmen, Domestic Animals, Marriage Ceremonials, Funeral Services, Styles of Dress, Trade and Commerce, Modes of Warfare, System of Slavery, &c., &c. Mahommah's Early Life, His Education, His Capture and Slavery in Western Africa and Brazil, His Escape to the United States, from Thence to Hayti, (the City of Port Au Prince,) His Reception by the Baptist Missionary There, The Rev. W. L. Judd; His Conversion to Christianity, Baptism, and Return to This Country, His Views, Objects and Aim. Written and Revised from His Own Words, by Samuel Moore, Esq., Late Publisher of the "North of England Shipping Gazette," Author of Several Popular Works, and Editor of Sundry Reform Papers.'; $truncatedTitle = substr($fullTitle, 0, 1007); // 1007 = 1024 - index name "value_title_1" + Randomness @@ -674,13 +677,13 @@ public function testGenerateTableRowsTruncatesFieldsTooLargeToIndex() // Assert that the title starts with the truncated title. // This will be the case for both Mongo 2.4 and Mongo 2.6 - $this->assertTrue(strpos($rows['results'][0]['title'], $truncatedTitle) === 0, 'Unexpected title'); + $this->assertSame(0, strpos($rows['results'][0]['title'], $truncatedTitle), 'Unexpected title'); } /** * Test that link modifier is derived from the joined resource id, rather than base. */ - public function testJoinLinkValueIsForJoinedResource() + public function testJoinLinkValueIsForJoinedResource(): void { $this->tripodTables->generateTableRows('t_join_link'); $rows = $this->tripodTables->getTableRows('t_join_link', ['_id.r' => 'baseData:foo1234']); @@ -709,7 +712,7 @@ public function testJoinLinkValueIsForJoinedResource() * Test to ensure that impact index contains joined ids for resources that do not yet exist in the database (i.e. * allow open world model). */ - public function testPreviouslyUnavailableDataBecomesPresentAndTriggersTableRegen() + public function testPreviouslyUnavailableDataBecomesPresentAndTriggersTableRegen(): void { $this->tripodTables->generateTableRows('t_join_link'); $rows = $this->tripodTables->getTableRows('t_join_link', ['_id.r' => 'baseData:bar1234']); @@ -725,6 +728,7 @@ public function testPreviouslyUnavailableDataBecomesPresentAndTriggersTableRegen $g = new MongoGraph(); $g->add_resource_triple($uri, $g->qname_to_uri('rdf:type'), $g->qname_to_uri('foaf:Person')); $g->add_literal_triple($uri, $g->qname_to_uri('foaf:name'), 'A. Nonymous'); + $this->tripod->saveChanges(new MongoGraph(), $g, 'http://talisaspire.com/', "This resource didn't exist at join time"); $userGraph = $this->tripod->describeResource($uri); @@ -741,14 +745,14 @@ public function testPreviouslyUnavailableDataBecomesPresentAndTriggersTableRegen /** * Ensure that an array of links is returned if there are multiple resources matched by the join. */ - public function testLinkWorksOnRepeatingPredicatesForResource() + public function testLinkWorksOnRepeatingPredicatesForResource(): void { $this->tripodTables->generateTableRows('t_link_multiple'); $rows = $this->tripodTables->getTableRows('t_link_multiple', ['_id.r' => 'baseData:bar1234']); $this->assertEquals(1, $rows['head']['count']); $this->assertArrayHasKey('contributorLink', $rows['results'][0]); $this->assertTrue(is_array($rows['results'][0]['contributorLink'])); - $this->assertEquals(2, count($rows['results'][0]['contributorLink'])); + $this->assertCount(2, $rows['results'][0]['contributorLink']); $this->assertEquals('http://schemas.talis.com/2005/user/schema#10101', $rows['results'][0]['contributorLink'][0]); $this->assertEquals('http://schemas.talis.com/2005/user/schema#10102', $rows['results'][0]['contributorLink'][1]); } @@ -756,7 +760,7 @@ public function testLinkWorksOnRepeatingPredicatesForResource() /** * Return the distinct values of a table column. */ - public function testDistinct() + public function testDistinct(): void { // Get table rows $table = 't_distinct'; @@ -769,7 +773,7 @@ public function testDistinct() $this->assertArrayHasKey('count', $results['head']); $this->assertEquals(4, $results['head']['count']); $this->assertArrayHasKey('results', $results); - $this->assertEquals(4, count($results['results'])); + $this->assertCount(4, $results['results']); $this->assertContains('Physics 3rd Edition: Physics for Engineers and Scientists', $results['results']); $this->assertContains('A document title', $results['results']); $this->assertContains('Another document title', $results['results']); @@ -780,7 +784,7 @@ public function testDistinct() $this->assertArrayHasKey('count', $results['head']); $this->assertEquals(2, $results['head']['count']); $this->assertArrayHasKey('results', $results); - $this->assertEquals(2, count($results['results'])); + $this->assertCount(2, $results['results']); $this->assertNotContains('Physics 3rd Edition: Physics for Engineers and Scientists', $results['results']); $this->assertContains('A document title', $results['results']); $this->assertContains('Another document title', $results['results']); @@ -790,7 +794,7 @@ public function testDistinct() $this->assertArrayHasKey('count', $results['head']); $this->assertEquals(7, $results['head']['count']); $this->assertArrayHasKey('results', $results); - $this->assertEquals(7, count($results['results'])); + $this->assertCount(7, $results['results']); $this->assertContains('acorn:Resource', $results['results']); $this->assertContains('acorn:Work', $results['results']); $this->assertContains('bibo:Book', $results['results']); @@ -800,18 +804,18 @@ public function testDistinct() /** * Return no results for tablespec that doesn't exist. */ - public function testDistinctOnTableSpecThatDoesNotExist() + public function testDistinctOnTableSpecThatDoesNotExist(): void { $table = 't_nothing_to_see_here'; $this->expectException(ConfigException::class); - $this->expectExceptionMessage('Table id \'t_nothing_to_see_here\' not in configuration'); - $results = $this->tripodTables->distinct($table, 'value.foo'); + $this->expectExceptionMessage("Table id 't_nothing_to_see_here' not in configuration"); + $this->tripodTables->distinct($table, 'value.foo'); } /** * Return no results for distinct on a fieldname that is not defined in tableSpec. */ - public function testDistinctOnFieldNameThatIsNotInTableSpec() + public function testDistinctOnFieldNameThatIsNotInTableSpec(): void { // Get table rows $table = 't_distinct'; @@ -825,7 +829,7 @@ public function testDistinctOnFieldNameThatIsNotInTableSpec() /** * Return no results for filters that match no table rows. */ - public function testDistinctForFilterWithNoMatches() + public function testDistinctForFilterWithNoMatches(): void { // Get table rows $table = 't_distinct'; @@ -836,7 +840,7 @@ public function testDistinctForFilterWithNoMatches() $this->assertEmpty($results['results']); } - public function testTableRowsGenerateWhenDefinedPredicateChanges() + public function testTableRowsGenerateWhenDefinedPredicateChanges(): void { foreach (Config::getInstance()->getTableSpecifications($this->tripod->getStoreName()) as $specId => $spec) { $this->generateTableRows($specId); @@ -892,7 +896,7 @@ public function testTableRowsGenerateWhenDefinedPredicateChanges() $tripod->expects($this->once()) ->method('getComposite') ->with(OP_TABLES) - ->will($this->returnValue($tables)); + ->willReturn($tables); // Walk through the processSyncOperations process manually for tables @@ -944,7 +948,7 @@ public function testTableRowsGenerateWhenDefinedPredicateChanges() } } - public function testTableRowsNotGeneratedWhenUndefinedPredicateChanges() + public function testTableRowsNotGeneratedWhenUndefinedPredicateChanges(): void { foreach (Config::getInstance()->getTableSpecifications($this->tripod->getStoreName()) as $specId => $spec) { $this->generateTableRows($specId); @@ -970,7 +974,7 @@ public function testTableRowsNotGeneratedWhenUndefinedPredicateChanges() $this->assertEmpty($impactedSubjects); } - public function testUpdateOfResourceInImpactIndexTriggersRegenerationTableRows() + public function testUpdateOfResourceInImpactIndexTriggersRegenerationTableRows(): void { $mockTables = $this->getMockBuilder(Tripod\Mongo\Composites\Tables::class) ->onlyMethods(['generateTableRows']) @@ -1035,7 +1039,7 @@ public function testUpdateOfResourceInImpactIndexTriggersRegenerationTableRows() } } - public function testRdfTypeTriggersGenerationOfTableRows() + public function testRdfTypeTriggersGenerationOfTableRows(): void { $uri = 'http://example.com/resources/' . uniqid(); @@ -1088,7 +1092,7 @@ public function testRdfTypeTriggersGenerationOfTableRows() $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockTripodUpdates->expects($this->once()) ->method('processSyncOperations') @@ -1145,7 +1149,7 @@ public function testRdfTypeTriggersGenerationOfTableRows() } } - public function testUpdateToResourceWithMatchingRdfTypeShouldOnlyRegenerateIfRdfTypeIsPartOfUpdate() + public function testUpdateToResourceWithMatchingRdfTypeShouldOnlyRegenerateIfRdfTypeIsPartOfUpdate(): void { $uri = 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA'; $labeller = new Labeller(); @@ -1180,7 +1184,7 @@ public function testUpdateToResourceWithMatchingRdfTypeShouldOnlyRegenerateIfRdf $this->assertEquals($expectedImpactedSubjects, $impactedSubjects); } - public function testNewResourceThatDoesNotMatchAnythingCreatesNoImpactedSubjects() + public function testNewResourceThatDoesNotMatchAnythingCreatesNoImpactedSubjects(): void { $uri = 'http://example.com/resources/' . uniqid(); $labeller = new Labeller(); @@ -1229,7 +1233,7 @@ public function testNewResourceThatDoesNotMatchAnythingCreatesNoImpactedSubjects $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockTripodUpdates->expects($this->once()) ->method('processSyncOperations') @@ -1252,7 +1256,7 @@ public function testNewResourceThatDoesNotMatchAnythingCreatesNoImpactedSubjects $this->assertEmpty($tables->getImpactedSubjects($subjectsAndPredicatesOfChange, $this->defaultContext)); } - public function testDeleteResourceCreatesImpactedSubjects() + public function testDeleteResourceCreatesImpactedSubjects(): void { $uri = 'http://example.com/users/' . uniqid(); $labeller = new Labeller(); @@ -1292,7 +1296,7 @@ public function testDeleteResourceCreatesImpactedSubjects() $graph2->add_literal_triple( $uri2, $labeller->qname_to_uri('foaf:surname'), - 'O\'ther' + "O'ther" ); // Save the graphs and ensure that table rows are generated @@ -1368,7 +1372,7 @@ public function testDeleteResourceCreatesImpactedSubjects() $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $expectedSubjectsAndPredicatesOfChange = [ $uriAlias => ['rdf:type', 'foaf:firstName', 'foaf:surname'], @@ -1449,7 +1453,7 @@ public function testDeleteResourceCreatesImpactedSubjects() * Save several new resources in a single operation. Only one of the resources has a type that is applicable based on specifications, * therefore only one ImpactedSubject should be created. */ - public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() + public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject(): void { $tripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) @@ -1486,7 +1490,7 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() $tripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdates)); + ->willReturn($tripodUpdates); // first lets add a book, which should trigger a search doc, view and table gen for a single item $g = new MongoGraph(); @@ -1512,6 +1516,7 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri('dct:title'), 'This is yet another new resource'); $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri('dct:subject'), 'art'); $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri('dct:subject'), 'design'); + $subjectsAndPredicatesOfChange = [ $newSubjectUri1 => ['rdf:type', 'dct:creator', 'dct:title', 'dct:subject'], $newSubjectUri2 => ['rdf:type', 'dct:creator', 'dct:title', 'dct:subject'], @@ -1539,7 +1544,7 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() $this->assertEquals($expectedImpactedSubjects, $impactedSubjects); } - public function testRemoveTableSpecDoesNotAffectInvalidation() + public function testRemoveTableSpecDoesNotAffectInvalidation(): void { foreach (Config::getInstance()->getTableSpecifications($this->tripod->getStoreName()) as $specId => $spec) { $this->generateTableRows($specId); @@ -1588,7 +1593,7 @@ public function testRemoveTableSpecDoesNotAffectInvalidation() $mockTripod->expects($this->once()) ->method('getComposite') ->with(OP_TABLES) - ->will($this->returnValue($mockTables)); + ->willReturn($mockTables); $mockTables->expects($this->never()) ->method('update'); @@ -1603,7 +1608,7 @@ public function testRemoveTableSpecDoesNotAffectInvalidation() $this->assertGreaterThan(0, $collection->count(['_id.type' => 't_resource', 'value._impactIndex' => [_ID_RESOURCE => $uri, _ID_CONTEXT => $context]])); } - public function testCountTables() + public function testCountTables(): void { $collection = $this->getMockBuilder(Collection::class) ->setConstructorArgs([new Manager(), 'db', 'coll']) @@ -1617,19 +1622,19 @@ public function testCountTables() $tables->expects($this->once()) ->method('getCollectionForTableSpec') ->with('t_source_count') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('count') ->with(['_id.type' => 't_source_count']) - ->will($this->returnValue(50)); + ->willReturn(50); $this->assertEquals(50, $tables->count('t_source_count')); } - public function testCountTablesWithFilters() + public function testCountTablesWithFilters(): void { - $filters = ['_cts' => ['$lte' => new UTCDateTime(null)]]; + $filters = ['_cts' => ['$lte' => new UTCDateTime()]]; $query = array_merge(['_id.type' => 't_source_count'], $filters); $collection = $this->getMockBuilder(Collection::class) ->setConstructorArgs([new Manager(), 'db', 'coll']) @@ -1643,17 +1648,17 @@ public function testCountTablesWithFilters() $tables->expects($this->once()) ->method('getCollectionForTableSpec') ->with('t_source_count') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('count') ->with($query) - ->will($this->returnValue(37)); + ->willReturn(37); $this->assertEquals(37, $tables->count('t_source_count', $filters)); } - public function testDeleteTableRowsByTableId() + public function testDeleteTableRowsByTableId(): void { $collection = $this->getMockBuilder(Collection::class) ->setConstructorArgs([new Manager(), 'db', 'coll']) @@ -1667,7 +1672,7 @@ public function testDeleteTableRowsByTableId() $deleteResult->expects($this->once()) ->method('getDeletedCount') - ->will($this->returnValue(2)); + ->willReturn(2); $tables = $this->getMockBuilder(Tripod\Mongo\Composites\Tables::class) ->onlyMethods(['getCollectionForTableSpec']) @@ -1677,19 +1682,19 @@ public function testDeleteTableRowsByTableId() $tables->expects($this->once()) ->method('getCollectionForTableSpec') ->with('t_source_count') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('deleteMany') ->with(['_id.type' => 't_source_count']) - ->will($this->returnValue($deleteResult)); + ->willReturn($deleteResult); $this->assertEquals(2, $tables->deleteTableRowsByTableId('t_source_count')); } - public function testDeleteTableRowsByTableIdWithTimestamp() + public function testDeleteTableRowsByTableIdWithTimestamp(): void { - $timestamp = new UTCDateTime(null); + $timestamp = new UTCDateTime(); $query = [ '_id.type' => 't_source_count', @@ -1710,7 +1715,7 @@ public function testDeleteTableRowsByTableIdWithTimestamp() $deleteResult->expects($this->once()) ->method('getDeletedCount') - ->will($this->returnValue(11)); + ->willReturn(11); $tables = $this->getMockBuilder(Tripod\Mongo\Composites\Tables::class) ->onlyMethods(['getCollectionForTableSpec']) @@ -1720,17 +1725,17 @@ public function testDeleteTableRowsByTableIdWithTimestamp() $tables->expects($this->once()) ->method('getCollectionForTableSpec') ->with('t_source_count') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('deleteMany') ->with($query) - ->will($this->returnValue($deleteResult)); + ->willReturn($deleteResult); $this->assertEquals(11, $tables->deleteTableRowsByTableId('t_source_count', $timestamp)); } - public function testTablesDocuments() + public function testTablesDocuments(): void { $dbDoc = [ '_id' => [ @@ -1751,7 +1756,7 @@ public function testTablesDocuments() 'code' => 'XMEN-004', 'nodeUrl' => 'http://talis.com/modules/xmen-004', 'name' => 'Psychology: Living with The Voices', - 'description' => 'Professor Deadpool will attempt to give you the ability to embrace your mental disorder and use it to your advantage. Whether you suffer from Schizophrenia, Dissociative Identity Disorder or plain old Comic Awareness, Wade Wilson has probably suffered through it himself. And while Deadpool can\'t solve your problem, he can teach you how to make it one of your most marketable qualities.', + 'description' => "Professor Deadpool will attempt to give you the ability to embrace your mental disorder and use it to your advantage. Whether you suffer from Schizophrenia, Dissociative Identity Disorder or plain old Comic Awareness, Wade Wilson has probably suffered through it himself. And while Deadpool can't solve your problem, he can teach you how to make it one of your most marketable qualities.", 'parentCode' => 'XMEN-001', 'parentNodeUrl' => 'http://talis.com/schools/xmen-001', 'listCount' => 0, @@ -1770,7 +1775,7 @@ public function testTablesDocuments() $this->assertArrayNotHasKey('type', $doc['_id']); } - public function testGetTableRowsNoCount() + public function testGetTableRowsNoCount(): void { $this->tripodTables->generateTableRows('t_resource'); @@ -1780,7 +1785,7 @@ public function testGetTableRowsNoCount() $this->assertEquals(-1, $tableRows['head']['count']); } - public function testGetTableRowsReturnCursor() + public function testGetTableRowsReturnCursor(): void { $this->tripodTables->generateTableRows('t_resource'); @@ -1792,20 +1797,19 @@ public function testGetTableRowsReturnCursor() $this->assertInstanceOf(Tables::class, $result); $count++; } - $this->assertEquals(1, $count); + + $this->assertSame(1, $count); $this->assertGreaterThan(1, $tableRows['head']['count']); } /** * Generate dummy config that we can use for creating a Config object. * - * @return array + * @return array */ - private function generateMongoTripodTestConfig() + private function generateMongoTripodTestConfig(): array { - $config = []; - $config['defaultContext'] = 'http://talisaspire.com/'; - $config['data_sources'] = [ + return ['defaultContext' => 'http://talisaspire.com/', 'data_sources' => [ 'db' => [ 'type' => 'mongo', 'connection' => 'mongodb://localhost', @@ -1814,23 +1818,18 @@ private function generateMongoTripodTestConfig() 'type' => 'mongo', 'connection' => 'mongodb://tloghost:27017,tloghost:27018', ], - ]; - $config['stores'] = [ + ], 'stores' => [ $this->defaultStoreName => [ 'data_source' => 'db', 'pods' => [ $this->defaultPodName => [], ], ], - ]; - $config['queue'] = ['database' => 'queue', 'collection' => 'q_queue', 'data_source' => 'db']; - $config['transaction_log'] = [ + ], 'queue' => ['database' => 'queue', 'collection' => 'q_queue', 'data_source' => 'db'], 'transaction_log' => [ 'database' => 'transactions', 'collection' => 'transaction_log', 'data_source' => 'db', - ]; - - return $config; + ]]; } /** diff --git a/test/unit/mongo/MongoTripodTestBase.php b/test/unit/mongo/MongoTripodTestBase.php index eb7e71f1..65a2b324 100644 --- a/test/unit/mongo/MongoTripodTestBase.php +++ b/test/unit/mongo/MongoTripodTestBase.php @@ -1,5 +1,7 @@ %s\n", get_class($this), $this->getName()); @@ -149,6 +153,7 @@ protected function getDocument($_id, $collection = null, $fromTransactionLog = f if ($collection == null) { return $this->getTripodCollection($this->tripod)->findOne(['_id' => $_id]); } + if ($collection instanceof Driver) { return $this->getTripodCollection($collection)->findOne(['_id' => $_id]); } @@ -166,11 +171,13 @@ protected function assertChangesForGivenSubject(array $changes, $subjectOfChange $changeSet = null; foreach ($changes as $c) { - if (strpos($c['_id']['r'], '_:cs') !== false) { - if ($c['cs:subjectOfChange']['u'] == $subjectOfChange) { - $changeSet = $c; - } + if (strpos($c['_id']['r'], '_:cs') === false) { + continue; } + if ($c['cs:subjectOfChange']['u'] != $subjectOfChange) { + continue; + } + $changeSet = $c; } $this->assertNotNull($changeSet, 'No change set found for the specified subject of change'); @@ -183,6 +190,7 @@ protected function assertChangesForGivenSubject(array $changes, $subjectOfChange $actualAdditions = count($changeSet['cs:addition']); } } + $this->assertEquals($expectedNumberOfAdditions, $actualAdditions, 'Number of additions did not match expectd value'); $actualRemovals = 0; @@ -198,11 +206,11 @@ protected function assertChangesForGivenSubject(array $changes, $subjectOfChange } /** - * @param string $key + * @param array $doc */ - protected function assertTransactionDate(array $doc, $key) + protected function assertTransactionDate(array $doc, string $key) { - $this->assertTrue(isset($doc[$key]), 'the date property: {$key} was not present in document'); + $this->assertArrayHasKey($key, $doc, 'the date property: {$key} was not present in document'); $this->assertInstanceOf(UTCDateTime::class, $doc[$key]); $this->assertNotEmpty($doc[$key]->toDateTime()); } @@ -214,7 +222,7 @@ protected function assertTransactionDate(array $doc, $key) * @param Driver|null $tripod * @param bool $fromTransactionLog */ - protected function assertDocumentVersion($_id, $expectedValue = null, $hasVersion = true, $tripod = null, $fromTransactionLog = false) + protected function assertDocumentVersion(array $_id, $expectedValue = null, $hasVersion = true, $tripod = null, $fromTransactionLog = false) { // just make sure $_id is aliased $labeller = new Labeller(); @@ -224,14 +232,14 @@ protected function assertDocumentVersion($_id, $expectedValue = null, $hasVersio $doc = $this->getDocument($_id, $tripod, $fromTransactionLog); if ($hasVersion == true) { - $this->assertTrue(isset($doc['_version']), 'Document for ' . var_export($_id, true) . ' should have a version, but none found'); + $this->assertArrayHasKey('_version', $doc, 'Document for ' . var_export($_id, true) . ' should have a version, but none found'); if ($expectedValue !== null) { // echo $expectedValue.":".$doc['_version']; $this->assertEquals($expectedValue, $doc['_version'], 'Document version does not match expected version'); } } else { - $this->assertFalse(isset($doc['_version']), 'Was not expecting document to have a version'); + $this->assertArrayNotHasKey('_version', $doc, 'Was not expecting document to have a version'); } } @@ -252,9 +260,9 @@ protected function assertDocumentHasProperty(array $_id, $property, $expectedVal $doc = $this->getDocument($_id, $tripod, $fromTransactionLog); - $this->assertTrue(isset($doc[$property]), 'Document for ' . var_export($_id, true) . " should have property [{$property}], but none found"); + $this->assertArrayHasKey($property, $doc, 'Document for ' . var_export($_id, true) . sprintf(' should have property [%s], but none found', $property)); if ($expectedValue !== null) { - $this->assertEquals($expectedValue, $doc[$property], "Document property [{$property}] actual value [" . print_r($doc[$property], true) . '] does not match expected value [' . print_r($expectedValue, true) . ']'); + $this->assertEquals($expectedValue, $doc[$property], sprintf('Document property [%s] actual value [', $property) . print_r($doc[$property], true) . '] does not match expected value [' . print_r($expectedValue, true) . ']'); } } @@ -264,7 +272,7 @@ protected function assertDocumentHasProperty(array $_id, $property, $expectedVal * @param Collection|IDriver|null $tripod where to retrieve the document from * @param bool $fromTransactionLog if you want to retrieve the document from transaction log */ - protected function assertDocumentDoesNotHaveProperty($_id, $property, $tripod = null, $fromTransactionLog = false) + protected function assertDocumentDoesNotHaveProperty(array $_id, string $property, $tripod = null, $fromTransactionLog = false) { // just make sure $_id is aliased $labeller = new Labeller(); @@ -274,7 +282,7 @@ protected function assertDocumentDoesNotHaveProperty($_id, $property, $tripod = $doc = $this->getDocument($_id, $tripod, $fromTransactionLog); - $this->assertFalse(isset($doc[$property]), 'Document for ' . var_export($_id, true) . " should not have property [{$property}], but propert was found"); + $this->assertArrayNotHasKey($property, $doc, 'Document for ' . var_export($_id, true) . sprintf(' should not have property [%s], but propert was found', $property)); } /** @@ -294,15 +302,15 @@ protected function assertDocumentExists($_id, $tripod = null, $fromTransactionLo * @param Driver|null $tripod * @param bool $useTransactionTripod */ - protected function assertDocumentHasBeenDeleted($_id, $tripod = null, $useTransactionTripod = false) + protected function assertDocumentHasBeenDeleted(string $_id, $tripod = null, $useTransactionTripod = false) { $doc = $this->getDocument($_id, $tripod, $useTransactionTripod); if ($useTransactionTripod) { - $this->assertNull($doc, "Document with _id:[{$_id}] exists, but it should not"); + $this->assertNull($doc, sprintf('Document with _id:[%s] exists, but it should not', $_id)); } else { $this->assertTrue(is_array($doc), 'Document should be array'); $keys = array_keys($doc); - $this->assertEquals(4, count($keys)); + $this->assertCount(4, $keys); $this->assertArrayHasKey('_id', $doc); $this->assertArrayHasKey(_VERSION, $doc); $this->assertArrayHasKey(_CREATED_TS, $doc); @@ -311,43 +319,39 @@ protected function assertDocumentHasBeenDeleted($_id, $tripod = null, $useTransa } /** - * @param string $s * @param string $p * @param string $o */ - protected function assertHasLiteralTriple(ExtendedGraph $graph, $s, $p, $o) + protected function assertHasLiteralTriple(ExtendedGraph $graph, string $s, $p, $o) { - $this->assertTrue($graph->has_literal_triple($s, $p, $o), "Graph did not contain the literal triple: <{$s}> <{$p}> \"{$o}\""); + $this->assertTrue($graph->has_literal_triple($s, $p, $o), sprintf('Graph did not contain the literal triple: <%s> <%s> "%s"', $s, $p, $o)); } /** - * @param string $s * @param string $p * @param string $o */ - protected function assertHasResourceTriple(ExtendedGraph $graph, $s, $p, $o) + protected function assertHasResourceTriple(ExtendedGraph $graph, string $s, $p, $o) { - $this->assertTrue($graph->has_resource_triple($s, $p, $o), "Graph did not contain the resource triple: <{$s}> <{$p}> <{$o}>"); + $this->assertTrue($graph->has_resource_triple($s, $p, $o), sprintf('Graph did not contain the resource triple: <%s> <%s> <%s>', $s, $p, $o)); } /** - * @param string $s * @param string $p * @param string $o */ - protected function assertDoesNotHaveLiteralTriple(ExtendedGraph $graph, $s, $p, $o) + protected function assertDoesNotHaveLiteralTriple(ExtendedGraph $graph, string $s, $p, $o) { - $this->assertFalse($graph->has_literal_triple($s, $p, $o), "Graph should not contain the literal triple: <{$s}> <{$p}> \"{$o}\""); + $this->assertFalse($graph->has_literal_triple($s, $p, $o), sprintf('Graph should not contain the literal triple: <%s> <%s> "%s"', $s, $p, $o)); } /** - * @param string $s * @param string $p * @param string $o */ - protected function assertDoesNotHaveResourceTriple(ExtendedGraph $graph, $s, $p, $o) + protected function assertDoesNotHaveResourceTriple(ExtendedGraph $graph, string $s, $p, $o) { - $this->assertFalse($graph->has_resource_triple($s, $p, $o), "Graph should not contain the resource triple: <{$s}> <{$p}> <{$o}>"); + $this->assertFalse($graph->has_resource_triple($s, $p, $o), sprintf('Graph should not contain the resource triple: <%s> <%s> <%s>', $s, $p, $o)); } /** @@ -384,7 +388,7 @@ protected function getMockStat($host, $port, $prefix = '', array $mockedMethods } /** - * @return array + * @return array|array> */ protected function getStatsDConfig() { @@ -398,10 +402,7 @@ protected function getStatsDConfig() ]; } - /** - * @param string $filename - */ - private function loadDataViaTripod(Driver $tripod, $filename) + private function loadDataViaTripod(Driver $tripod, string $filename): void { $docs = json_decode(file_get_contents(__DIR__ . $filename), true); foreach ($docs as $d) { @@ -430,7 +431,7 @@ class TripodTestConfig extends Tripod\Mongo\Config */ public function __construct() {} - public function loadConfig(array $config) + protected function loadConfig(array $config) { parent::loadConfig($config); } diff --git a/test/unit/mongo/MongoTripodTransactionRollbackTest.php b/test/unit/mongo/MongoTripodTransactionRollbackTest.php index 413d24f8..cd28a884 100644 --- a/test/unit/mongo/MongoTripodTransactionRollbackTest.php +++ b/test/unit/mongo/MongoTripodTransactionRollbackTest.php @@ -1,5 +1,7 @@ tripod = $tripod; } - public function testTransactionRollbackDuringLockAllDocuments() + public function testTransactionRollbackDuringLockAllDocuments(): void { // Save some basic data into the db before we create a transaction to modify it $subjectOne = 'http://example.com/resources/1'; @@ -107,14 +109,14 @@ public function testTransactionRollbackDuringLockAllDocuments() $mockTripodUpdate->expects($this->exactly(1)) ->method('generateTransactionId') - ->will($this->returnValue($mockTransactionId)); + ->willReturn($mockTransactionId); $mockTripodUpdate->expects($this->exactly(2 * 20)) // 20 retries for 2 subjects ->method('lockSingleDocument') - ->will($this->returnCallback([$this, 'lockSingleDocumentCauseFailureCallback'])); + ->willReturnCallback([$this, 'lockSingleDocumentCauseFailureCallback']); $mockTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdate)); + ->willReturn($mockTripodUpdate); $mockTripod->setTransactionLog($this->tripodTransactionLog); @@ -147,7 +149,7 @@ public function testTransactionRollbackDuringLockAllDocuments() $this->assertEquals('failed', $transaction['status']); } - public function testTransactionRollbackDuringLockAllDocumentsWithEmptyOriginalCBDS() + public function testTransactionRollbackDuringLockAllDocumentsWithEmptyOriginalCBDS(): void { $subjectOne = 'http://example.com/resources/1'; $subjectTwo = 'http://example.com/resources/2'; @@ -174,14 +176,14 @@ public function testTransactionRollbackDuringLockAllDocumentsWithEmptyOriginalCB $mockTripodUpdate->expects($this->exactly(1)) ->method('generateTransactionId') - ->will($this->returnValue($mockTransactionId)); + ->willReturn($mockTransactionId); $mockTripodUpdate->expects($this->exactly(2 * 20)) // 20 retries for 2 subjects ->method('lockSingleDocument') - ->will($this->returnCallback([$this, 'lockSingleDocumentCauseFailureCallback'])); + ->willReturnCallback([$this, 'lockSingleDocumentCauseFailureCallback']); $mockTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdate)); + ->willReturn($mockTripodUpdate); $mockTripod->setTransactionLog($this->tripodTransactionLog); @@ -207,7 +209,7 @@ public function testTransactionRollbackDuringLockAllDocumentsWithEmptyOriginalCB $this->assertEquals('failed', $transaction['status']); } - public function testTransactionRollbackDuringCreateTransaction() + public function testTransactionRollbackDuringCreateTransaction(): void { // Save some basic data into the db before we create a transaction to modify it $subjectOne = 'http://example.com/resources/1'; @@ -259,13 +261,13 @@ public function testTransactionRollbackDuringCreateTransaction() ->getMock(); $mockTransactionLog->expects($this->once()) ->method('createNewTransaction') - ->will($this->throwException($mockExpectedException)); + ->willThrowException($mockExpectedException); $mockTransactionLog->expects($this->once()) ->method('cancelTransaction') - ->with($this->equalTo($mockTransactionId), $this->equalTo($mockExpectedException)); + ->with($mockTransactionId, $mockExpectedException); $mockTransactionLog->expects($this->once()) ->method('failTransaction') - ->with($this->equalTo($mockTransactionId)); + ->with($mockTransactionId); $mockTripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) @@ -278,16 +280,16 @@ public function testTransactionRollbackDuringCreateTransaction() $mockTripodUpdate->expects($this->once()) ->method('generateTransactionId') - ->will($this->returnValue($mockTransactionId)); + ->willReturn($mockTransactionId); $mockTripodUpdate->expects($this->exactly(2)) ->method('lockSingleDocument') - ->will($this->returnCallback([$this, 'lockSingleDocumentCallback'])); + ->willReturnCallback([$this, 'lockSingleDocumentCallback']); $mockTripodUpdate->expects($this->exactly(3)) ->method('getTransactionLog') - ->will($this->returnValue($mockTransactionLog)); + ->willReturn($mockTransactionLog); $mockTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdate)); + ->willReturn($mockTripodUpdate); try { $mockTripod->saveChanges($oG, $nG, 'http://talisaspire.com/'); @@ -314,7 +316,7 @@ public function testTransactionRollbackDuringCreateTransaction() $this->assertDocumentDoesNotHaveProperty(['r' => $subjectTwo, 'c' => 'http://talisaspire.com/'], _LOCKED_FOR_TRANS_TS, $this->tripod); } - public function testTransactionRollbackDuringApplyChanges() + public function testTransactionRollbackDuringApplyChanges(): void { // Save some basic data into the db before we create a transaction to modify it $subjectOne = 'http://example.com/resources/1'; @@ -366,14 +368,14 @@ public function testTransactionRollbackDuringApplyChanges() ->getMock(); $mockTripodUpdate->expects($this->exactly(1)) ->method('generateTransactionId') - ->will($this->returnValue($mockTransactionId)); + ->willReturn($mockTransactionId); $mockTripodUpdate->expects($this->exactly(2)) ->method('lockSingleDocument') - ->will($this->returnCallback([$this, 'lockSingleDocumentCallback'])); - $mockTripodUpdate->expects($this->once())->method('applyChangeSet')->will($this->throwException(new Exception('Exception throw by mock test during applychangeset'))); + ->willReturnCallback([$this, 'lockSingleDocumentCallback']); + $mockTripodUpdate->expects($this->once())->method('applyChangeSet')->willThrowException(new Exception('Exception throw by mock test during applychangeset')); $mockTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdate)); + ->willReturn($mockTripodUpdate); $mockTripod->setTransactionLog($this->tripodTransactionLog); @@ -479,6 +481,7 @@ public function lockSingleDocumentCallback($s, $transaction_id, $contextAlias) if (!$result->isAcknowledged()) { throw new Exception('Failed to create new document with error message'); } + $document = $this->getTripodCollection($this->tripod)->findOne(['_id' => [_ID_RESOURCE => $this->labeller->uri_to_alias($s), _ID_CONTEXT => $contextAlias]]); } catch (Exception $e) { return false; diff --git a/test/unit/mongo/MongoTripodViewsTest.php b/test/unit/mongo/MongoTripodViewsTest.php index 39ed0ab7..71420dbf 100644 --- a/test/unit/mongo/MongoTripodViewsTest.php +++ b/test/unit/mongo/MongoTripodViewsTest.php @@ -1,5 +1,7 @@ tripodViews->getViewForResource('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', 'v_resource_full'); @@ -130,7 +132,7 @@ public function testGenerateView() /** * Tests view filters removes data, but keeps it in the impact index. */ - public function testGenerateViewWithFilterRemovesFilteredDataButKeepsResourcesInTheImpactIndex() + public function testGenerateViewWithFilterRemovesFilteredDataButKeepsResourcesInTheImpactIndex(): void { // get the view - this should trigger generation $this->tripodViews->getViewForResource('http://talisaspire.com/resources/filter1', 'v_resource_filter1'); @@ -199,7 +201,7 @@ public function testGenerateViewWithFilterRemovesFilteredDataButKeepsResourcesIn /** * Tests view filter by literal values. */ - public function testGenerateViewWithFilterOnLiteralValue() + public function testGenerateViewWithFilterOnLiteralValue(): void { // get the view - this should trigger generation $this->tripodViews->getViewForResource('http://talisaspire.com/resources/filter1', 'v_resource_filter2'); @@ -262,7 +264,7 @@ public function testGenerateViewWithFilterOnLiteralValue() /** * Test data removed from view by filter is included in view after update and regeneration. */ - public function testGenerateViewCorrectlyAfterUpdateAffectsFilter() + public function testGenerateViewCorrectlyAfterUpdateAffectsFilter(): void { // get the view - this should trigger generation $this->tripodViews->getViewForResource('http://talisaspire.com/resources/filter1', 'v_resource_filter1'); @@ -330,6 +332,7 @@ public function testGenerateViewCorrectlyAfterUpdateAffectsFilter() // Modify http://talisaspire.com/works/filter1 so that it is a Chapter (included in the view) not a Book (excluded from the view) $oldGraph = new ExtendedGraph(); $oldGraph->add_resource_triple('http://talisaspire.com/works/filter1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'http://purl.org/ontology/bibo/Book'); + $newGraph = new ExtendedGraph(); $newGraph->add_resource_triple('http://talisaspire.com/works/filter1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'http://purl.org/ontology/bibo/Chapter'); @@ -399,7 +402,7 @@ public function testGenerateViewCorrectlyAfterUpdateAffectsFilter() /** * Test including an rdf sequence in a view. */ - public function testGenerateViewContainingRdfSequence() + public function testGenerateViewContainingRdfSequence(): void { // get the view - this should trigger generation $this->tripodViews->getViewForResource('http://talisaspire.com/resources/filter1', 'v_resource_rdfsequence'); @@ -470,14 +473,14 @@ public function testGenerateViewContainingRdfSequence() $this->assertInstanceOf(UTCDateTime::class, $actualView['_cts']); } - public function testGenerateViewWithTTL() + public function testGenerateViewWithTTL(): void { $expiryDate = DateUtil::getMongoDate((time() + 300) * 1000); $mockTripodViews = $this->getMockBuilder(Views::class) ->onlyMethods(['getExpirySecFromNow']) ->setConstructorArgs($this->viewsConstParams) ->getMock(); - $mockTripodViews->expects($this->once())->method('getExpirySecFromNow')->with(300)->will($this->returnValue(time() + 300)); + $mockTripodViews->expects($this->once())->method('getExpirySecFromNow')->with(300)->willReturn(time() + 300); $mockTripodViews->getViewForResource('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', 'v_resource_full_ttl'); @@ -522,7 +525,7 @@ public function testGenerateViewWithTTL() $this->assertInstanceOf(UTCDateTime::class, $actualView['_cts']); } - public function testNonExpiringViewWithNegativeTTL() + public function testNonExpiringViewWithNegativeTTL(): void { $views = new Views( $this->viewsConstParams[0], @@ -650,23 +653,23 @@ public function testNonExpiringViewWithNegativeTTL() * * Depending on the order the mongodriver selects data */ - public function testViewGenerationMaxJoinsObjectsMatchPredicates() + public function testViewGenerationMaxJoinsObjectsMatchPredicates(): void { // get the view $graph = $this->tripodViews->getViewForResource('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', 'v_resource_to_single_source'); foreach ($graph->get_resource_triple_values('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', 'http://purl.org/dc/terms/source') as $object) { - $this->assertFalse($graph->get_subject_subgraph($object)->is_empty(), "Subgraph for {$object} should not be empty, should have been followed as join"); + $this->assertFalse($graph->get_subject_subgraph($object)->is_empty(), sprintf('Subgraph for %s should not be empty, should have been followed as join', $object)); } } - public function testTTLViewIsRegeneratedOnFetch() + public function testTTLViewIsRegeneratedOnFetch(): void { // make mock return expiry date in past... $mockTripodViews = $this->getMockBuilder(Views::class) ->onlyMethods(['getExpirySecFromNow']) ->setConstructorArgs($this->viewsConstParams) ->getMock(); - $mockTripodViews->expects($this->once())->method('getExpirySecFromNow')->with(300)->will($this->returnValue(time() - 300)); + $mockTripodViews->expects($this->once())->method('getExpirySecFromNow')->with(300)->willReturn(time() - 300); $mockTripodViews->generateView('v_resource_full_ttl', 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA'); @@ -680,7 +683,7 @@ public function testTTLViewIsRegeneratedOnFetch() $mockTripodViews2->getViewForResource('http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', 'v_resource_full_ttl'); } - public function testGenerateViewWithCountAggregate() + public function testGenerateViewWithCountAggregate(): void { $expiryDate = DateUtil::getMongoDate((time() + 300) * 1000); @@ -688,7 +691,7 @@ public function testGenerateViewWithCountAggregate() ->onlyMethods(['getExpirySecFromNow']) ->setConstructorArgs($this->viewsConstParams) ->getMock(); - $mockTripodViews->expects($this->once())->method('getExpirySecFromNow')->with(300)->will($this->returnValue(time() + 300)); + $mockTripodViews->expects($this->once())->method('getExpirySecFromNow')->with(300)->willReturn(time() + 300); $mockTripodViews->getViewForResource('http://talisaspire.com/works/4d101f63c10a6', 'v_counts'); @@ -742,7 +745,7 @@ public function testGenerateViewWithCountAggregate() $this->assertInstanceOf(UTCDateTime::class, $actualView['_cts']); } - public function testGetViewWithNamespaces() + public function testGetViewWithNamespaces(): void { $g = $this->tripodViews->getViewForResource('baseData:1', 'v_work_see_also', 'baseData:DefaultGraph'); $this->assertFalse($g->is_empty(), 'Graph should not be empty'); @@ -768,13 +771,13 @@ public function testGetViewWithNamespaces() $this->assertEquals($g2->to_ntriples(), $g5->to_ntriples(), 'View requested with subject/context qnamed should be equal to that with only context namespaced'); } - public function testGenerateViewsForResourcesOfTypeWithNamespace() + public function testGenerateViewsForResourcesOfTypeWithNamespace(): void { $mockTripodViews = $this->getMockBuilder(Views::class) ->onlyMethods(['generateView']) ->setConstructorArgs($this->viewsConstParams) ->getMock(); - $mockTripodViews->expects($this->atLeastOnce())->method('generateView')->will($this->returnValue(['ok' => true])); + $mockTripodViews->expects($this->atLeastOnce())->method('generateView')->willReturn(['ok' => true]); // spec is namespaced, acorn:Work, can it resolve? $mockTripodViews->generateViewsForResourcesOfType('http://talisaspire.com/schema#Work'); @@ -783,7 +786,7 @@ public function testGenerateViewsForResourcesOfTypeWithNamespace() ->onlyMethods(['generateView']) ->setConstructorArgs($this->viewsConstParams) ->getMock(); - $mockTripodViews->expects($this->atLeastOnce())->method('generateView')->will($this->returnValue(['ok' => true])); + $mockTripodViews->expects($this->atLeastOnce())->method('generateView')->willReturn(['ok' => true]); // spec is fully qualified, http://talisaspire.com/shema#Work2, can it resolve? $mockTripodViews->generateViewsForResourcesOfType('acorn:Work2'); @@ -791,7 +794,7 @@ public function testGenerateViewsForResourcesOfTypeWithNamespace() // todo: more unit tests to cover other view spec/search document properties: condition, maxJoins, followSequence, from - public function testGetViewForResourcesDoesNotInvokeViewGenerationForMissingResources() + public function testGetViewForResourcesDoesNotInvokeViewGenerationForMissingResources(): void { $uri1 = 'http://uri1'; $uri2 = 'http://uri2'; @@ -824,8 +827,8 @@ public function testGetViewForResourcesDoesNotInvokeViewGenerationForMissingReso ->onlyMethods(['findOne']) ->getMock(); - $mockDb->expects($this->any())->method('selectCollection')->will($this->returnValue($mockColl)); - $mockColl->expects($this->once())->method('findOne')->will($this->returnValue(null)); + $mockDb->method('selectCollection')->willReturn($mockColl); + $mockColl->expects($this->once())->method('findOne')->willReturn(null); $mockConfig = $this->getMockBuilder(TripodTestConfig::class) ->onlyMethods(['getCollectionForCBD', 'getCollectionForView']) @@ -834,12 +837,12 @@ public function testGetViewForResourcesDoesNotInvokeViewGenerationForMissingReso $mockConfig->expects($this->atLeastOnce()) ->method('getCollectionForCBD') ->with('tripod_php_testing', $this->anything(), $this->anything()) - ->will($this->returnValue($mockColl)); + ->willReturn($mockColl); $mockConfig->expects($this->atLeastOnce()) ->method('getCollectionForView') ->with('tripod_php_testing', $this->anything(), $this->anything()) - ->will($this->returnValue($mockViewColl)); + ->willReturn($mockViewColl); $mockConfig->loadConfig(Config::getConfig()); @@ -854,18 +857,18 @@ public function testGetViewForResourcesDoesNotInvokeViewGenerationForMissingReso $mockTripodViews->expects($this->once()) ->method('fetchGraph') ->with($query, MONGO_VIEW, $mockViewColl, null, 101) - ->will($this->returnValue($returnedGraph)); + ->willReturn($returnedGraph); $mockTripodViews->expects($this->atLeastOnce()) ->method('getConfigInstance') - ->will($this->returnValue($mockConfig)); + ->willReturn($mockConfig); $resultGraph = $mockTripodViews->getViewForResources([$uri1, $uri2], $viewType, $context); $this->assertEquals($returnedGraph->to_ntriples(), $resultGraph->to_ntriples()); } - public function testGetViewForResourcesInvokesViewGenerationForMissingResources() + public function testGetViewForResourcesInvokesViewGenerationForMissingResources(): void { $uri1 = 'http://uri1'; $uri2 = 'http://uri2'; @@ -886,8 +889,8 @@ public function testGetViewForResourcesInvokesViewGenerationForMissingResources( ->onlyMethods(['findOne']) ->getMock(); - $mockDb->expects($this->any())->method('selectCollection')->will($this->returnValue($mockColl)); - $mockColl->expects($this->once())->method('findOne')->will($this->returnValue(['_id' => $uri1])); // the actual returned doc is not important, it just has to not be null + $mockDb->method('selectCollection')->willReturn($mockColl); + $mockColl->expects($this->once())->method('findOne')->willReturn(['_id' => $uri1]); // the actual returned doc is not important, it just has to not be null $mockConfig = $this->getMockBuilder(TripodTestConfig::class) ->onlyMethods(['getCollectionForCBD', 'getCollectionForView']) @@ -896,12 +899,12 @@ public function testGetViewForResourcesInvokesViewGenerationForMissingResources( $mockConfig->expects($this->atLeastOnce()) ->method('getCollectionForCBD') ->with('tripod_php_testing', $this->anything(), $this->anything()) - ->will($this->returnValue($mockColl)); + ->willReturn($mockColl); $mockConfig->expects($this->atLeastOnce()) ->method('getCollectionForView') ->with('tripod_php_testing', $this->anything(), $this->anything()) - ->will($this->returnValue($mockViewColl)); + ->willReturn($mockViewColl); $mockConfig->loadConfig(Config::getConfig()); @@ -913,15 +916,15 @@ public function testGetViewForResourcesInvokesViewGenerationForMissingResources( $mockTripodViews->expects($this->once()) ->method('generateView') ->with($viewType, $uri2, $context) - ->will($this->returnValue(['ok' => true])); + ->willReturn(['ok' => true]); $mockTripodViews->expects($this->exactly(2)) ->method('fetchGraph') - ->will($this->returnCallback([$this, 'fetchGraphInGetViewForResourcesCallback'])); + ->willReturnCallback([$this, 'fetchGraphInGetViewForResourcesCallback']); $mockTripodViews->expects($this->atLeastOnce()) ->method('getConfigInstance') - ->will($this->returnValue($mockConfig)); + ->willReturn($mockConfig); $resultGraph = $mockTripodViews->getViewForResources([$uri1, $uri2], $viewType, $context); @@ -932,7 +935,7 @@ public function testGetViewForResourcesInvokesViewGenerationForMissingResources( $this->assertEquals($expectedGraph->to_ntriples(), $resultGraph->to_ntriples()); } - public function testDeletionOfResourceTriggersViewRegeneration() + public function testDeletionOfResourceTriggersViewRegeneration(): void { $context = 'http://talisaspire.com/'; @@ -953,6 +956,7 @@ public function testDeletionOfResourceTriggersViewRegeneration() ); $originalGraph->add_resource_triple($uri1, $labeller->qname_to_uri('dct:isVersionOf'), $uri2); + $tripod = new Driver('CBD_testing', 'tripod_php_testing', ['defaultContext' => $context]); $tripod->saveChanges(new ExtendedGraph(), $originalGraph); @@ -1015,12 +1019,12 @@ public function testDeletionOfResourceTriggersViewRegeneration() $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockTripod->expects($this->once()) ->method('getComposite') ->with(OP_VIEWS) - ->will($this->returnValue($mockViews)); + ->willReturn($mockViews); $mockTripodUpdates->expects($this->once()) ->method('processSyncOperations') @@ -1090,7 +1094,7 @@ public function testDeletionOfResourceTriggersViewRegeneration() /** * Basically identical to testDeletionOfResourceTriggersViewRegeneration, but focus on $url2, instead. */ - public function testDeletionOfResourceInImpactIndexTriggersViewRegeneration() + public function testDeletionOfResourceInImpactIndexTriggersViewRegeneration(): void { $context = 'http://talisaspire.com/'; @@ -1107,6 +1111,7 @@ public function testDeletionOfResourceInImpactIndexTriggersViewRegeneration() $originalGraph->add_literal_triple($uri2, $labeller->qname_to_uri('dct:subject'), 'Things grouped by no specific criteria'); $originalGraph->add_resource_triple($uri1, $labeller->qname_to_uri('dct:isVersionOf'), $uri2); + $tripod = new Driver('CBD_testing', 'tripod_php_testing', ['defaultContext' => $context]); $tripod->saveChanges(new ExtendedGraph(), $originalGraph); @@ -1168,12 +1173,12 @@ public function testDeletionOfResourceInImpactIndexTriggersViewRegeneration() $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockTripod->expects($this->once()) ->method('getComposite') ->with(OP_VIEWS) - ->will($this->returnValue($mockViews)); + ->willReturn($mockViews); $mockTripodUpdates->expects($this->once()) ->method('processSyncOperations') @@ -1265,7 +1270,7 @@ public function testDeletionOfResourceInImpactIndexTriggersViewRegeneration() * Basically identical to testDeletionOfResourceInImpactIndexTriggersViewRegeneration, but update $url2, rather * than deleting it. */ - public function testUpdateOfResourceInImpactIndexTriggersViewRegeneration() + public function testUpdateOfResourceInImpactIndexTriggersViewRegeneration(): void { $context = 'http://talisaspire.com/'; @@ -1282,6 +1287,7 @@ public function testUpdateOfResourceInImpactIndexTriggersViewRegeneration() $originalGraph->add_literal_triple($uri2, $labeller->qname_to_uri('dct:subject'), 'Things grouped by no specific criteria'); $originalGraph->add_resource_triple($uri1, $labeller->qname_to_uri('dct:isVersionOf'), $uri2); + $tripod = new Driver('CBD_testing', 'tripod_php_testing', ['defaultContext' => $context]); $tripod->saveChanges(new ExtendedGraph(), $originalGraph); @@ -1341,12 +1347,12 @@ public function testUpdateOfResourceInImpactIndexTriggersViewRegeneration() $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockTripod->expects($this->once()) ->method('getComposite') ->with(OP_VIEWS) - ->will($this->returnValue($mockViews)); + ->willReturn($mockViews); $mockTripodUpdates->expects($this->once()) ->method('processSyncOperations') @@ -1400,6 +1406,7 @@ public function testUpdateOfResourceInImpactIndexTriggersViewRegeneration() $newGraph = $originalGraph->get_subject_subgraph($uri2); $newGraph->replace_literal_triple($uri2, $labeller->qname_to_uri('dct:subject'), 'Things grouped by no specific criteria', 'Grab bag'); + $mockTripod->saveChanges($originalGraph->get_subject_subgraph($uri2), $newGraph); // Walk through the processSyncOperations process manually for views @@ -1439,7 +1446,7 @@ public function testUpdateOfResourceInImpactIndexTriggersViewRegeneration() /** * Similar to testDeletionOfResourceTriggersViewRegeneration except $url1 is updated, rather than deleted. */ - public function testUpdateOfResourceTriggersViewRegeneration() + public function testUpdateOfResourceTriggersViewRegeneration(): void { $context = 'http://talisaspire.com/'; @@ -1456,6 +1463,7 @@ public function testUpdateOfResourceTriggersViewRegeneration() $originalGraph->add_literal_triple($uri2, $labeller->qname_to_uri('dct:subject'), 'Things grouped by no specific criteria'); $originalGraph->add_resource_triple($uri1, $labeller->qname_to_uri('dct:isVersionOf'), $uri2); + $tripod = new Driver('CBD_testing', 'tripod_php_testing', ['defaultContext' => $context]); $tripod->saveChanges(new ExtendedGraph(), $originalGraph); @@ -1515,12 +1523,12 @@ public function testUpdateOfResourceTriggersViewRegeneration() $mockTripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockTripod->expects($this->once()) ->method('getComposite') ->with(OP_VIEWS) - ->will($this->returnValue($mockViews)); + ->willReturn($mockViews); $mockTripodUpdates->expects($this->once()) ->method('processSyncOperations') @@ -1574,6 +1582,7 @@ public function testUpdateOfResourceTriggersViewRegeneration() $newGraph = $originalGraph->get_subject_subgraph($uri1); $newGraph->add_literal_triple($uri1, $labeller->qname_to_uri('dct:title'), 'Title of Resource'); + $mockTripod->saveChanges($originalGraph->get_subject_subgraph($uri1), $newGraph); // Walk through the processSyncOperations process manually for views @@ -1613,7 +1622,7 @@ public function testUpdateOfResourceTriggersViewRegeneration() * Test that a change to a resource that isn't covered by a viewspec or in an impact index still triggers the discover * impacted subjects operation and returns nothing. */ - public function testResourceUpdateNotCoveredBySpecStillTriggersOperations() + public function testResourceUpdateNotCoveredBySpecStillTriggersOperations(): void { $context = 'http://talisaspire.com/'; @@ -1624,7 +1633,7 @@ public function testResourceUpdateNotCoveredBySpecStillTriggersOperations() $uri1 = 'http://example.com/resources/' . uniqid(); $originalGraph->add_resource_triple($uri1, RDF_TYPE, $labeller->qname_to_uri('bibo:Document')); $originalGraph->add_literal_triple($uri1, $labeller->qname_to_uri('dct:title'), 'How to speak American like a native'); - $originalGraph->add_literal_triple($uri1, $labeller->qname_to_uri('dct:subject'), 'Languages -- \'Murrican'); + $originalGraph->add_literal_triple($uri1, $labeller->qname_to_uri('dct:subject'), "Languages -- 'Murrican"); $originalSubjectsAndPredicatesOfChange = [ $labeller->uri_to_alias($uri1) => ['rdf:type', 'dct:title', 'dct:subject'], @@ -1680,12 +1689,12 @@ public function testResourceUpdateNotCoveredBySpecStillTriggersOperations() $mockTripod->expects($this->exactly(2)) ->method('getDataUpdater') - ->will($this->returnValue($mockTripodUpdates)); + ->willReturn($mockTripodUpdates); $mockTripod->expects($this->exactly(2)) ->method('getComposite') ->with(OP_VIEWS) - ->will($this->returnValue($mockViews)); + ->willReturn($mockViews); $mockTripodUpdates->expects($this->exactly(2)) ->method('processSyncOperations') @@ -1726,7 +1735,7 @@ public function testResourceUpdateNotCoveredBySpecStillTriggersOperations() $this->assertEmpty($impactedSubjects); $newGraph = $originalGraph->get_subject_subgraph($uri1); - $newGraph->replace_literal_triple($uri1, $labeller->qname_to_uri('dct:subject'), 'Languages -- \'Murrican', 'Languages -- English, American'); + $newGraph->replace_literal_triple($uri1, $labeller->qname_to_uri('dct:subject'), "Languages -- 'Murrican", 'Languages -- English, American'); $mockTripod->saveChanges($originalGraph, $newGraph); @@ -1742,7 +1751,7 @@ public function testResourceUpdateNotCoveredBySpecStillTriggersOperations() * Save several new resources in a single operation. Only one of the resources has a type that is applicable based on specifications, * therefore only one ImpactedSubject should be created. */ - public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() + public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject(): void { $tripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getDataUpdater']) @@ -1779,7 +1788,7 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() $tripod->expects($this->once()) ->method('getDataUpdater') - ->will($this->returnValue($tripodUpdates)); + ->willReturn($tripodUpdates); // first lets add a book, which should trigger a search doc, view and table gen for a single item $g = new MongoGraph(); @@ -1805,6 +1814,7 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri('dct:title'), 'This is yet another new resource'); $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri('dct:subject'), 'art'); $g->add_literal_triple($newSubjectUri3, $g->qname_to_uri('dct:subject'), 'design'); + $subjectsAndPredicatesOfChange = [ $newSubjectUri1 => ['rdf:type', 'dct:creator', 'dct:title', 'dct:subject'], $newSubjectUri2 => ['rdf:type', 'dct:creator', 'dct:title', 'dct:subject'], @@ -1831,7 +1841,7 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject() $this->assertEquals($expectedImpactedSubjects, $impactedSubjects); } - public function testSavingToAPreviouslyEmptySeqeunceUpdatesView() + public function testSavingToAPreviouslyEmptySeqeunceUpdatesView(): void { // create a tripod with views sync $tripod = new Driver('CBD_testing', 'tripod_php_testing', [ @@ -1855,7 +1865,7 @@ public function testSavingToAPreviouslyEmptySeqeunceUpdatesView() $this->assertTrue($view->has_triples_about('http://basedata.com/b/sequence123')); } - public function testSavingToAPreviouslyEmptyJoinUpdatesView() + public function testSavingToAPreviouslyEmptyJoinUpdatesView(): void { // create a tripod with views sync $tripod = new Driver('CBD_testing', 'tripod_php_testing', [ @@ -1882,7 +1892,7 @@ public function testSavingToAPreviouslyEmptyJoinUpdatesView() /** * @return ExtendedGraph */ - public function fetchGraphInGetViewForResourcesCallback() + public function fetchGraphInGetViewForResourcesCallback(...$args) { $uri1 = 'http://uri1'; $uri2 = 'http://uri2'; @@ -1898,18 +1908,18 @@ public function fetchGraphInGetViewForResourcesCallback() $returnedGraph2 = new ExtendedGraph(); $returnedGraph2->add_literal_triple($uri2, 'http://somepred', 'someval'); - - $args = func_get_args(); if ($args[0] == $query1) { return $returnedGraph1; } + if ($args[0] == $query2) { return $returnedGraph2; } + $this->fail(); } - public function testCursorNoExceptions() + public function testCursorNoExceptions(): void { $uri1 = 'http://uri1'; @@ -1935,10 +1945,10 @@ public function testCursorNoExceptions() ->onlyMethods(['rewind']) ->getMock(); - $mockViewColl->expects($this->once())->method('find')->will($this->returnValue($mockCursor)); + $mockViewColl->expects($this->once())->method('find')->willReturn($mockCursor); - $mockDb->expects($this->any())->method('selectCollection')->will($this->returnValue($mockColl)); - $mockColl->expects($this->once())->method('findOne')->will($this->returnValue(null)); + $mockDb->method('selectCollection')->willReturn($mockColl); + $mockColl->expects($this->once())->method('findOne')->willReturn(null); $mockConfig = $this->getMockBuilder(TripodTestConfig::class) ->onlyMethods(['getCollectionForCBD', 'getCollectionForView']) @@ -1947,12 +1957,12 @@ public function testCursorNoExceptions() $mockConfig->expects($this->atLeastOnce()) ->method('getCollectionForCBD') ->with('tripod_php_testing', $this->anything(), $this->anything()) - ->will($this->returnValue($mockColl)); + ->willReturn($mockColl); $mockConfig->expects($this->atLeastOnce()) ->method('getCollectionForView') ->with('tripod_php_testing', $this->anything(), $this->anything()) - ->will($this->returnValue($mockViewColl)); + ->willReturn($mockViewColl); $mockConfig->loadConfig(Config::getConfig()); @@ -1966,12 +1976,12 @@ public function testCursorNoExceptions() $mockTripodViews->expects($this->atLeastOnce()) ->method('getConfigInstance') - ->will($this->returnValue($mockConfig)); + ->willReturn($mockConfig); $mockTripodViews->getViewForResources([$uri1], $viewType, $context); } - public function testCursorExceptionThrown() + public function testCursorExceptionThrown(): void { $uri1 = 'http://uri1'; @@ -1997,10 +2007,10 @@ public function testCursorExceptionThrown() ->onlyMethods(['rewind']) ->getMock(); - $mockCursor->expects($this->exactly(30))->method('rewind')->will($this->throwException(new Exception('Exception thrown when cursoring to Mongo'))); - $mockViewColl->expects($this->once())->method('find')->will($this->returnValue($mockCursor)); + $mockCursor->expects($this->exactly(30))->method('rewind')->willThrowException(new Exception('Exception thrown when cursoring to Mongo')); + $mockViewColl->expects($this->once())->method('find')->willReturn($mockCursor); - $mockDb->expects($this->any())->method('selectCollection')->will($this->returnValue($mockColl)); + $mockDb->method('selectCollection')->willReturn($mockColl); $mockColl->expects($this->never())->method('findOne'); $mockConfig = $this->getMockBuilder(TripodTestConfig::class) @@ -2013,7 +2023,7 @@ public function testCursorExceptionThrown() $mockConfig->expects($this->atLeastOnce()) ->method('getCollectionForView') ->with('tripod_php_testing', $this->anything(), $this->anything()) - ->will($this->returnValue($mockViewColl)); + ->willReturn($mockViewColl); $mockConfig->loadConfig(Config::getConfig()); @@ -2027,14 +2037,14 @@ public function testCursorExceptionThrown() $mockTripodViews->expects($this->atLeastOnce()) ->method('getConfigInstance') - ->will($this->returnValue($mockConfig)); + ->willReturn($mockConfig); $this->expectException(Exception::class); $this->expectExceptionMessage('Exception thrown when cursoring to Mongo'); $mockTripodViews->getViewForResources([$uri1], $viewType, $context); } - public function testCursorNoExceptionThrownWhenCursorThrowsSomeExceptions() + public function testCursorNoExceptionThrownWhenCursorThrowsSomeExceptions(): void { $uri1 = 'http://uri1'; @@ -2061,19 +2071,12 @@ public function testCursorNoExceptionThrownWhenCursorThrowsSomeExceptions() ->getMock(); $mockCursor->expects($this->exactly(5)) - ->method('rewind') - ->will($this->onConsecutiveCalls( - $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), - $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), - $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), - $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), - $this->returnValue($mockCursor) - )); + ->method('rewind')->willReturnOnConsecutiveCalls($this->throwException(new Exception('Exception thrown when cursoring to Mongo')), $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), $this->returnValue($mockCursor)); - $mockViewColl->expects($this->once())->method('find')->will($this->returnValue($mockCursor)); + $mockViewColl->expects($this->once())->method('find')->willReturn($mockCursor); - $mockDb->expects($this->any())->method('selectCollection')->will($this->returnValue($mockColl)); - $mockColl->expects($this->once())->method('findOne')->will($this->returnValue(null)); + $mockDb->method('selectCollection')->willReturn($mockColl); + $mockColl->expects($this->once())->method('findOne')->willReturn(null); $mockConfig = $this->getMockBuilder(TripodTestConfig::class) ->onlyMethods(['getCollectionForCBD', 'getCollectionForView']) @@ -2082,12 +2085,12 @@ public function testCursorNoExceptionThrownWhenCursorThrowsSomeExceptions() $mockConfig->expects($this->atLeastOnce()) ->method('getCollectionForCBD') ->with('tripod_php_testing', $this->anything(), $this->anything()) - ->will($this->returnValue($mockColl)); + ->willReturn($mockColl); $mockConfig->expects($this->atLeastOnce()) ->method('getCollectionForView') ->with('tripod_php_testing', $this->anything(), $this->anything()) - ->will($this->returnValue($mockViewColl)); + ->willReturn($mockViewColl); $mockConfig->loadConfig(Config::getConfig()); @@ -2101,12 +2104,12 @@ public function testCursorNoExceptionThrownWhenCursorThrowsSomeExceptions() $mockTripodViews->expects($this->atLeastOnce()) ->method('getConfigInstance') - ->will($this->returnValue($mockConfig)); + ->willReturn($mockConfig); $mockTripodViews->getViewForResources([$uri1], $viewType, $context); } - public function testCountViews() + public function testCountViews(): void { $collection = $this->getMockBuilder(Collection::class) ->setConstructorArgs([new Manager(), 'db', 'coll']) @@ -2120,19 +2123,19 @@ public function testCountViews() $views->expects($this->once()) ->method('getCollectionForViewSpec') ->with('v_some_spec') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('count') ->with(['_id.type' => 'v_some_spec']) - ->will($this->returnValue(101)); + ->willReturn(101); $this->assertEquals(101, $views->count('v_some_spec')); } - public function testCountViewsWithFilters() + public function testCountViewsWithFilters(): void { - $filters = ['_cts' => ['$lte' => new UTCDateTime(null)]]; + $filters = ['_cts' => ['$lte' => new UTCDateTime()]]; $query = array_merge(['_id.type' => 'v_some_spec'], $filters); $collection = $this->getMockBuilder(Collection::class) ->setConstructorArgs([new Manager(), 'db', 'coll']) @@ -2146,17 +2149,17 @@ public function testCountViewsWithFilters() $views->expects($this->once()) ->method('getCollectionForViewSpec') ->with('v_some_spec') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('count') ->with($query) - ->will($this->returnValue(101)); + ->willReturn(101); $this->assertEquals(101, $views->count('v_some_spec', $filters)); } - public function testDeleteViewsByViewId() + public function testDeleteViewsByViewId(): void { $collection = $this->getMockBuilder(Collection::class) ->setConstructorArgs([new Manager(), 'db', 'coll']) @@ -2170,7 +2173,7 @@ public function testDeleteViewsByViewId() $deleteResult->expects($this->once()) ->method('getDeletedCount') - ->will($this->returnValue(30)); + ->willReturn(30); $views = $this->getMockBuilder(Views::class) ->onlyMethods(['getCollectionForViewSpec']) @@ -2180,19 +2183,19 @@ public function testDeleteViewsByViewId() $views->expects($this->once()) ->method('getCollectionForViewSpec') ->with('v_resource_full') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('deleteMany') ->with(['_id.type' => 'v_resource_full']) - ->will($this->returnValue($deleteResult)); + ->willReturn($deleteResult); $this->assertEquals(30, $views->deleteViewsByViewId('v_resource_full')); } - public function testDeleteViewsByViewIdWithTimestamp() + public function testDeleteViewsByViewIdWithTimestamp(): void { - $timestamp = new UTCDateTime(null); + $timestamp = new UTCDateTime(); $query = [ '_id.type' => 'v_resource_full', @@ -2213,7 +2216,7 @@ public function testDeleteViewsByViewIdWithTimestamp() $deleteResult->expects($this->once()) ->method('getDeletedCount') - ->will($this->returnValue(30)); + ->willReturn(30); $views = $this->getMockBuilder(Views::class) ->onlyMethods(['getCollectionForViewSpec']) @@ -2223,17 +2226,17 @@ public function testDeleteViewsByViewIdWithTimestamp() $views->expects($this->once()) ->method('getCollectionForViewSpec') ->with('v_resource_full') - ->will($this->returnValue($collection)); + ->willReturn($collection); $collection->expects($this->once()) ->method('deleteMany') ->with($query) - ->will($this->returnValue($deleteResult)); + ->willReturn($deleteResult); $this->assertEquals(30, $views->deleteViewsByViewId('v_resource_full', $timestamp)); } - public function testBatchViewGeneration() + public function testBatchViewGeneration(): void { $count = 234; $docs = []; diff --git a/test/unit/mongo/ResqueJobTestBase.php b/test/unit/mongo/ResqueJobTestBase.php index 5fe2d5c6..2c5d0c0e 100644 --- a/test/unit/mongo/ResqueJobTestBase.php +++ b/test/unit/mongo/ResqueJobTestBase.php @@ -1,5 +1,7 @@ getMock(); $mockJob->expects($this->atLeastOnce()) ->method('getInstance') - ->will($this->returnValue($job)); - $mockJob->expects($this->any()) + ->willReturn($job); + $mockJob ->method('getArguments') - ->will($this->returnValue($job->args)); + ->willReturn($job->args); $mockJob->perform(); } } diff --git a/test/unit/mongo/TestConfigGenerator.php b/test/unit/mongo/TestConfigGenerator.php index 4a1a19b1..27dd2548 100644 --- a/test/unit/mongo/TestConfigGenerator.php +++ b/test/unit/mongo/TestConfigGenerator.php @@ -8,15 +8,19 @@ class TestConfigGenerator extends Config private function __construct() {} - public function serialize() + /** + * @return array + */ + public function serialize(): array { return ['class' => get_class($this), 'filename' => $this->fileName]; } - public static function deserialize(array $config) + public static function deserialize(array $config): self { $instance = new self(); $instance->fileName = $config['filename']; + $cfg = json_decode(file_get_contents($config['filename']), true); $instance->loadConfig($cfg); diff --git a/test/unit/mongo/TestJobBase.php b/test/unit/mongo/TestJobBase.php index 9cdb9bbb..f3a73846 100644 --- a/test/unit/mongo/TestJobBase.php +++ b/test/unit/mongo/TestJobBase.php @@ -8,19 +8,19 @@ class TestJobBase extends JobBase * Expose this method for testing. * {@inheritDoc} */ - public function getTripodConfig() + protected function getTripodConfig() { return parent::getTripodConfig(); } public function perform() {} - protected function getStatTimerSuccessKey() + protected function getStatTimerSuccessKey(): string { return 'TEST_SUCCESS'; } - protected function getStatFailureIncrementKey() + protected function getStatFailureIncrementKey(): string { return 'TEST_FAIL'; } diff --git a/test/unit/mongo/TriplesUtilTest.php b/test/unit/mongo/TriplesUtilTest.php index f1d058e2..b83fffa1 100644 --- a/test/unit/mongo/TriplesUtilTest.php +++ b/test/unit/mongo/TriplesUtilTest.php @@ -1,10 +1,12 @@ Date: Fri, 27 Feb 2026 00:14:01 +0000 Subject: [PATCH 02/56] Stricter typing in ExtendedGraph --- src/classes/ChangeSet.php | 4 +- src/classes/ExtendedGraph.php | 228 +++++++++++++------------- src/classes/Labeller.php | 30 ++-- src/mongo/Labeller.php | 26 +-- test/unit/ExtendedGraphTest.php | 91 ++++------ test/unit/mongo/EnsureIndexesTest.php | 4 +- test/unit/mongo/MongoGraphTest.php | 27 +-- 7 files changed, 184 insertions(+), 226 deletions(-) diff --git a/src/classes/ChangeSet.php b/src/classes/ChangeSet.php index c26cfafd..be798b17 100644 --- a/src/classes/ChangeSet.php +++ b/src/classes/ChangeSet.php @@ -213,7 +213,7 @@ public function addT($s, $p, $o, $o_type = 'bnode'): void /** * @return string */ - public function toRDFXML() + public function toRDFXML(): string { /** @var \ARC2_RDFSerializer $ser */ $ser = \ARC2::getRDFXMLSerializer(); @@ -224,7 +224,7 @@ public function toRDFXML() /** * @return string */ - public function to_rdfxml() + public function to_rdfxml(): string { return $this->toRDFXML(); } diff --git a/src/classes/ExtendedGraph.php b/src/classes/ExtendedGraph.php index 63015bc0..d05237b8 100644 --- a/src/classes/ExtendedGraph.php +++ b/src/classes/ExtendedGraph.php @@ -104,7 +104,7 @@ public function __destruct() * @param string $prefix the namespace prefix to associate with the URI * @param string $uri the URI to associate with the prefix */ - public function set_namespace_mapping($prefix, $uri): void + public function set_namespace_mapping(string $prefix, string $uri): void { $this->_labeller->set_namespace_mapping($prefix, $uri); } @@ -112,23 +112,23 @@ public function set_namespace_mapping($prefix, $uri): void /** * Convert a QName to a URI using registered namespace prefixes. * - * @param string $qname the QName to convert + * @param string|null $qName the QName to convert * - * @return string the URI corresponding to the QName if a suitable prefix exists, null otherwise + * @return string|null the URI corresponding to the QName if a suitable prefix exists, null otherwise */ - public function qname_to_uri($qname) + public function qname_to_uri(?string $qName): ?string { - return $this->_labeller->qname_to_uri($qname); + return $this->_labeller->qname_to_uri($qName); } /** * Convert a URI to a QName using registered namespace prefixes. * - * @param string $uri the URI to convert + * @param string|null $uri the URI to convert * - * @return string the QName corresponding to the URI if a suitable prefix exists, null otherwise + * @return string|null the QName corresponding to the URI if a suitable prefix exists, null otherwise */ - public function uri_to_qname($uri) + public function uri_to_qname(?string $uri): ?string { return $this->_labeller->uri_to_qname($uri); } @@ -138,7 +138,7 @@ public function uri_to_qname($uri) * * @return string */ - public function get_prefix($ns) + public function get_prefix(string $ns): string { return $this->_labeller->get_prefix($ns); } @@ -146,7 +146,7 @@ public function get_prefix($ns) /** * @param string $p */ - public function add_labelling_property($p): void + public function add_labelling_property(string $p): void { $this->_labeller->add_labelling_property($p); } @@ -158,7 +158,7 @@ public function add_labelling_property($p): void * * @return array an associative array with two keys: 'type' and 'value'. Type is either bnode or uri */ - public function make_resource_array($resource): array + public function make_resource_array(string $resource): array { $resource_type = strpos($resource, '_:') === 0 ? 'bnode' : 'uri'; @@ -168,13 +168,13 @@ public function make_resource_array($resource): array /** * Adds a triple with a resource object to the graph. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate URI of the triple - * @param string $o the object of the triple, either a URI or a blank node in the format _:name + * @param string $s the subject of the triple, either a URI or a blank node in the format _:name + * @param string $p the predicate URI of the triple + * @param string|null $o the object of the triple, either a URI or a blank node in the format _:name * * @return bool true if the triple was new, false if it already existed in the graph */ - public function add_resource_triple($s, $p, $o) + public function add_resource_triple(string $s, string $p, ?string $o): bool { if ($this->isValidResource($o)) { return $this->_add_triple($s, $p, ['type' => strpos($o, '_:') === 0 ? 'bnode' : 'uri', 'value' => $o]); @@ -188,13 +188,13 @@ public function add_resource_triple($s, $p, $o) * * @param string $s the subject of the triple, either a URI or a blank node in the format _:name * @param string $p the predicate of the triple as a URI - * @param string $o the object of the triple as a string - * @param string $lang the language code of the triple's object (optional) - * @param string $dt the datatype URI of the triple's object (optional) + * @param bool|float|int|string $o the object of the triple as a scalar value + * @param string|null $lang the language code of the triple's object (optional) + * @param string|null $dt the datatype URI of the triple's object (optional) * * @return bool true if the triple was new, false if it already existed in the graph */ - public function add_literal_triple($s, $p, $o, $lang = null, $dt = null) + public function add_literal_triple(string $s, string $p, $o, ?string $lang = null, ?string $dt = null): bool { if ($this->isValidLiteral($o)) { $o_info = ['type' => 'literal', 'value' => $o]; @@ -215,7 +215,7 @@ public function add_literal_triple($s, $p, $o, $lang = null, $dt = null) /** * @deprecated this is deprecated */ - public function get_triples() + public function get_triples(): array { return \ARC2::getTriplesFromIndex($this->_to_arc_index($this->_index)); } @@ -225,7 +225,7 @@ public function get_triples() * * @see http://n2.talis.com/wiki/RDF_PHP_Specification */ - public function get_index() + public function get_index(): array { return $this->_index; } @@ -235,7 +235,7 @@ public function get_index() * * @return string the RDF/XML version of the graph */ - public function to_rdfxml() + public function to_rdfxml(): string { /** @var \ARC2_RDFSerializer $serializer */ $serializer = \ARC2::getRDFXMLSerializer( @@ -254,7 +254,7 @@ public function to_rdfxml() * * @return string the Turtle version of the graph */ - public function to_turtle() + public function to_turtle(): string { /** @var \ARC2_RDFSerializer $serializer */ $serializer = \ARC2::getTurtleSerializer( @@ -273,7 +273,7 @@ public function to_turtle() * * @return string the N-Triples version of the graph */ - public function to_ntriples() + public function to_ntriples(): string { /** @var \ARC2_RDFSerializer $serializer */ $serializer = \ARC2::getComponent('NTriplesSerializer', []); @@ -288,7 +288,7 @@ public function to_ntriples() * * @return string the JSON version of the graph */ - public function to_json() + public function to_json(): string { return json_encode($this->_index); } @@ -301,7 +301,7 @@ public function to_json() * * @return string a HTML version of the graph */ - public function to_html($s = null, $guess_labels = true): string + public function to_html($s = null, bool $guess_labels = true): string { $h = ''; @@ -407,14 +407,13 @@ public function to_html($s = null, $guess_labels = true): string /** * Fetch the first literal value for a given subject and predicate. If there are multiple possible values then one is selected at random. * - * @param string $s the subject to search for - * @param string $p the predicate to search for, or an array of predicates - * @param string $default a default value to use if no literal values are found - * @param string $preferred_language + * @param string $s the subject to search for + * @param array|string $p the predicate to search for, or an array of predicates + * @param bool|float|int|string|null $default a default value to use if no literal values are found * - * @return string the first literal value found or the supplied default if no values were found + * @return bool|float|int|string|null the first literal value found or the supplied default if no values were found */ - public function get_first_literal($s, $p, $default = null, $preferred_language = null) + public function get_first_literal(string $s, $p, $default = null, ?string $preferred_language = null) { $best_literal = $default; if (array_key_exists($s, $this->_index)) { @@ -463,9 +462,9 @@ public function get_first_literal($s, $p, $default = null, $preferred_language = * @param string $p the predicate to search for * @param string $default a default value to use if no literal values are found * - * @return string the first resource value found or the supplied default if no values were found + * @return string|null the first resource value found or the supplied default if no values were found */ - public function get_first_resource($s, $p, $default = null) + public function get_first_resource(string $s, string $p, ?string $default = null): ?string { if (isset($this->_index[$s][$p])) { foreach ($this->_index[$s][$p] as $value) { @@ -483,9 +482,9 @@ public function get_first_resource($s, $p, $default = null) * * @param string $s the subject of the triple, either a URI or a blank node in the format _:name * @param string $p the predicate URI of the triple - * @param string $o the object of the triple, either a URI or a blank node in the format _:name + * @param bool|float|int|string $o the object of the triple, either a URI or a blank node in the format _:name */ - public function remove_resource_triple($s, $p, $o): void + public function remove_resource_triple(string $s, string $p, $o): void { // Already removed if (!isset($this->_index[$s]) || !isset($this->_index[$s][$p])) { @@ -510,9 +509,9 @@ public function remove_resource_triple($s, $p, $o): void /** * @param string $s * @param string $p - * @param string $o + * @param bool|float|int|string $o */ - public function remove_literal_triple($s, $p, $o): void + public function remove_literal_triple(string $s, string $p, $o): void { // Already removed if (!isset($this->_index[$s]) || !isset($this->_index[$s][$p])) { @@ -539,7 +538,7 @@ public function remove_literal_triple($s, $p, $o): void * * @param string $s the subject of the triple, either a URI or a blank node in the format _:name */ - public function remove_triples_about($s): void + public function remove_triples_about(string $s): void { unset($this->_index[$s]); } @@ -550,7 +549,7 @@ public function remove_triples_about($s): void * @param string $rdfxml the RDF/XML to parse * @param string $base the base URI against which relative URIs in the RDF/XML document will be resolved */ - public function from_rdfxml($rdfxml, $base = ''): void + public function from_rdfxml(string $rdfxml, string $base = ''): void { if ($rdfxml) { $this->remove_all_triples(); @@ -565,7 +564,7 @@ public function from_rdfxml($rdfxml, $base = ''): void * * @param string $json the JSON to parse */ - public function from_json($json): void + public function from_json(string $json): void { if ($json) { $this->remove_all_triples(); @@ -583,7 +582,7 @@ public function from_json($json): void * * @param string $json the JSON to parse */ - public function add_json($json): void + public function add_json(string $json): void { if ($json) { $json_index = json_decode($json, true); @@ -596,7 +595,7 @@ public function add_json($json): void /** * @return array */ - public function get_parser_errors() + public function get_parser_errors(): array { return $this->parser_errors; } @@ -609,7 +608,7 @@ public function get_parser_errors() * * @author Keith Alexander */ - public function add_rdf($rdf, $base = ''): void + public function add_rdf(string $rdf, string $base = ''): void { $trimRdf = trim($rdf); if ($trimRdf[0] == '{') { // lazy is-this-json assessment - might be better to try json_decode - but more costly @@ -636,7 +635,7 @@ public function add_rdf($rdf, $base = ''): void * @param string $rdfxml the RDF/XML to parse * @param string $base the base URI against which relative URIs in the RDF/XML document will be resolved */ - public function add_rdfxml($rdfxml, $base = ''): void + public function add_rdfxml(string $rdfxml, string $base = ''): void { if ($rdfxml) { /** @var \ARC2_RDFXMLParser $parser */ @@ -656,7 +655,7 @@ public function add_rdfxml($rdfxml, $base = ''): void * @param string $turtle the Turtle to parse * @param string $base the base URI against which relative URIs in the Turtle document will be resolved */ - public function from_turtle($turtle, $base = ''): void + public function from_turtle(string $turtle, string $base = ''): void { if ($turtle) { $this->remove_all_triples(); @@ -672,7 +671,7 @@ public function from_turtle($turtle, $base = ''): void * @param string $turtle the Turtle to parse * @param string $base the base URI against which relative URIs in the Turtle document will be resolved */ - public function add_turtle($turtle, $base = ''): void + public function add_turtle(string $turtle, string $base = ''): void { if ($turtle) { /** @var \ARC2_TurtleParser $parser */ @@ -688,9 +687,9 @@ public function add_turtle($turtle, $base = ''): void * Replace the triples in the graph with those parsed from the supplied RDFa. * * @param string $html the HTML containing RDFa to parse - * @param string $base the base URI against which relative URIs in the Turtle document will be resolved + * @param string $base the base URI against which relative URIs in the RDFa document will be resolved */ - public function from_rdfa($html, $base = ''): void + public function from_rdfa(string $html, string $base = ''): void { if ($html) { $this->remove_all_triples(); @@ -702,9 +701,9 @@ public function from_rdfa($html, $base = ''): void * Add the triples parsed from the supplied RDFa to the graph. * * @param string $html the HTML containing RDFa to parse - * @param string $base the base URI against which relative URIs in the Turtle document will be resolved + * @param string $base the base URI against which relative URIs in the RDFa document will be resolved */ - public function add_rdfa($html, $base = ''): void + public function add_rdfa(string $html, string $base = ''): void { if ($html) { /** @var \ARC2_SemHTMLParser $parser */ @@ -724,7 +723,7 @@ public function add_rdfa($html, $base = ''): void * * @return bool */ - public function add_graph(ExtendedGraph $g) + public function add_graph(ExtendedGraph $g): bool { $triples_were_added = false; $index = $g->get_index(); @@ -746,11 +745,11 @@ public function add_graph(ExtendedGraph $g) * * @param string $s the subject of the triple, either a URI or a blank node in the format _:name * @param string $p the predicate URI of the triple - * @param string $o the object of the triple, either a URI or a blank node in the format _:name + * @param bool|float|int|string $o the object of the triple, either a URI or a blank node in the format _:name * * @return bool true if the triple exists in the graph, false otherwise */ - public function has_resource_triple($s, $p, $o): bool + public function has_resource_triple(string $s, string $p, $o): bool { if (array_key_exists($s, $this->_index) && array_key_exists($p, $this->_index[$s])) { foreach ($this->_index[$s][$p] as $value) { @@ -768,13 +767,13 @@ public function has_resource_triple($s, $p, $o): bool * * @param string $s the subject of the triple, either a URI or a blank node in the format _:name * @param string $p the predicate URI of the triple - * @param string $o the object of the triple as a literal value + * @param bool|float|int|string $o the object of the triple as a literal value * @param string|null $lang the language of the object * @param string|null $dt the datatype of the object * * @return bool true if the triple exists in the graph, false otherwise */ - public function has_literal_triple($s, $p, $o, $lang = null, $dt = null) + public function has_literal_triple(string $s, string $p, $o, ?string $lang = null, ?string $dt = null): bool { if (array_key_exists($s, $this->_index) && array_key_exists($p, $this->_index[$s])) { foreach ($this->_index[$s][$p] as $value) { @@ -803,7 +802,7 @@ public function has_literal_triple($s, $p, $o, $lang = null, $dt = null) * * @return array list of URIs and blank nodes that are the objects of triples with the supplied subject and predicate */ - public function get_resource_triple_values($s, $p): array + public function get_resource_triple_values(string $s, string $p): array { $values = []; if (array_key_exists($s, $this->_index) && array_key_exists($p, $this->_index[$s])) { @@ -821,11 +820,11 @@ public function get_resource_triple_values($s, $p): array * Fetch the literal values for a given subject and predicate. * * @param string $s the subject to search for - * @param string $p the predicate to search for + * @param string|array $p the predicate to search for or an array of predicates * * @return array list of literals that are the objects of triples with the supplied subject and predicate */ - public function get_literal_triple_values($s, $p): array + public function get_literal_triple_values(string $s, $p): array { $values = []; if (array_key_exists($s, $this->_index)) { @@ -855,11 +854,11 @@ public function get_literal_triple_values($s, $p): array * Fetch the values for a given subject and predicate. * * @param string $s the subject to search for - * @param string $p the predicate to search for + * @param string|array $p the predicate to search for, or an array of predicates * * @return array list of values of triples with the supplied subject and predicate */ - public function get_subject_property_values($s, $p): array + public function get_subject_property_values(string $s, $p): array { $values = []; if (!is_array($p)) { @@ -886,7 +885,7 @@ public function get_subject_property_values($s, $p): array * * @return ExtendedGraph triples with the supplied subject */ - public function get_subject_subgraph($s): \Tripod\ExtendedGraph + public function get_subject_subgraph(string $s): ExtendedGraph { $sub = new ExtendedGraph(); if (array_key_exists($s, $this->_index)) { @@ -898,6 +897,8 @@ public function get_subject_subgraph($s): \Tripod\ExtendedGraph /** * Fetch an array of all the subjects. + * + * @return string[] list of all the subjects in the graph */ public function get_subjects(): array { @@ -911,7 +912,7 @@ public function get_subjects(): array * * @return array */ - public function get_subjects_of_type($t) + public function get_subjects_of_type(string $t): array { return $this->get_subjects_where_resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#type', $t); } @@ -922,7 +923,7 @@ public function get_subjects_of_type($t) * @param string $p the predicate to match * @param string $o the resource object to match */ - public function get_subjects_where_resource($p, $o): array + public function get_subjects_where_resource(string $p, string $o): array { return array_merge($this->get_subjects_where($p, $o, 'uri'), $this->get_subjects_where($p, $o, 'bnode')); } @@ -931,11 +932,11 @@ public function get_subjects_where_resource($p, $o): array * Fetch an array of all the subjects where the predicate and object match a ?s $p $o triple in the graph and the object is a literal value. * * @param string $p the predicate to match - * @param string $o the resource object to match + * @param bool|float|int|string $o the literal object to match * * @return array */ - public function get_subjects_where_literal($p, $o) + public function get_subjects_where_literal(string $p, $o): array { return $this->get_subjects_where($p, $o, 'literal'); } @@ -948,7 +949,7 @@ public function get_subjects_where_literal($p, $o) * * @return array list of property URIs */ - public function get_subject_properties($s, $distinct = true): array + public function get_subject_properties(string $s, bool $distinct = true): array { $values = []; if (array_key_exists($s, $this->_index)) { @@ -975,7 +976,7 @@ public function get_subject_properties($s, $distinct = true): array * * @return bool true if a matching triple exists in the graph, false otherwise */ - public function subject_has_property($s, $p) + public function subject_has_property(string $s, string $p): bool { if (array_key_exists($s, $this->_index)) { return array_key_exists($p, $this->_index[$s]); @@ -991,7 +992,7 @@ public function subject_has_property($s, $p) * * @return bool true if the graph contains any triples with the specified subject, false otherwise */ - public function has_triples_about($s): bool + public function has_triples_about(string $s): bool { return array_key_exists($s, $this->_index); } @@ -1002,7 +1003,7 @@ public function has_triples_about($s): bool * @param string $s the subject of the triple, either a URI or a blank node in the format _:name * @param string $p the predicate URI of the triple */ - public function remove_property_values($s, $p): void + public function remove_property_values(string $s, string $p): void { unset($this->_index[$s][$p]); } @@ -1032,7 +1033,7 @@ public function is_empty(): bool * * @return string */ - public function get_label($resource_uri, $capitalize = false, $use_qnames = false) + public function get_label(string $resource_uri, bool $capitalize = false, bool $use_qnames = false): string { return $this->_labeller->get_label($resource_uri, $this, $capitalize, $use_qnames); } @@ -1044,7 +1045,7 @@ public function get_label($resource_uri, $capitalize = false, $use_qnames = fals * * @return string */ - public function get_inverse_label($resource_uri, $capitalize = false, $use_qnames = false) + public function get_inverse_label(string $resource_uri, bool $capitalize = false, bool $use_qnames = false): string { return $this->_labeller->get_inverse_label($resource_uri, $this, $capitalize, $use_qnames); } @@ -1088,7 +1089,7 @@ public function reify(array $resources, string $nodeID_prefix = 'Statement'): ar * * @author Keith */ - public function diff(...$indices): array + public function diff(array ...$indices): array { if (count($indices) === 1) { array_unshift($indices, $this->_index); @@ -1143,7 +1144,7 @@ public function diff(...$indices): array * * @author Keith */ - public function merge(...$indices) + public function merge(array ...$indices): array { $old_bnodeids = []; if (count($indices) === 1) { @@ -1211,7 +1212,7 @@ public function merge(...$indices) * @param string $look_for * @param string $replace_with */ - public function replace_resource($look_for, $replace_with): void + public function replace_resource(string $look_for, string $replace_with): void { $remove_list_resources = []; $remove_list_literals = []; @@ -1301,7 +1302,7 @@ public function replace_resource($look_for, $replace_with): void /** * @param string $listUri */ - public function get_list_values($listUri): array + public function get_list_values(string $listUri): array { $array = []; while (!empty($listUri) && $listUri != RDF_NIL) { @@ -1328,7 +1329,7 @@ public static function initProperties(array $properties): void * @param string $uri1 * @param string $uri2 */ - public function replace_uris($uri1, $uri2): void + public function replace_uris(string $uri1, string $uri2): void { $index = $this->get_index(); if (isset($index[$uri1])) { @@ -1358,9 +1359,9 @@ public function replace_uris($uri1, $uri2): void /** * @param string|null $s * @param string|null $p - * @param string|null $o + * @param bool|float|int|string|null $o */ - public function get_triple_count($s = null, $p = null, $o = null): int + public function get_triple_count(?string $s = null, ?string $p = null, $o = null): int { $index = $this->get_index(); @@ -1411,7 +1412,7 @@ public function get_resources(): array * * @return array the resource values found */ - public function get_resources_for_subject($s): array + public function get_resources_for_subject(string $s): array { $resources = []; if (array_key_exists($s, $this->_index)) { @@ -1430,7 +1431,7 @@ public function get_resources_for_subject($s): array /** * @param string $p */ - public function remove_properties($p): void + public function remove_properties(string $p): void { foreach ($this->get_subjects() as $s) { $this->remove_property_values($s, $p); @@ -1440,7 +1441,7 @@ public function remove_properties($p): void /** * @param string $p */ - public function get_resource_properties($p): array + public function get_resource_properties(string $p): array { $resources = []; foreach ($this->get_subjects() as $s) { @@ -1453,9 +1454,9 @@ public function get_resource_properties($p): array /** * @param string $p - * @param string $o + * @param bool|float|int|string $o */ - public function get_subjects_with_property_value($p, $o): array + public function get_subjects_with_property_value(string $p, $o): array { $subjects = []; foreach ($this->get_subjects() as $s) { @@ -1470,7 +1471,7 @@ public function get_subjects_with_property_value($p, $o): array /** * @param string $sequenceUri */ - public function get_sequence_values($sequenceUri): array + public function get_sequence_values(string $sequenceUri): array { $triples = $this->get_index(); $properties = []; @@ -1504,7 +1505,7 @@ public function get_sequence_values($sequenceUri): array /** * @param string $sequenceUri */ - public function get_next_sequence($sequenceUri): int + public function get_next_sequence(string $sequenceUri): int { $values = $this->get_sequence_values($sequenceUri); @@ -1513,9 +1514,9 @@ public function get_next_sequence($sequenceUri): int /** * @param string $s - * @param string $o + * @param bool|float|int|string $o */ - public function add_literal_to_sequence($s, $o): void + public function add_literal_to_sequence(string $s, $o): void { $this->add_to_sequence($s, $o, 'literal'); } @@ -1526,7 +1527,7 @@ public function add_literal_to_sequence($s, $o): void * @param string $sequenceUri * @param string $resourceValue */ - public function remove_resource_from_sequence($sequenceUri, $resourceValue): void + public function remove_resource_from_sequence(string $sequenceUri, string $resourceValue): void { $sequenceProperties = $this->get_subject_properties($sequenceUri); $sequenceValues = $this->get_sequence_values($sequenceUri); @@ -1551,9 +1552,9 @@ public function remove_resource_from_sequence($sequenceUri, $resourceValue): voi * @param string $s * @param string $o */ - public function add_resource_to_sequence($s, $o): void + public function add_resource_to_sequence(string $s, string $o): void { - $this->add_to_sequence($s, $o); + $this->add_to_sequence($s, $o, 'resource'); } /** @@ -1561,7 +1562,7 @@ public function add_resource_to_sequence($s, $o): void * @param string $o * @param int $position */ - public function add_resource_to_sequence_in_position($s, $o, $position): void + public function add_resource_to_sequence_in_position(string $s, string $o, int $position): void { $sequenceValues = $this->get_sequence_values($s); @@ -1586,10 +1587,10 @@ public function add_resource_to_sequence_in_position($s, $o, $position): void /** * @param string $s * @param string $p - * @param string $oOldValue - * @param string $oNewValue + * @param bool|float|int|string $oOldValue + * @param bool|float|int|string $oNewValue */ - public function replace_literal_triple($s, $p, $oOldValue, $oNewValue): bool + public function replace_literal_triple(string $s, string $p, $oOldValue, $oNewValue): bool { if ($this->has_literal_triple($s, $p, $oOldValue)) { $this->remove_literal_triple($s, $p, $oOldValue); @@ -1601,12 +1602,7 @@ public function replace_literal_triple($s, $p, $oOldValue, $oNewValue): bool return false; } - /** - * @param string $s - * @param string $p - * @param string $o - */ - public function replace_resource_triples($s, $p, $o): void + public function replace_resource_triples(string $s, string $p, ?string $o): void { if ($this->subject_has_property($s, $p)) { $this->remove_property_values($s, $p); @@ -1618,11 +1614,9 @@ public function replace_resource_triples($s, $p, $o): void } /** - * @param string $s - * @param string $p - * @param string $o + * @param bool|float|int|string|null $o */ - public function replace_literal_triples($s, $p, $o): void + public function replace_literal_triples(string $s, string $p, $o): void { if ($this->subject_has_property($s, $p)) { $this->remove_property_values($s, $p); @@ -1640,7 +1634,7 @@ public function replace_literal_triples($s, $p, $o): void * * @throws Exception */ - public function get_label_for_uri($uri) + public function get_label_for_uri(string $uri): string { if (!isset($this->_index[$uri])) { return ''; @@ -1670,7 +1664,7 @@ public function is_equal_to(ExtendedGraph $otherGraph): bool /** * @param string $type */ - public function remove_subjects_of_type($type): void + public function remove_subjects_of_type(string $type): void { $subjects = $this->get_subjects_of_type($type); foreach ($subjects as $s) { @@ -1693,7 +1687,7 @@ public function from_graph(ExtendedGraph $graph): void * but accepting scalars so we can handle legacy data * which was not type-checked. * - * @param string $value + * @param mixed $value */ protected function isValidLiteral($value): bool { @@ -1703,7 +1697,7 @@ protected function isValidLiteral($value): bool /** * Check if a triple value is valid. * - * @param string $value + * @param mixed $value */ protected function isValidResource($value): bool { @@ -1717,7 +1711,7 @@ protected function isValidResource($value): bool * * @throws Exception */ - private function _add_triple($s, $p, array $o_info): bool + private function _add_triple(string $s, string $p, array $o_info): bool { // The value $o should already have been validated by this point // It's validation differs depending on whether it is a literal or resource @@ -1755,7 +1749,7 @@ private function _add_triple($s, $p, array $o_info): bool /** * @param array $triples */ - private function _add_arc2_triple_list(&$triples): void + private function _add_arc2_triple_list(array &$triples): void { $bnode_index = []; @@ -1819,7 +1813,7 @@ private function _add_arc2_triple_list(&$triples): void /** * @param array $index */ - private function _to_arc_index(&$index): array + private function _to_arc_index(array &$index): array { $ret = []; @@ -1847,10 +1841,10 @@ private function _to_arc_index(&$index): array /** * @param string $p - * @param string $o - * + * @param bool|float|int|string $o + * @param string $type */ - private function get_subjects_where($p, $o, string $type): array + private function get_subjects_where(string $p, $o, string $type): array { $subjects = []; foreach ($this->_index as $subject => $properties) { @@ -1870,9 +1864,9 @@ private function get_subjects_where($p, $o, string $type): array /** * @param string $s - * @param string $o + * @param bool|float|int|string $o */ - private function add_to_sequence($s, $o, string $type = 'resource'): void + private function add_to_sequence(string $s, $o, string $type = 'resource'): void { $sequenceValue = $this->get_next_sequence($s); $this->add_resource_triple($s, self::rdf_type, self::rdf_seq); diff --git a/src/classes/Labeller.php b/src/classes/Labeller.php index 2cbc5578..93829528 100644 --- a/src/classes/Labeller.php +++ b/src/classes/Labeller.php @@ -296,7 +296,7 @@ class Labeller * @param string $prefix the namespace prefix to associate with the URI * @param string $uri the URI to associate with the prefix */ - public function set_namespace_mapping($prefix, $uri): void + public function set_namespace_mapping(string $prefix, string $uri): void { $this->_ns[$prefix] = $uri; } @@ -304,13 +304,13 @@ public function set_namespace_mapping($prefix, $uri): void /** * Convert a QName to a URI using registered namespace prefixes. * - * @param string $qname the QName to convert + * @param string|null $qName the QName to convert * - * @return string the URI corresponding to the QName if a suitable prefix exists, null otherwise + * @return string|null the URI corresponding to the QName if a suitable prefix exists, null otherwise */ - public function qname_to_uri($qname): ?string + public function qname_to_uri(?string $qName): ?string { - if (!preg_match('~^(.+):(.+)$~', $qname, $m)) { + if ($qName === null || !preg_match('~^(.+):(.+)$~', $qName, $m)) { return null; } if (isset($this->_ns[$m[1]])) { @@ -323,13 +323,13 @@ public function qname_to_uri($qname): ?string /** * Convert a URI to a QName using registered namespace prefixes. * - * @param string $uri the URI to convert + * @param string|null $uri the URI to convert * - * @return string the QName corresponding to the URI if a suitable prefix exists, null otherwise + * @return string|null the QName corresponding to the URI if a suitable prefix exists, null otherwise */ - public function uri_to_qname($uri): ?string + public function uri_to_qname(?string $uri): ?string { - if (preg_match('~^(.*[\/\#])([a-z0-9\-\_\:]+)$~i', $uri, $m)) { + if ($uri !== null && preg_match('~^(.*[\/\#])([a-z0-9\-\_\:]+)$~i', $uri, $m)) { $ns = $m[1]; $localname = $m[2]; $prefix = $this->get_prefix($ns); @@ -346,7 +346,7 @@ public function uri_to_qname($uri): ?string * * @return string */ - public function get_prefix($ns) + public function get_prefix(string $ns): string { $prefix = array_search($ns, $this->_ns, true); if ($prefix != null && $prefix !== false) { @@ -377,7 +377,7 @@ public function get_prefix($ns) /** * @param string $p */ - public function add_labelling_property($p): void + public function add_labelling_property(string $p): void { $this->_label_properties[] = $p; } @@ -385,7 +385,7 @@ public function add_labelling_property($p): void /** * @return array */ - public function get_ns() + public function get_ns(): array { return $this->_ns; } @@ -398,7 +398,7 @@ public function get_ns() * * @return string */ - public function get_label($uri, $g = null, $capitalize = false, $use_qnames = false) + public function get_label(string $uri, ?ExtendedGraph $g = null, bool $capitalize = false, bool $use_qnames = false): string { if ($g) { $label = $g->get_first_literal($uri, 'http://www.w3.org/2004/02/skos/core#prefLabel', '', 'en'); @@ -503,7 +503,7 @@ public function get_label($uri, $g = null, $capitalize = false, $use_qnames = fa * * @return string */ - public function get_plural_label($uri, $g = null, $capitalize = false, $use_qnames = false) + public function get_plural_label(string $uri, ?ExtendedGraph $g = null, bool $capitalize = false, bool $use_qnames = false): string { if ($g) { $label = $g->get_first_literal($uri, 'http://purl.org/net/vocab/2004/03/label#plural', '', 'en'); @@ -542,7 +542,7 @@ public function get_plural_label($uri, $g = null, $capitalize = false, $use_qnam * * @return string */ - public function get_inverse_label($uri, $g = null, $capitalize = false, $use_qnames = false) + public function get_inverse_label(string $uri, ?ExtendedGraph $g = null, bool $capitalize = false, bool $use_qnames = false): string { if ($g) { $label = $g->get_first_literal($uri, 'http://purl.org/net/vocab/2004/03/label#inverseSingular', '', 'en'); diff --git a/src/mongo/Labeller.php b/src/mongo/Labeller.php index 639e4387..eda5d0a0 100644 --- a/src/mongo/Labeller.php +++ b/src/mongo/Labeller.php @@ -31,11 +31,11 @@ public function __construct() /** * If labeller can generate a qname for this uri, it will return it. Otherwise just returns the original uri. * - * @param string $uri + * @param string|null $uri * - * @return string + * @return string|null */ - public function uri_to_alias($uri) + public function uri_to_alias(?string $uri): ?string { try { $retVal = $this->uri_to_qname($uri); @@ -48,28 +48,28 @@ public function uri_to_alias($uri) /** * If labeller can generate a uri for this qname, it will return it. Otherwise just returns the original qname. * - * @param string $qname + * @param string|null $qName * - * @return string + * @return string|null */ - public function qname_to_alias($qname) + public function qname_to_alias(?string $qName): ?string { try { - $retVal = $this->qname_to_uri($qname); + $retVal = $this->qname_to_uri($qName); } catch (LabellerException $e) { } - return (empty($retVal)) ? $qname : $retVal; + return (empty($retVal)) ? $qName : $retVal; } /** - * @param string $qName + * @param string|null $qName * - * @return string + * @return string|null * * @throws LabellerException */ - public function qname_to_uri($qName) + public function qname_to_uri(?string $qName): ?string { $retVal = parent::qname_to_uri($qName); if (empty($retVal)) { @@ -87,10 +87,10 @@ public function qname_to_uri($qName) * * @throws LabellerException */ - public function get_prefix($ns) + public function get_prefix(string $ns): string { $prefix = array_search($ns, $this->_ns, true); - if ($prefix != null && $prefix !== false) { + if ($prefix !== null && $prefix !== false) { return $prefix; } diff --git a/test/unit/ExtendedGraphTest.php b/test/unit/ExtendedGraphTest.php index 9a1bcf5a..6834c189 100644 --- a/test/unit/ExtendedGraphTest.php +++ b/test/unit/ExtendedGraphTest.php @@ -31,10 +31,7 @@ public function testAddValidValueToLiteralResultsInTriple($value): void $this->assertTrue($hasPropertyResult, 'The triple should have been added for this value'); } - /** - * @return \Iterator<(int | string), array<(1.2 | int | string | true)>> - */ - public function addValidValueToLiteralResultsInTriple_Provider(): \Iterator + public function addValidValueToLiteralResultsInTriple_Provider(): iterable { yield ['String']; yield [1]; @@ -57,10 +54,7 @@ public function testAddInvalidValueToLiteralResultsInNoTriple($value): void $this->assertFalse($hasPropertyResult, 'The triple should not have been added for this value'); } - /** - * @return \Iterator<(int | string), array<(Closure(): void | \stdClass | null)>> - */ - public function addInvalidValueToLiteralResultsInNoTriple_Provider(): \Iterator + public function addInvalidValueToLiteralResultsInNoTriple_Provider(): iterable { yield [null]; yield [new stdClass()]; @@ -74,16 +68,13 @@ public function addInvalidValueToLiteralResultsInNoTriple_Provider(): \Iterator */ public function testAddInvalidSubjectToLiteralThrowsException($value): void { - $this->expectException(Tripod\Exceptions\Exception::class); + $this->expectExceptionMessageMatches('/^(The subject is invalid|Argument 1.+must be of the type string.+)$/'); $graph = new ExtendedGraph(); $graph->add_resource_triple($value, 'http://some/predicate', 'http://someplace.com'); } - /** - * @return \Iterator<(int | string), array<(1.2 | array | Closure(): void | int | \stdClass | string | true | null)>> - */ - public function addInvalidSubjectToLiteralResultsInNoTriple_Provider(): \Iterator + public function addInvalidSubjectToLiteralResultsInNoTriple_Provider(): iterable { yield ['']; yield [1]; @@ -102,27 +93,22 @@ public function addInvalidSubjectToLiteralResultsInNoTriple_Provider(): \Iterato */ public function testAddInvalidPredicateToLiteralThrowsException($value): void { - $this->expectException(Tripod\Exceptions\Exception::class); + $this->expectExceptionMessageMatches('/^(The predicate is invalid|Argument 2.+must be of the type string.+)$/'); $graph = new ExtendedGraph(); $graph->add_resource_triple('http://some/subject/1', $value, 'http://someplace.com'); } - /** - * @return array|null[]|\stdClass[]|(\Closure(): void)[]> - */ - public function addInvalidPredicateToLiteralResultsInNoTriple_Provider(): array + public function addInvalidPredicateToLiteralResultsInNoTriple_Provider(): iterable { - return [ - [''], - [1], - [1.2], - [true], - [[]], - [null], - [new stdClass()], - [function (): void {}], - ]; + yield ['']; + yield [1]; + yield [1.2]; + yield [true]; + yield [[]]; + yield [null]; + yield [new stdClass()]; + yield [function (): void {}]; } public function testAddValidValueToResourceResultsInTriple(): void @@ -145,18 +131,21 @@ public function testAddInvalidValueToResourceResultsInNoTriple($value): void { $graph = new ExtendedGraph(); - $addResult = $graph->add_resource_triple('http://some/subject/1', 'http://some/predicate', $value); + try { + $addResult = $graph->add_resource_triple('http://some/subject/1', 'http://some/predicate', $value); + } catch (TypeError $typeError) { + $addResult = false; + } $this->assertFalse($addResult, 'The triple should not have been added for this value'); $hasPropertyResult = $graph->subject_has_property('http://some/subject/1', 'http://some/predicate'); $this->assertFalse($hasPropertyResult, 'The triple should not have been added for this value'); } - /** - * @return \Iterator<(int | string), array<(1.2 | array | Closure(): void | int | \stdClass | true | null)>> - */ - public function addInvalidValueToResourceResultsInNoTriple_Provider(): \Iterator + public function addInvalidValueToResourceResultsInNoTriple_Provider(): iterable { + yield ['']; + yield ['0']; yield [1]; yield [1.2]; yield [true]; @@ -173,16 +162,13 @@ public function addInvalidValueToResourceResultsInNoTriple_Provider(): \Iterator */ public function testAddInvalidSubjectToResourceThrowsException($value): void { - $this->expectException(Tripod\Exceptions\Exception::class); + $this->expectExceptionMessageMatches('/^(The subject is invalid|Argument 1.+must be of the type string.+)$/'); $graph = new ExtendedGraph(); $graph->add_resource_triple($value, 'http://some/predicate', 'http://someplace.com'); } - /** - * @return \Iterator<(int | string), array<(1.2 | array | Closure(): void | int | \stdClass | string | true | null)>> - */ - public function addInvalidSubjectToResourceResultsInNoTriple_Provider(): \Iterator + public function addInvalidSubjectToResourceResultsInNoTriple_Provider(): iterable { yield ['']; yield [1]; @@ -201,27 +187,22 @@ public function addInvalidSubjectToResourceResultsInNoTriple_Provider(): \Iterat */ public function testAddInvalidPredicateToResourceThrowsException($value): void { - $this->expectException(Tripod\Exceptions\Exception::class); + $this->expectExceptionMessageMatches('/^(The predicate is invalid|Argument 2.+must be of the type string.+)$/'); $graph = new ExtendedGraph(); $graph->add_resource_triple('http://some/subject/1', $value, 'http://someplace.com'); } - /** - * @return array|null[]|\stdClass[]|(\Closure(): void)[]> - */ - public function addInvalidPredicateToResourceResultsInNoTriple_Provider(): array + public function addInvalidPredicateToResourceResultsInNoTriple_Provider(): iterable { - return [ - [''], - [1], - [1.2], - [true], - [[]], - [null], - [new stdClass()], - [function (): void {}], - ]; + yield ['']; + yield [1]; + yield [1.2]; + yield [true]; + yield [[]]; + yield [null]; + yield [new stdClass()]; + yield [function (): void {}]; } public function testRemoveProperties(): void @@ -482,7 +463,7 @@ public function testGetTripleCountWithPredicate(): void $graph->add_literal_triple('http://some/subject/3', 'http://some/predicate', 'some object'); $expected = 3; - $actual = $graph->get_triple_count(false, 'http://some/predicate'); + $actual = $graph->get_triple_count(null, 'http://some/predicate'); $this->assertEquals($expected, $actual); } @@ -495,7 +476,7 @@ public function testGetTripleCountWithObject(): void $graph->add_literal_triple('http://some/subject/3', 'http://some/predicate', 'some object'); $expected = 3; - $actual = $graph->get_triple_count(false, false, 'some object'); + $actual = $graph->get_triple_count(null, null, 'some object'); $this->assertEquals($expected, $actual); } diff --git a/test/unit/mongo/EnsureIndexesTest.php b/test/unit/mongo/EnsureIndexesTest.php index 51945eb6..f1bf0102 100644 --- a/test/unit/mongo/EnsureIndexesTest.php +++ b/test/unit/mongo/EnsureIndexesTest.php @@ -56,10 +56,8 @@ public function testMandatoryArgs(string $argument, string $argumentName = null) /** * Data provider for testMandatoryArgs. - * - * @return \Iterator<(int | string), array> */ - public function mandatoryArgDataProvider(): \Iterator + public function mandatoryArgDataProvider(): iterable { yield ['tripodConfig', 'tripodConfig or tripodConfigGenerator']; yield ['storeName']; diff --git a/test/unit/mongo/MongoGraphTest.php b/test/unit/mongo/MongoGraphTest.php index fc512f54..d57318d2 100644 --- a/test/unit/mongo/MongoGraphTest.php +++ b/test/unit/mongo/MongoGraphTest.php @@ -136,10 +136,7 @@ public function testAddTripodArrayContainingValidLiteralValues($value): void $this->assertEquals($expected, $g); } - /** - * @return \Iterator<(int | string), array<(1.2 | int | string | true)>> - */ - public function addTripodArrayContainingValidLiteralValues_Provider(): \Iterator + public function addTripodArrayContainingValidLiteralValues_Provider(): iterable { yield ['A String']; yield [1]; @@ -175,10 +172,7 @@ public function testAddTripodArrayContainingInvalidLiteralValues($value): void $this->assertEquals($expected, $g); } - /** - * @return \Iterator<(int | string), array<(Closure(): void | \stdClass | null)>> - */ - public function addTripodArrayContainingInvalidLiteralValues_Provider(): \Iterator + public function addTripodArrayContainingInvalidLiteralValues_Provider(): iterable { yield [null]; yield [new stdClass()]; @@ -192,7 +186,7 @@ public function addTripodArrayContainingInvalidLiteralValues_Provider(): \Iterat */ public function testAddTripodArrayContainingInvalidPredicates($value): void { - $this->expectException(LabellerException::class); + $this->expectExceptionMessageMatches('/Argument 1 .* must be of the type string or null/'); $doc = [ '_id' => ['r' => 'http://talisaspire.com/works/4d101f63c10a6-2', 'c' => 'http://talisaspire.com/works/4d101f63c10a6-2'], '_version' => 0, @@ -211,10 +205,7 @@ public function testAddTripodArrayContainingInvalidPredicates($value): void $g->add_tripod_array($doc); } - /** - * @return \Iterator<(int | string), array<(1.2 | int | true)>> - */ - public function addTripodArrayContainingInvalidPredicates_Provider(): \Iterator + public function addTripodArrayContainingInvalidPredicates_Provider(): iterable { yield [1]; yield [1.2]; @@ -268,10 +259,7 @@ public function testAddTripodArrayContainingInvalidSubject($value): void $g->add_tripod_array($doc); } - /** - * @return \Iterator<(int | string), array<(1.2 | int | string | true)>> - */ - public function addTripodArrayContainingInvalidSubject_Provider(): \Iterator + public function addTripodArrayContainingInvalidSubject_Provider(): iterable { yield ['']; yield [1]; @@ -333,10 +321,7 @@ public function testAddTripodArrayContainingInvalidResourceValues($value): void $this->assertEquals($expected, $g); } - /** - * @return \Iterator<(int | string), array<(1.2 | array | Closure(): void | int | \stdClass | true | null)>> - */ - public function addTripodArrayContainingInvalidResourceValues_Provider(): \Iterator + public function addTripodArrayContainingInvalidResourceValues_Provider(): iterable { yield [1]; yield [1.2]; From 6f2502dea19fad4dd42105b33b393d38835c1b9a Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 00:16:47 +0000 Subject: [PATCH 03/56] Use ObjectId->getTimestamp() --- src/mongo/jobs/ApplyOperation.php | 3 +-- test/unit/mongo/ApplyOperationTest.php | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mongo/jobs/ApplyOperation.php b/src/mongo/jobs/ApplyOperation.php index eb4848eb..1f52ddbb 100644 --- a/src/mongo/jobs/ApplyOperation.php +++ b/src/mongo/jobs/ApplyOperation.php @@ -55,8 +55,7 @@ public function perform(): void $jobGroup = $this->getJobGroup($subject['storeName'], $this->args[self::TRACKING_KEY]); $jobCount = $jobGroup->incrementJobCount(-1); if ($jobCount <= 0) { - // @todo Replace this with ObjectId->getTimestamp() if we upgrade Mongo driver to 1.2 - $timestamp = new UTCDateTime(hexdec(substr($jobGroup->getId(), 0, 8)) * 1000); + $timestamp = new UTCDateTime($jobGroup->getId()->getTimestamp() * 1000); $tripod = $this->getTripod($subject['storeName'], $subject['podName']); $count = 0; foreach ($subject['specTypes'] as $specId) { diff --git a/test/unit/mongo/ApplyOperationTest.php b/test/unit/mongo/ApplyOperationTest.php index f5b6e16e..94923573 100644 --- a/test/unit/mongo/ApplyOperationTest.php +++ b/test/unit/mongo/ApplyOperationTest.php @@ -235,7 +235,7 @@ public function testApplyViewOperationCleanupIfAllGroupJobsComplete(): void $jobTrackerId = new ObjectId(); $applyOperation->args[ApplyOperation::TRACKING_KEY] = $jobTrackerId->__toString(); - $timestamp = new UTCDateTime(hexdec(substr($jobTrackerId, 0, 8)) * 1000); + $timestamp = new UTCDateTime($jobTrackerId->getTimestamp() * 1000); $jobGroup = $this->getMockBuilder(JobGroup::class) ->onlyMethods(['incrementJobCount']) @@ -543,7 +543,7 @@ public function testApplyTableOperationCleanupIfAllGroupJobsComplete(): void $jobTrackerId = new ObjectId(); $applyOperation->args[ApplyOperation::TRACKING_KEY] = $jobTrackerId->__toString(); - $timestamp = new UTCDateTime(hexdec(substr($jobTrackerId, 0, 8)) * 1000); + $timestamp = new UTCDateTime($jobTrackerId->getTimestamp() * 1000); $jobGroup = $this->getMockBuilder(JobGroup::class) ->onlyMethods(['incrementJobCount']) @@ -821,7 +821,7 @@ public function testApplySearchOperationCleanupIfAllGroupJobsComplete(): void $jobTrackerId = new ObjectId(); $applyOperation->args[ApplyOperation::TRACKING_KEY] = $jobTrackerId->__toString(); - $timestamp = new UTCDateTime(hexdec(substr($jobTrackerId, 0, 8)) * 1000); + $timestamp = new UTCDateTime($jobTrackerId->getTimestamp() * 1000); $jobGroup = $this->getMockBuilder(JobGroup::class) ->onlyMethods(['incrementJobCount']) From bde407bb5d4905e590dd6def47a332219e13d997 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 10:15:18 +0000 Subject: [PATCH 04/56] Fix call expectation --- test/unit/mongo/DiscoverImpactedSubjectsTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/unit/mongo/DiscoverImpactedSubjectsTest.php b/test/unit/mongo/DiscoverImpactedSubjectsTest.php index bc1d6617..bf06630a 100644 --- a/test/unit/mongo/DiscoverImpactedSubjectsTest.php +++ b/test/unit/mongo/DiscoverImpactedSubjectsTest.php @@ -814,10 +814,8 @@ public function testManuallySpecifiedQueueWillOverrideQueuesDefinedInConfig(): v $applyOperation->expects($this->once()) ->method('createJob') ->with( - [ - $tableSubjects, - $args['queue'], - ] + $tableSubjects, + $args['queue'], ); $this->performJob($discoverImpactedSubjects); From bb04e72c9b61d9b440e454a20131a3ae4e4c20c0 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 10:15:37 +0000 Subject: [PATCH 05/56] Fixes after applying Rector --- src/mongo/Config.php | 2 +- test/unit/mongo/MongoTripodTestBase.php | 2 +- test/unit/mongo/TestConfigGenerator.php | 2 +- test/unit/mongo/TestJobBase.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 2b37aa5f..67c1062d 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -1074,7 +1074,7 @@ public static function getLogger() /** * Sets the Tripod config. */ - public static function deserialize(array $config): self + public static function deserialize(array $config) { if (isset($config['class'], $config['config'])) { $config = $config['config']; diff --git a/test/unit/mongo/MongoTripodTestBase.php b/test/unit/mongo/MongoTripodTestBase.php index 65a2b324..1a06711c 100644 --- a/test/unit/mongo/MongoTripodTestBase.php +++ b/test/unit/mongo/MongoTripodTestBase.php @@ -431,7 +431,7 @@ class TripodTestConfig extends Tripod\Mongo\Config */ public function __construct() {} - protected function loadConfig(array $config) + public function loadConfig(array $config) { parent::loadConfig($config); } diff --git a/test/unit/mongo/TestConfigGenerator.php b/test/unit/mongo/TestConfigGenerator.php index 27dd2548..4f23a1a2 100644 --- a/test/unit/mongo/TestConfigGenerator.php +++ b/test/unit/mongo/TestConfigGenerator.php @@ -16,7 +16,7 @@ public function serialize(): array return ['class' => get_class($this), 'filename' => $this->fileName]; } - public static function deserialize(array $config): self + public static function deserialize(array $config) { $instance = new self(); $instance->fileName = $config['filename']; diff --git a/test/unit/mongo/TestJobBase.php b/test/unit/mongo/TestJobBase.php index f3a73846..04e07f13 100644 --- a/test/unit/mongo/TestJobBase.php +++ b/test/unit/mongo/TestJobBase.php @@ -8,7 +8,7 @@ class TestJobBase extends JobBase * Expose this method for testing. * {@inheritDoc} */ - protected function getTripodConfig() + public function getTripodConfig() { return parent::getTripodConfig(); } From 3501f5d363a2895d5f3439328be65a08bda6611f Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 10:35:34 +0000 Subject: [PATCH 06/56] Fix Config::getReplicaSetName test & validate data source --- src/mongo/Config.php | 4 +++ test/unit/mongo/MongoTripodConfigUnitTest.php | 28 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 67c1062d..0f4060a0 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -464,6 +464,10 @@ public function getDataSourceForPod($storeName, $podName) */ public function getReplicaSetName($datasource) { + if (empty($this->dataSources[$datasource])) { + throw new ConfigException(sprintf("Data source '%s' not in configuration", $datasource)); + } + if (!empty($this->dataSources[$datasource]['replicaSet'])) { return $this->dataSources[$datasource]['replicaSet']; } diff --git a/test/unit/mongo/MongoTripodConfigUnitTest.php b/test/unit/mongo/MongoTripodConfigUnitTest.php index d8fee9b8..c48c3a97 100644 --- a/test/unit/mongo/MongoTripodConfigUnitTest.php +++ b/test/unit/mongo/MongoTripodConfigUnitTest.php @@ -727,7 +727,33 @@ public function testGetReplicaSetName(): void $mtc = Config::getInstance(); $this->assertEquals('myreplicaset', $mtc->getReplicaSetName($mtc->getDefaultDataSourceForStore('tripod_php_testing'))); - $this->assertNull($mtc->getReplicaSetName('testing_2')); + $this->assertNull($mtc->getReplicaSetName($mtc->getDefaultDataSourceForStore('testing_2'))); + } + + public function testGetReplicaSetNameNonExistingDatasource() + { + Config::setConfig([ + 'defaultContext' => 'http://talisaspire.com/', + 'data_sources' => [ + 'tlog' => [ + 'type' => 'mongo', + 'connection' => 'mongodb://abc:zyx@localhost:27018', + ], + ], + 'transaction_log' => [ + 'database' => 'transactions', + 'collection' => 'transaction_log', + 'data_source' => 'tlog', + ], + 'stores' => [], + ]); + + /** @var Tripod\Mongo\Config */ + $mtc = Config::getInstance(); + + $this->expectException(ConfigException::class); + $this->expectExceptionMessage("Data source 'non_existing_data_source' not in configuration"); + $mtc->getReplicaSetName('non_existing_data_source'); } public function testGetReplicaSetNameFromConnectionString(): void From f46986ce2380894e44513a91c3de6117b735577a Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 13:11:59 +0000 Subject: [PATCH 07/56] Make lowercase modifier work with Stringable values --- src/mongo/delegates/Tables.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index 6182ff95..65f4c531 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -1361,7 +1361,7 @@ private function applyModifier($modifier, $value, array $options = []) break; case 'lowercase': - $value = is_array($value) ? array_map('strtolower', $value) : strtolower($value); + $value = is_array($value) ? array_map([$this, 'strtolower'], $value) : $this->strtolower($value); break; @@ -1386,6 +1386,16 @@ private function applyModifier($modifier, $value, array $options = []) return $value; } + /** + * Lowercase a value, casting to string first. + * @param string|\Stringable $value + * @return string + */ + private function strtolower($value): string + { + return strtolower((string) $value); + } + /** * Apply a regex to the RDF property value defined in $value. * From 66fbe41e7d756f12e8cadc87aa70c75fbf5bd45b Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 13:13:16 +0000 Subject: [PATCH 08/56] Re-throw exceptions instead of wrapping them in another --- src/mongo/Config.php | 2 +- src/mongo/base/DriverBase.php | 2 +- src/mongo/delegates/Updates.php | 4 ++-- src/mongo/util/TriplesUtil.php | 12 ++---------- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 0f4060a0..39bdc991 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -1871,7 +1871,7 @@ protected function getConnectionForDataSource($dataSource) if (!isset($this->connections[$dataSource])) { self::getLogger()->error('MongoConnectionException failed after ' . $retries . ' attempts (MAX:' . self::CONNECTION_RETRIES . '): ' . $e->getMessage()); - throw new ConnectionTimeoutException($exception); + throw $exception; } } diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index ab09a7a1..f349c497 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -318,7 +318,7 @@ protected function fetchGraph(array $query, $type, $collection = null, $includeP if ($cursorSuccess === false) { self::getLogger()->error('CursorException failed after ' . $retries . ' attempts (MAX:' . Config::CONNECTION_RETRIES . '): ' . $e->getMessage()); - throw new \Exception($exception); + throw $exception; } if ($ttlExpiredResources) { diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index c4cb167a..5a2eef61 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -734,7 +734,7 @@ protected function applyChangeSet(ChangeSet $cs, array $originalCBDs, $contextAl if (count($valueObject) === 1) { $valueObject = $valueObject[0]; // un-array if only one value } - + $this->addOperatorToChange($mongoUpdateOperations, MONGO_OPERATION_SET, [$nsPredicate => $valueObject]); } elseif ($predicateExists) { // remove all existing values, if existed in the first place @@ -777,7 +777,7 @@ protected function applyChangeSet(ChangeSet $cs, array $originalCBDs, $contextAl ] ); - throw new \Exception($e, $e->getCode(), $e); + throw $e; } } diff --git a/src/mongo/util/TriplesUtil.php b/src/mongo/util/TriplesUtil.php index 96595c29..6152c258 100644 --- a/src/mongo/util/TriplesUtil.php +++ b/src/mongo/util/TriplesUtil.php @@ -220,20 +220,12 @@ protected function saveCBD($cbdSubject, MongoGraph $cbdGraph, Collection $collec $existingGraph->add_tripod_array($collection->findOne($criteria)); $existingGraph->add_graph($cbdGraph); - try { - $collection->updateOne($criteria, ['$set' => $existingGraph->to_tripod_array($cbdSubject, $context)], ['w' => 1]); - } catch (\Exception $e2) { - throw new \Exception($e2->getMessage(), $e->getCode(), $e); // todo: would be good to have typed exception - } + $collection->updateOne($criteria, ['$set' => $existingGraph->to_tripod_array($cbdSubject, $context)], ['w' => 1]); } else { // retry echo 'CursorException on update: ' . $e->getMessage() . ", retrying\n"; - try { - $collection->insertOne($cbdGraph->to_tripod_array($cbdSubject, $context), ['w' => 1]); - } catch (\Exception $e2) { - throw new \Exception($e2->getMessage(), $e->getCode(), $e); // todo: would be good to have typed exception - } + $collection->insertOne($cbdGraph->to_tripod_array($cbdSubject, $context), ['w' => 1]); } } } From 4107d39795f7ae0a21cb6dcf439732370cd0d3e3 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 13:36:04 +0000 Subject: [PATCH 09/56] Stub sleep to speed up retry tests --- test/bootstrap.php | 2 ++ test/stubs.php | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 test/stubs.php diff --git a/test/bootstrap.php b/test/bootstrap.php index 03b85474..87b0558f 100644 --- a/test/bootstrap.php +++ b/test/bootstrap.php @@ -9,6 +9,8 @@ require_once __DIR__ . '/../src/tripod.inc.php'; +require_once __DIR__ . '/stubs.php'; + // Mongo Config For Main DB define('MONGO_MAIN_DB', 'acorn'); define('MONGO_MAIN_COLLECTION', 'CBD_harvest'); diff --git a/test/stubs.php b/test/stubs.php new file mode 100644 index 00000000..0ad9c8d4 --- /dev/null +++ b/test/stubs.php @@ -0,0 +1,12 @@ + Date: Fri, 27 Feb 2026 13:40:16 +0000 Subject: [PATCH 10/56] Make assertDocumentDoesNotHaveProperty pass if document doesn't exist --- test/unit/mongo/MongoTripodTestBase.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/unit/mongo/MongoTripodTestBase.php b/test/unit/mongo/MongoTripodTestBase.php index 1a06711c..fa153314 100644 --- a/test/unit/mongo/MongoTripodTestBase.php +++ b/test/unit/mongo/MongoTripodTestBase.php @@ -281,7 +281,10 @@ protected function assertDocumentDoesNotHaveProperty(array $_id, string $propert } $doc = $this->getDocument($_id, $tripod, $fromTransactionLog); - + if ($doc === null) { + $this->assertNull($doc); + return; // if document doesn't exist then it doesn't have the property, so assertion is successful + } $this->assertArrayNotHasKey($property, $doc, 'Document for ' . var_export($_id, true) . sprintf(' should not have property [%s], but propert was found', $property)); } From 6b68f0905d93fc51735dfab451af45d437cd35b8 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 13:42:01 +0000 Subject: [PATCH 11/56] Types in MongoTripodTestBase --- test/unit/mongo/MongoTripodTestBase.php | 53 +++++++++++++------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/test/unit/mongo/MongoTripodTestBase.php b/test/unit/mongo/MongoTripodTestBase.php index fa153314..352e80ee 100644 --- a/test/unit/mongo/MongoTripodTestBase.php +++ b/test/unit/mongo/MongoTripodTestBase.php @@ -5,6 +5,7 @@ use MongoDB\BSON\UTCDateTime; use MongoDB\Collection; use MongoDB\Driver\ReadPreference; +use MongoDB\InsertOneResult; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Tripod\Config; @@ -54,7 +55,7 @@ protected function tearDown(): void $this->tripodTransactionLog = null; } - protected function loadResourceData() + protected function loadResourceData(): void { $docs = json_decode(file_get_contents(__DIR__ . '/data/resources.json'), true); foreach ($docs as $d) { @@ -62,22 +63,22 @@ protected function loadResourceData() } } - protected function loadDatesDataViaTripod() + protected function loadDatesDataViaTripod(): void { $this->loadDataViaTripod($this->tripod, '/data/dates.json'); } - protected function loadResourceDataViaTripod() + protected function loadResourceDataViaTripod(): void { $this->loadDataViaTripod($this->tripod, '/data/resources.json'); } - protected function loadBaseSearchDataViaTripod() + protected function loadBaseSearchDataViaTripod(): void { $this->loadDataViaTripod($this->tripod, '/data/searchData.json'); } - protected function loadRelatedContentIntoTripod() + protected function loadRelatedContentIntoTripod(): void { $relatedContentTripod = new Driver( 'CBD_test_related_content', @@ -91,14 +92,14 @@ protected function loadRelatedContentIntoTripod() $this->loadDataViaTripod($relatedContentTripod, '/data/relatedContent.json'); } - protected function getConfigLocation() + protected function getConfigLocation(): string { return __DIR__ . '/data/config.json'; } // HELPERS BELOW HERE - protected function addDocument($doc, $toTransactionLog = false) + protected function addDocument($doc, $toTransactionLog = false): InsertOneResult { $config = Config::getInstance(); if ($toTransactionLog == true) { @@ -114,7 +115,7 @@ protected function addDocument($doc, $toTransactionLog = false) /** * @return Collection */ - protected function getTlogCollection() + protected function getTlogCollection(): Collection { $config = Config::getInstance(); $tLogConfig = $config->getTransactionLogConfig(); @@ -125,7 +126,7 @@ protected function getTlogCollection() /** * @return Collection */ - protected function getTripodCollection(Driver $tripod) + protected function getTripodCollection(Driver $tripod): Collection { $config = Config::getInstance(); $podName = $tripod->getPodName(); @@ -138,13 +139,13 @@ protected function getTripodCollection(Driver $tripod) } /** - * @param mixed $_id + * @param array|string $_id * @param Collection|IDriver|null $collection * @param bool $fromTransactionLog * * @return array|null */ - protected function getDocument($_id, $collection = null, $fromTransactionLog = false) + protected function getDocument($_id, $collection = null, bool $fromTransactionLog = false): ?array { if ($fromTransactionLog == true) { return $this->tripodTransactionLog->getTransaction($_id); @@ -166,7 +167,7 @@ protected function getDocument($_id, $collection = null, $fromTransactionLog = f * @param int $expectedNumberOfAdditions * @param int $expectedNumberOfRemovals */ - protected function assertChangesForGivenSubject(array $changes, $subjectOfChange, $expectedNumberOfAdditions, $expectedNumberOfRemovals) + protected function assertChangesForGivenSubject(array $changes, $subjectOfChange, $expectedNumberOfAdditions, $expectedNumberOfRemovals): void { $changeSet = null; @@ -208,7 +209,7 @@ protected function assertChangesForGivenSubject(array $changes, $subjectOfChange /** * @param array $doc */ - protected function assertTransactionDate(array $doc, string $key) + protected function assertTransactionDate(array $doc, string $key): void { $this->assertArrayHasKey($key, $doc, 'the date property: {$key} was not present in document'); $this->assertInstanceOf(UTCDateTime::class, $doc[$key]); @@ -222,7 +223,7 @@ protected function assertTransactionDate(array $doc, string $key) * @param Driver|null $tripod * @param bool $fromTransactionLog */ - protected function assertDocumentVersion(array $_id, $expectedValue = null, $hasVersion = true, $tripod = null, $fromTransactionLog = false) + protected function assertDocumentVersion(array $_id, $expectedValue = null, $hasVersion = true, $tripod = null, $fromTransactionLog = false): void { // just make sure $_id is aliased $labeller = new Labeller(); @@ -250,7 +251,7 @@ protected function assertDocumentVersion(array $_id, $expectedValue = null, $has * @param Collection|IDriver|null $tripod where to retrieve the document from * @param bool $fromTransactionLog if you want to retrieve the document from transaction log */ - protected function assertDocumentHasProperty(array $_id, $property, $expectedValue = null, $tripod = null, $fromTransactionLog = false) + protected function assertDocumentHasProperty(array $_id, $property, $expectedValue = null, $tripod = null, $fromTransactionLog = false): void { // just make sure $_id is aliased $labeller = new Labeller(); @@ -272,7 +273,7 @@ protected function assertDocumentHasProperty(array $_id, $property, $expectedVal * @param Collection|IDriver|null $tripod where to retrieve the document from * @param bool $fromTransactionLog if you want to retrieve the document from transaction log */ - protected function assertDocumentDoesNotHaveProperty(array $_id, string $property, $tripod = null, $fromTransactionLog = false) + protected function assertDocumentDoesNotHaveProperty(array $_id, string $property, $tripod = null, $fromTransactionLog = false): void { // just make sure $_id is aliased $labeller = new Labeller(); @@ -289,11 +290,11 @@ protected function assertDocumentDoesNotHaveProperty(array $_id, string $propert } /** - * @param mixed $_id + * @param array $_id * @param Driver|null $tripod * @param bool $fromTransactionLog */ - protected function assertDocumentExists($_id, $tripod = null, $fromTransactionLog = false) + protected function assertDocumentExists(array $_id, $tripod = null, bool $fromTransactionLog = false): void { $doc = $this->getDocument($_id, $tripod, $fromTransactionLog); $this->assertNotNull($doc); @@ -301,11 +302,11 @@ protected function assertDocumentExists($_id, $tripod = null, $fromTransactionLo } /** - * @param mixed $_id + * @param array $_id * @param Driver|null $tripod * @param bool $useTransactionTripod */ - protected function assertDocumentHasBeenDeleted(string $_id, $tripod = null, $useTransactionTripod = false) + protected function assertDocumentHasBeenDeleted(array $_id, $tripod = null, bool $useTransactionTripod = false): void { $doc = $this->getDocument($_id, $tripod, $useTransactionTripod); if ($useTransactionTripod) { @@ -325,7 +326,7 @@ protected function assertDocumentHasBeenDeleted(string $_id, $tripod = null, $us * @param string $p * @param string $o */ - protected function assertHasLiteralTriple(ExtendedGraph $graph, string $s, $p, $o) + protected function assertHasLiteralTriple(ExtendedGraph $graph, string $s, $p, $o): void { $this->assertTrue($graph->has_literal_triple($s, $p, $o), sprintf('Graph did not contain the literal triple: <%s> <%s> "%s"', $s, $p, $o)); } @@ -334,7 +335,7 @@ protected function assertHasLiteralTriple(ExtendedGraph $graph, string $s, $p, $ * @param string $p * @param string $o */ - protected function assertHasResourceTriple(ExtendedGraph $graph, string $s, $p, $o) + protected function assertHasResourceTriple(ExtendedGraph $graph, string $s, $p, $o): void { $this->assertTrue($graph->has_resource_triple($s, $p, $o), sprintf('Graph did not contain the resource triple: <%s> <%s> <%s>', $s, $p, $o)); } @@ -343,7 +344,7 @@ protected function assertHasResourceTriple(ExtendedGraph $graph, string $s, $p, * @param string $p * @param string $o */ - protected function assertDoesNotHaveLiteralTriple(ExtendedGraph $graph, string $s, $p, $o) + protected function assertDoesNotHaveLiteralTriple(ExtendedGraph $graph, string $s, $p, $o): void { $this->assertFalse($graph->has_literal_triple($s, $p, $o), sprintf('Graph should not contain the literal triple: <%s> <%s> "%s"', $s, $p, $o)); } @@ -352,7 +353,7 @@ protected function assertDoesNotHaveLiteralTriple(ExtendedGraph $graph, string $ * @param string $p * @param string $o */ - protected function assertDoesNotHaveResourceTriple(ExtendedGraph $graph, string $s, $p, $o) + protected function assertDoesNotHaveResourceTriple(ExtendedGraph $graph, string $s, $p, $o): void { $this->assertFalse($graph->has_resource_triple($s, $p, $o), sprintf('Graph should not contain the resource triple: <%s> <%s> <%s>', $s, $p, $o)); } @@ -361,7 +362,7 @@ protected function assertDoesNotHaveResourceTriple(ExtendedGraph $graph, string * @param string $subject * @param string $transaction_id */ - protected function lockDocument($subject, $transaction_id) + protected function lockDocument($subject, $transaction_id): void { $collection = Config::getInstance()->getCollectionForLocks('tripod_php_testing'); $labeller = new Labeller(); @@ -393,7 +394,7 @@ protected function getMockStat($host, $port, $prefix = '', array $mockedMethods /** * @return array|array> */ - protected function getStatsDConfig() + protected function getStatsDConfig(): array { return [ 'class' => StatsD::class, From ae320fe92505e6cb940f1c6a9fe95bdf99d78965 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 14:11:09 +0000 Subject: [PATCH 12/56] Fix types in MongoTransactionLogTest --- test/unit/mongo/MongoTransactionLogTest.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/unit/mongo/MongoTransactionLogTest.php b/test/unit/mongo/MongoTransactionLogTest.php index cf47e329..aa596124 100644 --- a/test/unit/mongo/MongoTransactionLogTest.php +++ b/test/unit/mongo/MongoTransactionLogTest.php @@ -436,7 +436,7 @@ public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully(): voi $mTripodUpdate->expects($this->atLeastOnce()) ->method('getUniqId') - ->willReturn(1); + ->willReturn('1'); $mTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') ->willReturn($mTripodUpdate); @@ -468,7 +468,7 @@ public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully(): voi $mTripodUpdate->expects($this->atLeastOnce()) ->method('getUniqId') - ->willReturn(2); + ->willReturn('2'); $mTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') ->willReturn($mTripodUpdate); @@ -517,7 +517,7 @@ public function testTransactionIsLoggedCorrectlyWhenCompletedSuccessfully(): voi $mTripodUpdate->expects($this->atLeastOnce()) ->method('getUniqId') - ->willReturn(3); + ->willReturn('3'); $mTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') ->willReturn($mTripodUpdate); @@ -574,7 +574,7 @@ public function testTransactionIsLoggedCorrectlyWhenSaveFails(): void $mTripodUpdate->expects($this->atLeastOnce()) ->method('getUniqId') - ->willReturn(1); + ->willReturn('1'); $mTripod->expects($this->atLeastOnce()) ->method('getDataUpdater') ->willReturn($mTripodUpdate); @@ -592,7 +592,7 @@ public function testTransactionIsLoggedCorrectlyWhenSaveFails(): void $mTripodUpdate->expects($this->atLeastOnce()) ->method('getUniqId') - ->willReturn(2); + ->willReturn('2'); $mTripodUpdate->expects($this->atLeastOnce()) ->method('applyChangeSet') ->willThrowException(new Exception('exception thrown by mock test')); @@ -725,16 +725,17 @@ public function testCreateNewTransactionThrowsExceptionIfInsertFails(): void /** * helper method. * + * @param int $id * @param string $subjectOfChange * @param string $startTime * @param string $endTime * @param int $_version * @return array */ - protected function buildTransactionDocument(string $id, $subjectOfChange, $startTime, $endTime, $_version): array + protected function buildTransactionDocument($id, $subjectOfChange, $startTime, $endTime, $_version): array { return [ - '_id' => 'transaction_' . $id, + '_id' => 'transaction_' . (string) $id, 'changes' => [ [ '_id' => ['r' => '_:cs0', 'c' => 'http://talisaspire.com/'], From 13752a2c75165677ea2c8f63ee6fb35f7dbc5792 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 14:26:24 +0000 Subject: [PATCH 13/56] Apply php-cs-fixer --- .php-cs-fixer.dist.php | 17 +++ scripts/mongo/BSONToQuads.php | 1 - scripts/mongo/BSONToTriples.php | 1 - scripts/mongo/detectNamespaces.php | 3 +- scripts/mongo/ensureIndexes.php | 1 - scripts/mongo/loadTriples.php | 1 - scripts/mongo/triplesToBSON.php | 1 - scripts/mongo/worker.inc.php | 2 +- src/TripodStatFactory.php | 3 +- src/classes/ChangeSet.php | 8 +- src/classes/ExtendedGraph.php | 143 +++--------------- src/classes/Labeller.php | 36 +---- src/classes/StatsD.php | 3 +- src/mongo/Config.php | 44 +++--- src/mongo/Driver.php | 2 +- src/mongo/ImpactedSubject.php | 6 +- src/mongo/Labeller.php | 16 -- src/mongo/base/DriverBase.php | 14 +- src/mongo/base/JobBase.php | 8 +- src/mongo/delegates/SearchDocuments.php | 4 +- src/mongo/delegates/SearchIndexer.php | 3 +- src/mongo/delegates/Tables.php | 51 ++++--- src/mongo/delegates/Updates.php | 19 +-- src/mongo/delegates/Views.php | 21 ++- src/mongo/jobs/ApplyOperation.php | 6 +- src/mongo/jobs/EnsureIndexes.php | 2 +- src/mongo/providers/MongoSearchProvider.php | 6 +- src/mongo/serializers/NQuadSerializer.php | 27 ++-- src/mongo/util/DateUtil.php | 2 +- src/mongo/util/IndexUtils.php | 2 +- src/mongo/util/TriplesUtil.php | 3 +- test/bootstrap.php | 2 - test/stubs.php | 17 +-- test/unit/mongo/ApplyOperationTest.php | 2 +- test/unit/mongo/EnsureIndexesTest.php | 4 +- test/unit/mongo/IndexUtilsTest.php | 12 +- test/unit/mongo/MongoTransactionLogTest.php | 1 + test/unit/mongo/MongoTripodConfigUnitTest.php | 10 +- test/unit/mongo/MongoTripodDriverTest.php | 1 - .../mongo/MongoTripodSearchDocumentsTest.php | 2 +- test/unit/mongo/MongoTripodTestBase.php | 16 +- 41 files changed, 184 insertions(+), 339 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index c9c91693..822972a2 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -10,10 +10,25 @@ ->setRules([ '@auto' => true, '@PhpCsFixer' => true, + 'blank_line_before_statement' => ['statements' => [ + 'break', + 'case', + 'continue', + 'declare', + 'default', + 'exit', + 'goto', + 'phpdoc', + 'return', + 'switch', + 'throw', + 'try', + ]], 'concat_space' => ['spacing' => 'one'], 'increment_style' => false, 'multiline_whitespace_before_semicolons' => ['strategy' => 'no_multi_line'], 'ordered_types' => ['null_adjustment' => 'always_last'], + 'phpdoc_no_empty_return' => false, 'phpdoc_types_order' => ['null_adjustment' => 'always_last'], 'yoda_style' => false, 'php_unit_method_casing' => false, @@ -23,5 +38,7 @@ ->setFinder( (new Finder()) ->in(__DIR__) + ->ignoreVCSIgnored(true) ->ignoreDotFiles(false) + ->notPath('rector.php') ); diff --git a/scripts/mongo/BSONToQuads.php b/scripts/mongo/BSONToQuads.php index a4399d6f..15eda59c 100644 --- a/scripts/mongo/BSONToQuads.php +++ b/scripts/mongo/BSONToQuads.php @@ -5,7 +5,6 @@ use Tripod\Mongo\TriplesUtil; require_once __DIR__ . '/common.inc.php'; - require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; if ($argc !== 2) { diff --git a/scripts/mongo/BSONToTriples.php b/scripts/mongo/BSONToTriples.php index f16dbd40..26ebf821 100644 --- a/scripts/mongo/BSONToTriples.php +++ b/scripts/mongo/BSONToTriples.php @@ -5,7 +5,6 @@ use Tripod\Mongo\TriplesUtil; require_once __DIR__ . '/common.inc.php'; - require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; if ($argc !== 2) { diff --git a/scripts/mongo/detectNamespaces.php b/scripts/mongo/detectNamespaces.php index 5f48db6b..8c22091a 100644 --- a/scripts/mongo/detectNamespaces.php +++ b/scripts/mongo/detectNamespaces.php @@ -4,7 +4,6 @@ use Tripod\Mongo\TriplesUtil; require_once __DIR__ . '/common.inc.php'; - require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; ini_set('memory_limit', '32M'); @@ -156,7 +155,7 @@ function indent($json): string // If the last character was the beginning of an element, // output a new line and indent the next line. - if ((in_array($char, [',', '{', '['])) && $outOfQuotes) { + if (in_array($char, [',', '{', '[']) && $outOfQuotes) { $result .= $newLine; if ($char === '{' || $char === '[') { $pos++; diff --git a/scripts/mongo/ensureIndexes.php b/scripts/mongo/ensureIndexes.php index a4c57b97..c6c23599 100644 --- a/scripts/mongo/ensureIndexes.php +++ b/scripts/mongo/ensureIndexes.php @@ -5,7 +5,6 @@ use Tripod\Timer; require_once __DIR__ . '/common.inc.php'; - require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; if (!in_array($argc, [2, 3, 4])) { diff --git a/scripts/mongo/loadTriples.php b/scripts/mongo/loadTriples.php index 6d384191..540bf302 100644 --- a/scripts/mongo/loadTriples.php +++ b/scripts/mongo/loadTriples.php @@ -5,7 +5,6 @@ use Tripod\Timer; require_once __DIR__ . '/common.inc.php'; - require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; /** diff --git a/scripts/mongo/triplesToBSON.php b/scripts/mongo/triplesToBSON.php index 8f5ecd6e..96553b34 100644 --- a/scripts/mongo/triplesToBSON.php +++ b/scripts/mongo/triplesToBSON.php @@ -4,7 +4,6 @@ use Tripod\Mongo\TriplesUtil; require_once __DIR__ . '/common.inc.php'; - require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; if ($argc !== 2) { diff --git a/scripts/mongo/worker.inc.php b/scripts/mongo/worker.inc.php index 4f582323..1ecedcf7 100644 --- a/scripts/mongo/worker.inc.php +++ b/scripts/mongo/worker.inc.php @@ -6,8 +6,8 @@ use Tripod\Mongo\DriverBase; require_once __DIR__ . '/common.inc.php'; +require_once __DIR__ . '/../../src/tripod.inc.php'; -require __DIR__ . '/../../src/tripod.inc.php'; // the global is necessary for Resque worker to send statements to $logger = new Logger('TRIPOD-WORKER'); $logger->pushHandler(new StreamHandler('php://stderr', LogLevel::WARNING)); // resque too chatty on NOTICE & INFO. YMMV diff --git a/src/TripodStatFactory.php b/src/TripodStatFactory.php index 5a9a53db..eddd448c 100644 --- a/src/TripodStatFactory.php +++ b/src/TripodStatFactory.php @@ -9,8 +9,9 @@ class TripodStatFactory { /** - * @return ITripodStat * @param array $config + * + * @return ITripodStat */ public static function create(array $config = []) { diff --git a/src/classes/ChangeSet.php b/src/classes/ChangeSet.php index be798b17..b65ae7e8 100644 --- a/src/classes/ChangeSet.php +++ b/src/classes/ChangeSet.php @@ -78,7 +78,7 @@ public function __construct(array $a) $parser->parse(false, $a[$rdf]); $a[$rdf] = $parser->getSimpleIndex(0); } elseif ( - is_array($a[$rdf]) && isset($a[$rdf][0]) && isset($a[$rdf][0]['s']) + is_array($a[$rdf]) && isset($a[$rdf][0], $a[$rdf][0]['s']) ) { // triples array /** @var \ARC2_RDFSerializer $ser */ $ser = \ARC2::getTurtleSerializer(); @@ -210,9 +210,6 @@ public function addT($s, $p, $o, $o_type = 'bnode'): void } } - /** - * @return string - */ public function toRDFXML(): string { /** @var \ARC2_RDFSerializer $ser */ @@ -221,9 +218,6 @@ public function toRDFXML(): string return $ser->getSerializedIndex($this->_index); } - /** - * @return string - */ public function to_rdfxml(): string { return $this->toRDFXML(); diff --git a/src/classes/ExtendedGraph.php b/src/classes/ExtendedGraph.php index d05237b8..f0694495 100644 --- a/src/classes/ExtendedGraph.php +++ b/src/classes/ExtendedGraph.php @@ -133,19 +133,11 @@ public function uri_to_qname(?string $uri): ?string return $this->_labeller->uri_to_qname($uri); } - /** - * @param string $ns - * - * @return string - */ public function get_prefix(string $ns): string { return $this->_labeller->get_prefix($ns); } - /** - * @param string $p - */ public function add_labelling_property(string $p): void { $this->_labeller->add_labelling_property($p); @@ -186,11 +178,11 @@ public function add_resource_triple(string $s, string $p, ?string $o): bool /** * Adds a triple with a literal object to the graph. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate of the triple as a URI - * @param bool|float|int|string $o the object of the triple as a scalar value - * @param string|null $lang the language code of the triple's object (optional) - * @param string|null $dt the datatype URI of the triple's object (optional) + * @param string $s the subject of the triple, either a URI or a blank node in the format _:name + * @param string $p the predicate of the triple as a URI + * @param bool|float|int|string $o the object of the triple as a scalar value + * @param string|null $lang the language code of the triple's object (optional) + * @param string|null $dt the datatype URI of the triple's object (optional) * * @return bool true if the triple was new, false if it already existed in the graph */ @@ -297,7 +289,6 @@ public function to_json(): string * Serialise the graph to HTML. * * @param array|string|null $s - * @param bool $guess_labels * * @return string a HTML version of the graph */ @@ -408,7 +399,7 @@ public function to_html($s = null, bool $guess_labels = true): string * Fetch the first literal value for a given subject and predicate. If there are multiple possible values then one is selected at random. * * @param string $s the subject to search for - * @param array|string $p the predicate to search for, or an array of predicates + * @param string|string[] $p the predicate to search for, or an array of predicates * @param bool|float|int|string|null $default a default value to use if no literal values are found * * @return bool|float|int|string|null the first literal value found or the supplied default if no values were found @@ -480,9 +471,9 @@ public function get_first_resource(string $s, string $p, ?string $default = null /** * Remove a triple with a resource object from the graph. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate URI of the triple - * @param bool|float|int|string $o the object of the triple, either a URI or a blank node in the format _:name + * @param string $s the subject of the triple, either a URI or a blank node in the format _:name + * @param string $p the predicate URI of the triple + * @param bool|float|int|string $o the object of the triple, either a URI or a blank node in the format _:name */ public function remove_resource_triple(string $s, string $p, $o): void { @@ -507,9 +498,7 @@ public function remove_resource_triple(string $s, string $p, $o): void } /** - * @param string $s - * @param string $p - * @param bool|float|int|string $o + * @param bool|float|int|string $o */ public function remove_literal_triple(string $s, string $p, $o): void { @@ -592,9 +581,6 @@ public function add_json(string $json): void } } - /** - * @return array - */ public function get_parser_errors(): array { return $this->parser_errors; @@ -720,8 +706,6 @@ public function add_rdfa(string $html, string $base = ''): void * Add the triples in the supplied graph to the current graph. * * @param ExtendedGraph $g the graph to read - * - * @return bool */ public function add_graph(ExtendedGraph $g): bool { @@ -743,9 +727,9 @@ public function add_graph(ExtendedGraph $g): bool /** * Tests whether the graph contains the given triple. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate URI of the triple - * @param bool|float|int|string $o the object of the triple, either a URI or a blank node in the format _:name + * @param string $s the subject of the triple, either a URI or a blank node in the format _:name + * @param string $p the predicate URI of the triple + * @param bool|float|int|string $o the object of the triple, either a URI or a blank node in the format _:name * * @return bool true if the triple exists in the graph, false otherwise */ @@ -765,11 +749,11 @@ public function has_resource_triple(string $s, string $p, $o): bool /** * Tests whether the graph contains the given triple. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate URI of the triple - * @param bool|float|int|string $o the object of the triple as a literal value - * @param string|null $lang the language of the object - * @param string|null $dt the datatype of the object + * @param string $s the subject of the triple, either a URI or a blank node in the format _:name + * @param string $p the predicate URI of the triple + * @param bool|float|int|string $o the object of the triple as a literal value + * @param string|null $lang the language of the object + * @param string|null $dt the datatype of the object * * @return bool true if the triple exists in the graph, false otherwise */ @@ -819,8 +803,8 @@ public function get_resource_triple_values(string $s, string $p): array /** * Fetch the literal values for a given subject and predicate. * - * @param string $s the subject to search for - * @param string|array $p the predicate to search for or an array of predicates + * @param string $s the subject to search for + * @param array|string $p the predicate to search for or an array of predicates * * @return array list of literals that are the objects of triples with the supplied subject and predicate */ @@ -853,8 +837,8 @@ public function get_literal_triple_values(string $s, $p): array /** * Fetch the values for a given subject and predicate. * - * @param string $s the subject to search for - * @param string|array $p the predicate to search for, or an array of predicates + * @param string $s the subject to search for + * @param array|string $p the predicate to search for, or an array of predicates * * @return array list of values of triples with the supplied subject and predicate */ @@ -909,8 +893,6 @@ public function get_subjects(): array * Fetch an array of all the subject that have and rdf type that matches that given. * * @param string $t the type to match - * - * @return array */ public function get_subjects_of_type(string $t): array { @@ -931,10 +913,8 @@ public function get_subjects_where_resource(string $p, string $o): array /** * Fetch an array of all the subjects where the predicate and object match a ?s $p $o triple in the graph and the object is a literal value. * - * @param string $p the predicate to match + * @param string $p the predicate to match * @param bool|float|int|string $o the literal object to match - * - * @return array */ public function get_subjects_where_literal(string $p, $o): array { @@ -1026,25 +1006,11 @@ public function is_empty(): bool return count($this->_index) === 0; } - /** - * @param string $resource_uri - * @param bool $capitalize - * @param bool $use_qnames - * - * @return string - */ public function get_label(string $resource_uri, bool $capitalize = false, bool $use_qnames = false): string { return $this->_labeller->get_label($resource_uri, $this, $capitalize, $use_qnames); } - /** - * @param string $resource_uri - * @param bool $capitalize - * @param bool $use_qnames - * - * @return string - */ public function get_inverse_label(string $resource_uri, bool $capitalize = false, bool $use_qnames = false): string { return $this->_labeller->get_inverse_label($resource_uri, $this, $capitalize, $use_qnames); @@ -1086,7 +1052,6 @@ public function reify(array $resources, string $nodeID_prefix = 'Statement'): ar * * @param array1, array2, [array3, ...] * - * * @author Keith */ public function diff(array ...$indices): array @@ -1140,8 +1105,6 @@ public function diff(array ...$indices): array * * @param array1, array2, [array3, ...] * - * @return array - * * @author Keith */ public function merge(array ...$indices): array @@ -1208,10 +1171,6 @@ public function merge(array ...$indices): array return $current; } - /** - * @param string $look_for - * @param string $replace_with - */ public function replace_resource(string $look_for, string $replace_with): void { $remove_list_resources = []; @@ -1299,9 +1258,6 @@ public function replace_resource(string $look_for, string $replace_with): void } } - /** - * @param string $listUri - */ public function get_list_values(string $listUri): array { $array = []; @@ -1325,9 +1281,6 @@ public static function initProperties(array $properties): void /** * Replaces $uri1 with $uri2 in subject, predicate and object position. - * - * @param string $uri1 - * @param string $uri2 */ public function replace_uris(string $uri1, string $uri2): void { @@ -1357,8 +1310,6 @@ public function replace_uris(string $uri1, string $uri2): void } /** - * @param string|null $s - * @param string|null $p * @param bool|float|int|string|null $o */ public function get_triple_count(?string $s = null, ?string $p = null, $o = null): int @@ -1428,9 +1379,6 @@ public function get_resources_for_subject(string $s): array return array_unique($resources); } - /** - * @param string $p - */ public function remove_properties(string $p): void { foreach ($this->get_subjects() as $s) { @@ -1438,9 +1386,6 @@ public function remove_properties(string $p): void } } - /** - * @param string $p - */ public function get_resource_properties(string $p): array { $resources = []; @@ -1453,7 +1398,6 @@ public function get_resource_properties(string $p): array } /** - * @param string $p * @param bool|float|int|string $o */ public function get_subjects_with_property_value(string $p, $o): array @@ -1468,9 +1412,6 @@ public function get_subjects_with_property_value(string $p, $o): array return $subjects; } - /** - * @param string $sequenceUri - */ public function get_sequence_values(string $sequenceUri): array { $triples = $this->get_index(); @@ -1502,9 +1443,6 @@ public function get_sequence_values(string $sequenceUri): array return $values; } - /** - * @param string $sequenceUri - */ public function get_next_sequence(string $sequenceUri): int { $values = $this->get_sequence_values($sequenceUri); @@ -1513,7 +1451,6 @@ public function get_next_sequence(string $sequenceUri): int } /** - * @param string $s * @param bool|float|int|string $o */ public function add_literal_to_sequence(string $s, $o): void @@ -1523,9 +1460,6 @@ public function add_literal_to_sequence(string $s, $o): void /** * Remove a resource from a specified sequence and reindex the sequence to remove the gap. - * - * @param string $sequenceUri - * @param string $resourceValue */ public function remove_resource_from_sequence(string $sequenceUri, string $resourceValue): void { @@ -1548,20 +1482,11 @@ public function remove_resource_from_sequence(string $sequenceUri, string $resou } } - /** - * @param string $s - * @param string $o - */ public function add_resource_to_sequence(string $s, string $o): void { $this->add_to_sequence($s, $o, 'resource'); } - /** - * @param string $s - * @param string $o - * @param int $position - */ public function add_resource_to_sequence_in_position(string $s, string $o, int $position): void { $sequenceValues = $this->get_sequence_values($s); @@ -1585,8 +1510,6 @@ public function add_resource_to_sequence_in_position(string $s, string $o, int $ } /** - * @param string $s - * @param string $p * @param bool|float|int|string $oOldValue * @param bool|float|int|string $oNewValue */ @@ -1628,10 +1551,6 @@ public function replace_literal_triples(string $s, string $p, $o): void } /** - * @param string $uri - * - * @return string - * * @throws Exception */ public function get_label_for_uri(string $uri): string @@ -1661,9 +1580,6 @@ public function is_equal_to(ExtendedGraph $otherGraph): bool return empty($diffThisAndThat) && empty($diffThatAndThis); } - /** - * @param string $type - */ public function remove_subjects_of_type(string $type): void { $subjects = $this->get_subjects_of_type($type); @@ -1705,10 +1621,6 @@ protected function isValidResource($value): bool } /** - * @param string $s - * @param string $p - * - * * @throws Exception */ private function _add_triple(string $s, string $p, array $o_info): bool @@ -1746,9 +1658,6 @@ private function _add_triple(string $s, string $p, array $o_info): bool return false; } - /** - * @param array $triples - */ private function _add_arc2_triple_list(array &$triples): void { $bnode_index = []; @@ -1810,9 +1719,6 @@ private function _add_arc2_triple_list(array &$triples): void } // until ARC2 upgrades to support RDF/PHP we need to rename all types of "uri" to "iri" - /** - * @param array $index - */ private function _to_arc_index(array &$index): array { $ret = []; @@ -1840,9 +1746,7 @@ private function _to_arc_index(array &$index): array } /** - * @param string $p * @param bool|float|int|string $o - * @param string $type */ private function get_subjects_where(string $p, $o, string $type): array { @@ -1863,7 +1767,6 @@ private function get_subjects_where(string $p, $o, string $type): array } /** - * @param string $s * @param bool|float|int|string $o */ private function add_to_sequence(string $s, $o, string $type = 'resource'): void diff --git a/src/classes/Labeller.php b/src/classes/Labeller.php index 93829528..990eb98b 100644 --- a/src/classes/Labeller.php +++ b/src/classes/Labeller.php @@ -341,11 +341,6 @@ public function uri_to_qname(?string $uri): ?string return null; } - /** - * @param string $ns - * - * @return string - */ public function get_prefix(string $ns): string { $prefix = array_search($ns, $this->_ns, true); @@ -374,30 +369,16 @@ public function get_prefix(string $ns): string return $prefix; } - /** - * @param string $p - */ public function add_labelling_property(string $p): void { $this->_label_properties[] = $p; } - /** - * @return array - */ public function get_ns(): array { return $this->_ns; } - /** - * @param string $uri - * @param ExtendedGraph|null $g - * @param bool $capitalize - * @param bool $use_qnames - * - * @return string - */ public function get_label(string $uri, ?ExtendedGraph $g = null, bool $capitalize = false, bool $use_qnames = false): string { if ($g) { @@ -489,20 +470,13 @@ public function get_label(string $uri, ?ExtendedGraph $g = null, bool $capitaliz if ($capitalize && preg_match('~^[a-z]~', $localname)) { return ucfirst($localname); } + return $localname; } return $uri; } - /** - * @param string $uri - * @param ExtendedGraph|null $g - * @param bool $capitalize - * @param bool $use_qnames - * - * @return string - */ public function get_plural_label(string $uri, ?ExtendedGraph $g = null, bool $capitalize = false, bool $use_qnames = false): string { if ($g) { @@ -534,14 +508,6 @@ public function get_plural_label(string $uri, ?ExtendedGraph $g = null, bool $ca return $label; } - /** - * @param string $uri - * @param ExtendedGraph|null $g - * @param bool $capitalize - * @param bool $use_qnames - * - * @return string - */ public function get_inverse_label(string $uri, ?ExtendedGraph $g = null, bool $capitalize = false, bool $use_qnames = false): string { if ($g) { diff --git a/src/classes/StatsD.php b/src/classes/StatsD.php index 60ca9048..736d4fb6 100644 --- a/src/classes/StatsD.php +++ b/src/classes/StatsD.php @@ -69,7 +69,7 @@ public function gauge($operation, string $value): void } /** - * @return array|array> + * @return array|class-string> */ public function getConfig() { @@ -232,6 +232,7 @@ protected function send($data, $sampleRate = 1) * } * * @param array|string $value + * * @return array An associative array of the grouped_by_database and aggregate stats */ protected function generateStatData(string $operation, $value): array diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 39bdc991..9f371fd8 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -192,8 +192,9 @@ public function setMongoCursorTimeout($mongoCursorTimeout): void } /** - * @throws ConfigException * @param array $spec + * + * @throws ConfigException */ public function validateTableSpec(array $spec): void { @@ -298,10 +299,10 @@ public function getDefaultContextAlias() * * @throws ConfigException */ - public static function getInstance(): \Tripod\Mongo\IConfigInstance + public static function getInstance(): IConfigInstance { self::getLogger()->warning( - \Tripod\Mongo\Config::class . '::getInstance deprecated, use ' . \Tripod\Config::class . '::getInstance instead' + Config::class . '::getInstance deprecated, use ' . \Tripod\Config::class . '::getInstance instead' ); return \Tripod\Config::getInstance(); @@ -315,7 +316,7 @@ public static function getInstance(): \Tripod\Mongo\IConfigInstance public static function setConfig(array $config): void { self::getLogger()->warning( - \Tripod\Mongo\Config::class . '::setConfig deprecated, use ' . \Tripod\Config::class . '::setConfig instead' + Config::class . '::setConfig deprecated, use ' . \Tripod\Config::class . '::setConfig instead' ); \Tripod\Config::setConfig($config); } @@ -328,7 +329,7 @@ public static function setConfig(array $config): void public static function getConfig(): array { self::getLogger()->warning( - \Tripod\Mongo\Config::class . '::getConfig deprecated, use ' . \Tripod\Config::class . '::getConfig instead' + Config::class . '::getConfig deprecated, use ' . \Tripod\Config::class . '::getConfig instead' ); return \Tripod\Config::getConfig(); @@ -1115,8 +1116,9 @@ public function getBatchSize($operation) /** * Used to load the config from self::config when new instance is generated. * - * @throws ConfigException * @param array $config + * + * @throws ConfigException */ protected function loadConfig(array $config) { @@ -1316,10 +1318,10 @@ protected function loadConfig(array $config) } /** - * @param int $depth + * @param int $depth + * @param array $spec * * @throws ConfigException - * @param array $spec */ protected function validateTableSpecPart(array $spec, $depth = 0) { @@ -1420,7 +1422,7 @@ protected function validateTableSpecPart(array $spec, $depth = 0) } /** - * @param string[] $availableFields + * @param string[] $availableFields * @param array $spec */ protected function validateComputedFieldSpec(string $type, array $spec, array $availableFields) @@ -1444,9 +1446,10 @@ protected function validateComputedFieldSpec(string $type, array $spec, array $a } /** - * @throws ConfigException * @param array $spec - * @param string[] $availableFields + * @param string[] $availableFields + * + * @throws ConfigException */ protected function validateComputedConditionalSpec(array $spec, array $availableFields) { @@ -1537,9 +1540,10 @@ protected function validateSpecVariableReplacement($value, array $availableField } /** - * @throws ConfigException * @param array $spec - * @param string[] $availableFields + * @param string[] $availableFields + * + * @throws ConfigException */ protected function validateComputedReplaceSpec(array $spec, array $availableFields) { @@ -1561,9 +1565,10 @@ protected function validateComputedReplaceSpec(array $spec, array $availableFiel } /** - * @throws ConfigException * @param array $spec - * @param string[] $availableFields + * @param string[] $availableFields + * + * @throws ConfigException */ protected function validateComputedArithmeticSpec(array $spec, array $availableFields) { @@ -1883,7 +1888,7 @@ protected function getConnectionForDataSource($dataSource) * * @param string $connectionString */ - protected function getMongoClient($connectionString, array $connectionOptions = []): \MongoDB\Client + protected function getMongoClient($connectionString, array $connectionOptions = []): Client { return new Client( $connectionString, @@ -1954,10 +1959,11 @@ private function ifCountExistsWithoutTTLThrowException(array $spec): void /** * Returns the value of the supplied key or throws an error, if missing. * + * @param array $a * * @return mixed + * * @throws ConfigException - * @param array $a */ private function getMandatoryKey(string $key, array $a, string $configName = 'config') { @@ -1995,7 +2001,6 @@ private function findFieldsInTableSpec($fieldName, $spec) } /** - * * @return string */ private static function getQueueName(string $envVar, string $type) @@ -2006,9 +2011,10 @@ private static function getQueueName(string $envVar, string $type) } /** - * @param bool $default + * @param bool $default * * @return bool|string + * * @throws ConfigException */ private static function getenv(string $env, $default = false) diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index a834189e..78db3c5f 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -691,7 +691,7 @@ public function getComposite(string $operation) /** * For mocking. */ - protected function getLabeller(): \Tripod\Mongo\Labeller + protected function getLabeller(): Labeller { return new Labeller(); } diff --git a/src/mongo/ImpactedSubject.php b/src/mongo/ImpactedSubject.php index 0b139668..6741c50d 100644 --- a/src/mongo/ImpactedSubject.php +++ b/src/mongo/ImpactedSubject.php @@ -69,7 +69,7 @@ public function __construct(array $resourceId, $operation, $storeName, $podName, $this->podName = $podName; $this->specTypes = $specTypes; - if ($stat instanceof \Tripod\ITripodStat) { + if ($stat instanceof ITripodStat) { $this->tripodStat = $stat; } } @@ -117,7 +117,7 @@ public function getStoreName() /** * Serialises the data as an array. * - * @return array + * @return array */ public function toArray(): array { @@ -146,7 +146,7 @@ public function update(): void /** * For mocking. */ - protected function getTripod(): \Tripod\Mongo\Driver + protected function getTripod(): Driver { return new Driver($this->getPodName(), $this->getStoreName(), [ 'readPreference' => ReadPreference::RP_PRIMARY, diff --git a/src/mongo/Labeller.php b/src/mongo/Labeller.php index eda5d0a0..ec101193 100644 --- a/src/mongo/Labeller.php +++ b/src/mongo/Labeller.php @@ -30,10 +30,6 @@ public function __construct() /** * If labeller can generate a qname for this uri, it will return it. Otherwise just returns the original uri. - * - * @param string|null $uri - * - * @return string|null */ public function uri_to_alias(?string $uri): ?string { @@ -47,10 +43,6 @@ public function uri_to_alias(?string $uri): ?string /** * If labeller can generate a uri for this qname, it will return it. Otherwise just returns the original qname. - * - * @param string|null $qName - * - * @return string|null */ public function qname_to_alias(?string $qName): ?string { @@ -63,10 +55,6 @@ public function qname_to_alias(?string $qName): ?string } /** - * @param string|null $qName - * - * @return string|null - * * @throws LabellerException */ public function qname_to_uri(?string $qName): ?string @@ -81,10 +69,6 @@ public function qname_to_uri(?string $qName): ?string // overrides the default behaviour of trying to return a ns even if the prefix is not registered - instead, throw exception /** - * @param string $ns - * - * @return string - * * @throws LabellerException */ public function get_prefix(string $ns): string diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index f349c497..d6556b64 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -248,10 +248,10 @@ protected function getContextAlias($context = null) /** * @param array $query - * @param string $type - * @param Collection|null $collection - * @param array $includeProperties - * @param int $cursorSize + * @param string $type + * @param Collection|null $collection + * @param array $includeProperties + * @param int $cursorSize * * @return MongoGraph */ @@ -345,7 +345,7 @@ protected function fetchGraph(array $query, $type, $collection = null, $includeP /** * Expands an RDF sequence into proper tripod join clauses. * - * @param array $joins + * @param array $joins * @param array $source */ protected function expandSequence(&$joins, array $source) @@ -377,10 +377,10 @@ protected function expandSequence(&$joins, array $source) * Adds an _id object (or array of _id objects) to the target document's impact index. * * @param array &$target - * @param mixed $buildImpactIndex + * @param mixed $buildImpactIndex + * @param array $id * * @throws \InvalidArgumentException - * @param array $id */ protected function addIdToImpactIndex(array $id, array &$target, $buildImpactIndex = true) { diff --git a/src/mongo/base/JobBase.php b/src/mongo/base/JobBase.php index 8b82ea4b..e14da8b3 100644 --- a/src/mongo/base/JobBase.php +++ b/src/mongo/base/JobBase.php @@ -253,10 +253,10 @@ protected function ensureConfig() } /** - * @param string $queueName Queue name - * @param string $class Class name - * @param array $data Job arguments - * @param int $retryAttempts If queue fails, retry x times before throwing an exception + * @param string $queueName Queue name + * @param string $class Class name + * @param array $data Job arguments + * @param int $retryAttempts If queue fails, retry x times before throwing an exception * * @return string A tracking token for the submitted job * diff --git a/src/mongo/delegates/SearchDocuments.php b/src/mongo/delegates/SearchDocuments.php index e39674f6..123ee4e7 100644 --- a/src/mongo/delegates/SearchDocuments.php +++ b/src/mongo/delegates/SearchDocuments.php @@ -35,7 +35,6 @@ public function __construct($storeName, Collection $collection, $defaultContext, * @param string $resource * @param string $context * - * * @throws \Exception */ public function generateSearchDocumentBasedOnSpecId(string $specId, $resource, $context): ?array @@ -126,7 +125,6 @@ public function generateSearchDocumentBasedOnSpecId(string $specId, $resource, $ * @param string $resource * @param string $context * - * * @throws \Exception */ public function generateSearchDocumentsBasedOnRdfTypes(array $rdfTypes, $resource, $context): array @@ -287,7 +285,7 @@ protected function getSearchDocumentSpecification($specId) /** * @param array $field - * @param array $values + * @param array $values */ private function addValuesToTarget(array $values, array $field, array &$target): void { diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 6a6d11b8..3e3fbb84 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -156,6 +156,7 @@ public function generateAndIndexSearchDocuments($resourceUri, $context, $podName * @param string|null $resourceUri * @param string|null $context * @param string|null $queueName + * * @return array|null Will return an array with a count and group id, if $queueName is sent and $resourceUri is null */ public function generateSearchDocuments( @@ -289,7 +290,7 @@ protected function getSearchProvider() /** * @param string $context */ - protected function getSearchDocumentGenerator(Collection $collection, $context): \Tripod\Mongo\SearchDocuments + protected function getSearchDocumentGenerator(Collection $collection, $context): SearchDocuments { return new SearchDocuments($this->storeName, $collection, $context, $this->tripod->getStat()); } diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index 65f4c531..8caf845d 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -8,6 +8,7 @@ use MongoDB\BSON\UTCDateTime; use MongoDB\Collection; +use MongoDB\Driver\CursorInterface; use MongoDB\Driver\ReadPreference; use Tripod\Exceptions\LabellerException; use Tripod\ITripodStat; @@ -230,12 +231,12 @@ public function getOperationType(): string /** * Query the tables collection and return the results. * - * @param int $offset - * @param int $limit + * @param int $offset + * @param int $limit * @param array $options Table query options - * - * @return array * @param array $filter + * + * @return array */ public function getTableRows( string $tableSpecId, @@ -299,9 +300,9 @@ public function getTableRows( /** * Returns the distinct values for a table column, optionally filtered by query. * + * @param array $filter * * @return array - * @param array $filter */ public function distinct(string $tableSpecId, string $fieldName, array $filter = []): array { @@ -419,7 +420,6 @@ public function generateTableRowsForType($rdfType, $subject = null, $context = n * @param string|null $resource * @param string|null $context * @param string|null $queueName Queue for background bulk generation - * @return array */ public function generateTableRows(string $tableType, $resource = null, $context = null, $queueName = null): ?array { @@ -546,8 +546,8 @@ public function generateTableRows(string $tableType, $resource = null, $context /** * Count the number of documents in the spec that match $filters. * - * @param string $tableSpec Table spec ID - * @param array $filters Query filters to get count on + * @param string $tableSpec Table spec ID + * @param array $filters Query filters to get count on * * @return int */ @@ -642,7 +642,7 @@ protected function generateTableRowsForResource($resource, $context = null, $spe * If an exception in thrown because a field is too large to index, the field is * truncated and the save is retried. * - * @param array|array $generatedRow the rows to save + * @param array|array $generatedRow the rows to save * * @throws \Exception */ @@ -714,7 +714,7 @@ protected function truncateFields(Collection $collection, array &$generatedRow) /** * @param array $spec The table spec - * @param mixed[] $dest The table row document to save + * @param mixed[] $dest The table row document to save */ protected function doComputedFields(array $spec, array &$dest) { @@ -733,9 +733,9 @@ protected function doComputedFields(array $spec, array &$dest) } /** - * @param string $function A defined computed value function - * @param array $spec The computed field spec - * @param array $dest The table row document to save + * @param string $function A defined computed value function + * @param array $spec The computed field spec + * @param array $dest The table row document to save * * @return mixed The computed value */ @@ -764,10 +764,11 @@ protected function getComputedValue(string $function, array $spec, array &$dest) } /** + * @param array $equation + * * @return float|int|null * * @throws \InvalidArgumentException - * @param array $equation */ protected function computeArithmeticValue(array $equation, array &$dest) { @@ -824,7 +825,7 @@ protected function computeArithmeticValue(array $equation, array &$dest) /** * @param array $replaceSpec The replace value spec - * @param array $dest The table row document to save + * @param array $dest The table row document to save * * @return mixed */ @@ -850,7 +851,7 @@ protected function generateReplaceValue(array $replaceSpec, array &$dest) /** * @param array $conditionalSpec The conditional spec - * @param array $dest The table row document to save + * @param array $dest The table row document to save * * @return mixed The computed value */ @@ -896,9 +897,9 @@ protected function generateConditionalValue(array $conditionalSpec, array &$dest } /** - * @param mixed $value The value to replace, if it contains a variable - * @param array $dest The table row document to save - * @param string|null $setType Force the return to be set to specified type + * @param mixed $value The value to replace, if it contains a variable + * @param array $dest The table row document to save + * @param string|null $setType Force the return to be set to specified type * * @return mixed */ @@ -1084,7 +1085,7 @@ protected function addFields(array $source, array $spec, array &$dest) } } - // Otherwise apply a modifier + // Otherwise apply a modifier } elseif (isset($dest[$f['fieldName']])) { $dest[$f['fieldName']] = $this->applyModifier($function, $dest[$f['fieldName']], $functionOptions); } @@ -1119,7 +1120,7 @@ protected function addFields(array $source, array $spec, array &$dest) * * @param array $source * @param array $f - * @param string $predicate + * @param string $predicate */ protected function generateValues(array $source, array $f, $predicate, array &$dest) { @@ -1345,8 +1346,8 @@ protected function getCollectionForTableSpec($tableSpecId) * join - pass in "glue":" " to specify what to glue multiple values together with * date - no options. * - * @param string $modifier - * @param string $value + * @param string $modifier + * @param string $value * @param array $options * * @return mixed @@ -1388,8 +1389,8 @@ private function applyModifier($modifier, $value, array $options = []) /** * Lowercase a value, casting to string first. + * * @param string|\Stringable $value - * @return string */ private function strtolower($value): string { @@ -1399,7 +1400,7 @@ private function strtolower($value): string /** * Apply a regex to the RDF property value defined in $value. * - * @param mixed $regex + * @param mixed $regex * @param array $value * * @return int diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 5a2eef61..d02bfc2b 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -147,7 +147,6 @@ public function __construct(Driver $tripod, $opts = []) * @param string|null $context * @param string|null $description * - * * @throws \Exception */ public function saveChanges( @@ -268,7 +267,6 @@ public function getLockedDocuments($fromDateTime = null, $tillDateTime = null): * @param string $transaction_id * @param string $reason * - * * @throws \Exception, if something goes wrong when unlocking documents, or creating audit entries */ public function removeInertLocks($transaction_id, $reason): bool @@ -575,7 +573,6 @@ protected function storeChanges(ChangeSet $cs, $contextAlias) * @param string $transaction_id id of the transaction * @param array $originalCBDs containing the original CBDS * - * * @throws \Exception */ protected function rollbackTransaction(string $transaction_id, $originalCBDs, \Exception $exception): bool @@ -643,7 +640,8 @@ protected function getUniqId(): string * @param string $contextAlias * @param string $transaction_id * - * @return array + * @return array + * * @throws \Exception */ protected function applyChangeSet(ChangeSet $cs, array $originalCBDs, $contextAlias, $transaction_id) @@ -997,7 +995,6 @@ protected function lockAllDocuments($subjectsOfChange, $transaction_id, $context * * @param string $transaction_id id for this transaction * - * * @throws \Exception is thrown if for any reason the update to mongo fails */ protected function unlockAllDocuments(string $transaction_id): bool @@ -1114,7 +1111,7 @@ protected function getAuditManualRollbacksCollection() return $this->config->getCollectionForManualRollbackAudit($this->storeName); } - protected function generateIdForNewMongoDocument(): \MongoDB\BSON\ObjectId + protected function generateIdForNewMongoDocument(): ObjectId { return new ObjectId(); } @@ -1129,6 +1126,7 @@ protected function getMongoDate() /** * Saves a transaction. + * * @param array $transaction */ protected function applyTransaction(array $transaction) @@ -1159,7 +1157,7 @@ protected function applyTransaction(array $transaction) * * @param array $data */ - protected function getTripod(array $data): \Tripod\Mongo\Driver + protected function getTripod(array $data): Driver { return new Driver( $data['collection'], @@ -1256,7 +1254,6 @@ private function getAdditionsRemovalsGroupedByNsPredicate(ChangeSet $cs, $change * @param mixed $changeUri * @param mixed $changePredicate * - * * @throws Exception */ private function getChangesGroupedByNsPredicate(ChangeSet $cs, $changeUri, $changePredicate): array @@ -1291,9 +1288,9 @@ private function getChangesGroupedByNsPredicate(ChangeSet $cs, $changeUri, $chan /** * Helper method to add operator to a set of existing changes ready to be sent to Mongo. * - * @param array $changes - * @param mixed $operator - * @param array|array $kvp + * @param array $changes + * @param mixed $operator + * @param array|array $kvp */ private function addOperatorToChange(array &$changes, string $operator, array $kvp): void { diff --git a/src/mongo/delegates/Views.php b/src/mongo/delegates/Views.php index e471beeb..3f963451 100644 --- a/src/mongo/delegates/Views.php +++ b/src/mongo/delegates/Views.php @@ -176,6 +176,7 @@ public function getViews(array $filter, $viewType) * * @param string|null $resource * @param string|null $context + * * @return MongoGraph */ public function getViewForResource($resource, string $viewType, $context = null) @@ -331,7 +332,6 @@ public function generateViews($resources, $context = null): void * @param string|null $resource * @param string|null $context * - * * @throws \Exception */ public function generateViewsForResourcesOfType($rdfType, $resource = null, $context = null): void @@ -400,7 +400,6 @@ public function deleteViewsByViewId(string $viewId, $timestamp = null) * @param string|null $context * @param string|null $queueName Queue for background bulk generation * - * @return array * @throws ViewException */ public function generateView(string $viewId, $resource = null, $context = null, $queueName = null): ?array @@ -529,8 +528,8 @@ public function generateView(string $viewId, $resource = null, $context = null, /** * Count the number of documents in the spec that match $filters. * - * @param string $viewSpec View spec ID - * @param array $filters Query filters to get count on + * @param string $viewSpec View spec ID + * @param array $filters Query filters to get count on * * @return int */ @@ -544,12 +543,12 @@ public function count($viewSpec, array $filters = []) /** * Joins data to $dest from $source according to specification in $joins, or queries DB if data is not available in $source. * - * @param bool $buildImpactIndex - * @param mixed $source - * @param mixed $joins + * @param bool $buildImpactIndex + * @param mixed $source + * @param mixed $joins * @param array $dest - * @param mixed $from - * @param mixed $contextAlias + * @param mixed $from + * @param mixed $contextAlias */ protected function doJoins(array $source, $joins, array &$dest, $from, $contextAlias, $buildImpactIndex = true) { @@ -667,9 +666,9 @@ protected function matchesFilter($linkMatchType, $linkMatchValue, $filterType, $ * Returns a document with properties extracted from $source, according to $viewSpec. Useful for partial representations * of CBDs in a view. * - * @param mixed $source + * @param mixed $source * @param array $viewSpec - * @param mixed $from + * @param mixed $from */ protected function extractProperties(array $source, array $viewSpec, $from): array { diff --git a/src/mongo/jobs/ApplyOperation.php b/src/mongo/jobs/ApplyOperation.php index 1f52ddbb..e24d3224 100644 --- a/src/mongo/jobs/ApplyOperation.php +++ b/src/mongo/jobs/ApplyOperation.php @@ -139,7 +139,7 @@ protected function getStatFailureIncrementKey(): string * * @param array $args */ - protected function createImpactedSubject(array $args): \Tripod\Mongo\ImpactedSubject + protected function createImpactedSubject(array $args): ImpactedSubject { return new ImpactedSubject( $args['resourceId'], @@ -156,7 +156,7 @@ protected function createImpactedSubject(array $args): \Tripod\Mongo\ImpactedSub * @param string $storeName Tripod store (database) name * @param ObjectId|string $trackingKey JobGroup ID */ - protected function getJobGroup($storeName, $trackingKey): \Tripod\Mongo\JobGroup + protected function getJobGroup($storeName, $trackingKey): JobGroup { return new JobGroup($storeName, $trackingKey); } @@ -164,7 +164,7 @@ protected function getJobGroup($storeName, $trackingKey): \Tripod\Mongo\JobGroup /** * For mocking. */ - protected function getSearchProvider(Driver $tripod): \Tripod\Mongo\MongoSearchProvider + protected function getSearchProvider(Driver $tripod): MongoSearchProvider { return new MongoSearchProvider($tripod); } diff --git a/src/mongo/jobs/EnsureIndexes.php b/src/mongo/jobs/EnsureIndexes.php index 915e7407..40feb8ad 100644 --- a/src/mongo/jobs/EnsureIndexes.php +++ b/src/mongo/jobs/EnsureIndexes.php @@ -76,7 +76,7 @@ protected function getStatFailureIncrementKey(): string return MONGO_QUEUE_ENSURE_INDEXES_FAIL; } - protected function getIndexUtils(): \Tripod\Mongo\IndexUtils + protected function getIndexUtils(): IndexUtils { return new IndexUtils(); } diff --git a/src/mongo/providers/MongoSearchProvider.php b/src/mongo/providers/MongoSearchProvider.php index f11e39ca..2064567e 100644 --- a/src/mongo/providers/MongoSearchProvider.php +++ b/src/mongo/providers/MongoSearchProvider.php @@ -44,7 +44,6 @@ public function __construct(Driver $tripod) * * @param array $document the document to index * - * * @throws SearchException if there was an error indexing the document */ public function indexDocument($document): void @@ -73,7 +72,6 @@ public function indexDocument($document): void * @param string $context * @param array|string|null $specId * - * * @throws SearchException if there was an error removing the document */ public function deleteDocument($resource, $context, $specId = []): void @@ -356,8 +354,8 @@ public function deleteSearchDocumentsByTypeId($typeId, $timestamp = null) /** * Count the number of documents in the spec that match $filters. * - * @param string $searchSpec Search spec ID - * @param array $filters Query filters to get count on + * @param string $searchSpec Search spec ID + * @param array $filters Query filters to get count on * * @return int */ diff --git a/src/mongo/serializers/NQuadSerializer.php b/src/mongo/serializers/NQuadSerializer.php index 954cba5d..61e58784 100644 --- a/src/mongo/serializers/NQuadSerializer.php +++ b/src/mongo/serializers/NQuadSerializer.php @@ -71,8 +71,7 @@ public function getTerm($v) } /** - * @param array $index - * @param string $context + * @param array $index */ public function getSerializedIndex($index, ?string $context): string { @@ -179,51 +178,51 @@ public function getEscapedChar($c, $no) if ($no < 9) { return '\u' . sprintf('%04X', $no); } - // #x0-#x8 (0-8) + // #x0-#x8 (0-8) if ($no == 9) { return '\t'; } - // #x9 (9) + // #x9 (9) if ($no == 10) { return '\n'; } - // #xA (10) + // #xA (10) if ($no < 13) { return '\u' . sprintf('%04X', $no); } - // #xB-#xC (11-12) + // #xB-#xC (11-12) if ($no == 13) { return '\r'; } - // #xD (13) + // #xD (13) if ($no < 32) { return '\u' . sprintf('%04X', $no); } - // #xE-#x1F (14-31) + // #xE-#x1F (14-31) if ($no < 34) { return $c; } - // #x20-#x21 (32-33) + // #x20-#x21 (32-33) if ($no == 34) { return '\"'; } - // #x22 (34) + // #x22 (34) if ($no < 92) { return $c; } - // #x23-#x5B (35-91) + // #x23-#x5B (35-91) if ($no == 92) { return '\\\\'; } - // #x5C (92) + // #x5C (92) if ($no < 127) { return $c; } - // #x5D-#x7E (93-126) + // #x5D-#x7E (93-126) if ($no < 65536) { return '\u' . sprintf('%04X', $no); } - // #x7F-#xFFFF (128-65535) + // #x7F-#xFFFF (128-65535) if ($no < 1114112) { return '\U' . sprintf('%08X', $no); } // #x10000-#x10FFFF (65536-1114111) diff --git a/src/mongo/util/DateUtil.php b/src/mongo/util/DateUtil.php index 9d5ded69..2eaf5d75 100644 --- a/src/mongo/util/DateUtil.php +++ b/src/mongo/util/DateUtil.php @@ -15,7 +15,7 @@ class DateUtil * * @param float|int|null $milliseconds - time in milliseconds since the epoch */ - public static function getMongoDate($milliseconds = null): \MongoDB\BSON\UTCDateTime + public static function getMongoDate($milliseconds = null): UTCDateTime { if (is_null($milliseconds)) { $milliseconds = floor(microtime(true) * 1000); diff --git a/src/mongo/util/IndexUtils.php b/src/mongo/util/IndexUtils.php index 84796cd9..3103c608 100644 --- a/src/mongo/util/IndexUtils.php +++ b/src/mongo/util/IndexUtils.php @@ -161,7 +161,7 @@ public function ensureIndexes($reindex = false, $storeName = null, $background = * * @return \Tripod\Mongo\Config */ - protected function getConfig(): \Tripod\Mongo\IConfigInstance + protected function getConfig(): IConfigInstance { return Config::getInstance(); } diff --git a/src/mongo/util/TriplesUtil.php b/src/mongo/util/TriplesUtil.php index 6152c258..9bb29a11 100644 --- a/src/mongo/util/TriplesUtil.php +++ b/src/mongo/util/TriplesUtil.php @@ -241,8 +241,9 @@ private function isUri($object) } /** + * @param bool|list $parts + * * @return string - * @param list|bool $parts */ private function extract_object(array $parts) { diff --git a/test/bootstrap.php b/test/bootstrap.php index 87b0558f..14962e0f 100644 --- a/test/bootstrap.php +++ b/test/bootstrap.php @@ -6,9 +6,7 @@ use Tripod\Mongo\Jobs\JobBase; require_once __DIR__ . '/../vendor/autoload.php'; - require_once __DIR__ . '/../src/tripod.inc.php'; - require_once __DIR__ . '/stubs.php'; // Mongo Config For Main DB diff --git a/test/stubs.php b/test/stubs.php index 0ad9c8d4..6e5bc4a3 100644 --- a/test/stubs.php +++ b/test/stubs.php @@ -1,12 +1,11 @@ getMockBuilder(IndexUtils::class) ->onlyMethods(['getConfig']) @@ -312,7 +312,7 @@ protected function createMockIndexUtils($mockConfig): \PHPUnit\Framework\MockObj * * @return Collection&MockObject mock Collection object */ - protected function createMockCollection(): \PHPUnit\Framework\MockObject\MockObject + protected function createMockCollection(): MockObject { return $this->getMockBuilder(MongoDB\Collection::class) ->onlyMethods(['createIndex', 'dropIndexes']) @@ -329,7 +329,7 @@ protected function createMockCollection(): \PHPUnit\Framework\MockObject\MockObj * * @return MockObject&TripodTestConfig mock Config object */ - protected function createMockConfig(): \PHPUnit\Framework\MockObject\MockObject + protected function createMockConfig(): MockObject { return $this->getMockBuilder(TripodTestConfig::class) ->onlyMethods([ @@ -457,7 +457,7 @@ protected function getCollectionForCBDShouldNeverBeCalled($mockConfig) * * @param Collection&MockObject $mockCollection mock Collection object * @param bool $background create indexes in the background - * @param array $indexOptions + * @param array $indexOptions */ protected function oneCustomAndThreeInternalTripodCBDIndexesShouldBeCreated($mockCollection, $background = true, array $indexOptions = []) { @@ -541,8 +541,8 @@ protected function threeInternalTripodSearchDocIndexesShouldBeCreated($mockColle * This is a minimal config used to assert what should happen when ensuring * indexes for a CBD collection. * - * @param MockObject&TripodTestConfig $mockConfig mock Config object - * @param array $indexOptions + * @param MockObject&TripodTestConfig $mockConfig mock Config object + * @param array $indexOptions */ protected function setConfigForCBDIndexes($mockConfig, array $indexOptions = []) { diff --git a/test/unit/mongo/MongoTransactionLogTest.php b/test/unit/mongo/MongoTransactionLogTest.php index aa596124..125323a1 100644 --- a/test/unit/mongo/MongoTransactionLogTest.php +++ b/test/unit/mongo/MongoTransactionLogTest.php @@ -730,6 +730,7 @@ public function testCreateNewTransactionThrowsExceptionIfInsertFails(): void * @param string $startTime * @param string $endTime * @param int $_version + * * @return array */ protected function buildTransactionDocument($id, $subjectOfChange, $startTime, $endTime, $_version): array diff --git a/test/unit/mongo/MongoTripodConfigUnitTest.php b/test/unit/mongo/MongoTripodConfigUnitTest.php index c48c3a97..12672552 100644 --- a/test/unit/mongo/MongoTripodConfigUnitTest.php +++ b/test/unit/mongo/MongoTripodConfigUnitTest.php @@ -1647,7 +1647,7 @@ public function testMongoConnectionNoExceptions(): void $mockConfig->expects($this->exactly(1)) ->method('getMongoClient') ->with('mongodb://mongodb:27017/', ['connectTimeoutMS' => 20000]) - ->willReturnCallback(function (): \MongoDB\Client { + ->willReturnCallback(function (): Client { return new Client(); }); $mockConfig->getDatabase('tripod_php_testing', 'rs1', ReadPreference::RP_SECONDARY_PREFERRED); @@ -1680,10 +1680,10 @@ public function testMongoConnectionNoExceptionThrownWhenConnectionThrowsSomeExce $mockConfig->expects($this->exactly(5)) ->method('getMongoClient') ->with('mongodb://mongodb:27017/', ['connectTimeoutMS' => 20000])->willReturnOnConsecutiveCalls($this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->returnCallback( - function (): \MongoDB\Client { - return new Client(); - } - )); + function (): Client { + return new Client(); + } + )); $mockConfig->getDatabase('tripod_php_testing', 'rs1', ReadPreference::RP_SECONDARY_PREFERRED); $mockConfig->getCollectionForCBD('tripod_php_testing', 'CBD_testing', ReadPreference::RP_SECONDARY_PREFERRED); diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index b7cdff9a..3ba368c5 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -3,7 +3,6 @@ declare(strict_types=1); use MongoDB\BSON\Binary; -use MongoDB\BSON\Javascript; use MongoDB\BSON\ObjectId; use MongoDB\BSON\Regex; use MongoDB\BSON\UTCDateTime; diff --git a/test/unit/mongo/MongoTripodSearchDocumentsTest.php b/test/unit/mongo/MongoTripodSearchDocumentsTest.php index 2383847b..4c5c821d 100644 --- a/test/unit/mongo/MongoTripodSearchDocumentsTest.php +++ b/test/unit/mongo/MongoTripodSearchDocumentsTest.php @@ -666,7 +666,7 @@ public function testDeleteResourceCreatesImpactedSubjects(): void $this->assertEquals(0, $collection->count($impactQuery)); } - protected function getSearchDocuments(Driver $tripod): \Tripod\Mongo\SearchDocuments + protected function getSearchDocuments(Driver $tripod): SearchDocuments { return new SearchDocuments( $tripod->getStoreName(), diff --git a/test/unit/mongo/MongoTripodTestBase.php b/test/unit/mongo/MongoTripodTestBase.php index 352e80ee..fb61a8f2 100644 --- a/test/unit/mongo/MongoTripodTestBase.php +++ b/test/unit/mongo/MongoTripodTestBase.php @@ -112,9 +112,6 @@ protected function addDocument($doc, $toTransactionLog = false): InsertOneResult )->insertOne($doc, ['w' => 1]); } - /** - * @return Collection - */ protected function getTlogCollection(): Collection { $config = Config::getInstance(); @@ -123,9 +120,6 @@ protected function getTlogCollection(): Collection return $config->getTransactionLogDatabase()->selectCollection($tLogConfig['collection']); } - /** - * @return Collection - */ protected function getTripodCollection(Driver $tripod): Collection { $config = Config::getInstance(); @@ -141,9 +135,6 @@ protected function getTripodCollection(Driver $tripod): Collection /** * @param array|string $_id * @param Collection|IDriver|null $collection - * @param bool $fromTransactionLog - * - * @return array|null */ protected function getDocument($_id, $collection = null, bool $fromTransactionLog = false): ?array { @@ -284,15 +275,14 @@ protected function assertDocumentDoesNotHaveProperty(array $_id, string $propert $doc = $this->getDocument($_id, $tripod, $fromTransactionLog); if ($doc === null) { $this->assertNull($doc); + return; // if document doesn't exist then it doesn't have the property, so assertion is successful } $this->assertArrayNotHasKey($property, $doc, 'Document for ' . var_export($_id, true) . sprintf(' should not have property [%s], but propert was found', $property)); } /** - * @param array $_id * @param Driver|null $tripod - * @param bool $fromTransactionLog */ protected function assertDocumentExists(array $_id, $tripod = null, bool $fromTransactionLog = false): void { @@ -302,9 +292,7 @@ protected function assertDocumentExists(array $_id, $tripod = null, bool $fromTr } /** - * @param array $_id * @param Driver|null $tripod - * @param bool $useTransactionTripod */ protected function assertDocumentHasBeenDeleted(array $_id, $tripod = null, bool $useTransactionTripod = false): void { @@ -392,7 +380,7 @@ protected function getMockStat($host, $port, $prefix = '', array $mockedMethods } /** - * @return array|array> + * @return array|class-string> */ protected function getStatsDConfig(): array { From 22c5e0f4e516b70aeea463a86ccd5aee721c2445 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 14:30:08 +0000 Subject: [PATCH 14/56] Format tests --- test/unit/mongo/DateUtilTest.php | 6 +- test/unit/mongo/MongoTripodConfigUnitTest.php | 45 ++++++----- test/unit/mongo/MongoTripodDriverTest.php | 40 ++++++--- .../mongo/MongoTripodSearchDocumentsTest.php | 8 +- test/unit/mongo/MongoTripodTablesTest.php | 3 +- test/unit/mongo/MongoTripodViewsTest.php | 81 ++++++++++++++----- test/unit/mongo/TriplesUtilTest.php | 6 +- 7 files changed, 129 insertions(+), 60 deletions(-) diff --git a/test/unit/mongo/DateUtilTest.php b/test/unit/mongo/DateUtilTest.php index 0fef2ef1..09c77b45 100644 --- a/test/unit/mongo/DateUtilTest.php +++ b/test/unit/mongo/DateUtilTest.php @@ -15,7 +15,8 @@ public function testGetMongoDateWithNoParam(): void $_id = [ 'r' => 'http://talisaspire.com/resources/testEtag' . microtime(false), - 'c' => 'http://talisaspire.com/']; + 'c' => 'http://talisaspire.com/', + ]; $doc = [ '_id' => $_id, 'dct:title' => ['l' => 'etag'], @@ -41,7 +42,8 @@ public function testGetMongoDateWithParam(): void $_id = [ 'r' => 'http://talisaspire.com/resources/testEtag' . microtime(false), - 'c' => 'http://talisaspire.com/']; + 'c' => 'http://talisaspire.com/', + ]; $doc = [ '_id' => $_id, 'dct:title' => ['l' => 'etag'], diff --git a/test/unit/mongo/MongoTripodConfigUnitTest.php b/test/unit/mongo/MongoTripodConfigUnitTest.php index 12672552..1d54f9be 100644 --- a/test/unit/mongo/MongoTripodConfigUnitTest.php +++ b/test/unit/mongo/MongoTripodConfigUnitTest.php @@ -108,7 +108,8 @@ public function testCompoundIndexAllArraysThrowsException(): void 'indexes' => [ 'IllegalCompoundIndex' => [ 'rdf:type.value' => 1, - 'dct:subject.value' => 1], + 'dct:subject.value' => 1, + ], ], ], ], @@ -272,8 +273,7 @@ public function testViewSpecCountWithoutTTLThrowsException(): void 'tripod_php_testing' => [ 'data_source' => 'db', 'pods' => [ - 'CBD_testing' => [ - ], + 'CBD_testing' => [], ], ], ]; @@ -312,8 +312,7 @@ public function testViewSpecCountNestedInJoinWithoutTTLThrowsException(): void 'tripod_php_testing' => [ 'data_source' => 'db', 'pods' => [ - 'CBD_testing' => [ - ], + 'CBD_testing' => [], ], ], ]; @@ -355,8 +354,7 @@ public function testTableSpecNestedCountWithoutPropertyThrowsException(): void 'tripod_php_testing' => [ 'data_source' => 'db', 'pods' => [ - 'CBD_testing' => [ - ], + 'CBD_testing' => [], ], ], ]; @@ -630,8 +628,7 @@ public function testConfigWithoutDefaultNamespaceThrowsException(): void 'tripod_php_testing' => [ 'data_source' => 'db', 'pods' => [ - 'CBD_testing' => [ - ], + 'CBD_testing' => [], ], ], ]; @@ -709,15 +706,13 @@ public function testGetReplicaSetName(): void 'tripod_php_testing' => [ 'data_source' => 'rs1', 'pods' => [ - 'CBD_testing' => [ - ], + 'CBD_testing' => [], ], ], 'testing_2' => [ 'data_source' => 'mongo1', 'pods' => [ - 'CBD_testing' => [ - ], + 'CBD_testing' => [], ], ], ]; @@ -1078,8 +1073,12 @@ public function testDataLoadedInConfiguredDataSource(): void $collectionsForDataSource = []; $collectionsForDataSource['rs1'] = [ - VIEWS_COLLECTION, SEARCH_INDEX_COLLECTION, TABLE_ROWS_COLLECTION, 'CBD_testing', - AUDIT_MANUAL_ROLLBACKS_COLLECTION, LOCKS_COLLECTION, + VIEWS_COLLECTION, + SEARCH_INDEX_COLLECTION, + TABLE_ROWS_COLLECTION, + 'CBD_testing', + AUDIT_MANUAL_ROLLBACKS_COLLECTION, + LOCKS_COLLECTION, ]; $collectionsForDataSource['rs2'] = [VIEWS_COLLECTION, SEARCH_INDEX_COLLECTION, TABLE_ROWS_COLLECTION, 'CBD_testing_2', 'transaction_log']; @@ -1679,11 +1678,17 @@ public function testMongoConnectionNoExceptionThrownWhenConnectionThrowsSomeExce $mockConfig->loadConfig(json_decode(file_get_contents(__DIR__ . '/data/config.json'), true)); $mockConfig->expects($this->exactly(5)) ->method('getMongoClient') - ->with('mongodb://mongodb:27017/', ['connectTimeoutMS' => 20000])->willReturnOnConsecutiveCalls($this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->returnCallback( - function (): Client { - return new Client(); - } - )); + ->with('mongodb://mongodb:27017/', ['connectTimeoutMS' => 20000])->willReturnOnConsecutiveCalls( + $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), + $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), + $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), + $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), + $this->returnCallback( + function (): Client { + return new Client(); + } + ) + ); $mockConfig->getDatabase('tripod_php_testing', 'rs1', ReadPreference::RP_SECONDARY_PREFERRED); $mockConfig->getCollectionForCBD('tripod_php_testing', 'CBD_testing', ReadPreference::RP_SECONDARY_PREFERRED); diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index 3ba368c5..de08cd7d 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -79,7 +79,8 @@ public function testSelectMultiValue(): void [ '_id' => [ _ID_RESOURCE => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', - _ID_CONTEXT => 'http://talisaspire.com/'], + _ID_CONTEXT => 'http://talisaspire.com/', + ], 'dct:source' => [ 'http://life.ac.uk/resources/BFBC6A06-A8B0-DED8-53AA-8E80DB44CC53', 'http://life.ac.uk/resources/836E7CAD-63D2-63A0-B1CB-AA6A7E54A5C9', @@ -103,7 +104,8 @@ public function testSelectSingleValue(): void [ '_id' => [ _ID_RESOURCE => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', - _ID_CONTEXT => 'http://talisaspire.com/'], + _ID_CONTEXT => 'http://talisaspire.com/', + ], 'dct:subject' => 'http://talisaspire.com/disciplines/physics', ], ], @@ -696,8 +698,11 @@ public function testReadPreferencesOverMultipleSaves(): void $tripodMock = $this->getMockBuilder(TestTripod::class) ->onlyMethods(['getDataUpdater']) - ->setConstructorArgs(['CBD_testing', 'tripod_php_testing', - ['defaultContext' => 'http://talisaspire.com/', 'readPreference' => ReadPreference::RP_SECONDARY_PREFERRED]]) + ->setConstructorArgs([ + 'CBD_testing', + 'tripod_php_testing', + ['defaultContext' => 'http://talisaspire.com/', 'readPreference' => ReadPreference::RP_SECONDARY_PREFERRED], + ]) ->getMock(); $tripodUpdate = $this->getMockBuilder(Updates::class) @@ -1588,13 +1593,15 @@ public function testSelectSingleValueWithNamespaceContextQueryDoesntContainID(): [ '_id' => [ _ID_RESOURCE => 'baseData:1', - _ID_CONTEXT => 'baseData:DefaultGraph'], + _ID_CONTEXT => 'baseData:DefaultGraph', + ], 'rdf:type' => 'acorn:Work', ], [ '_id' => [ _ID_RESOURCE => 'baseData:2', - _ID_CONTEXT => 'baseData:DefaultGraph'], + _ID_CONTEXT => 'baseData:DefaultGraph', + ], 'rdf:type' => ['acorn:Work', 'acorn:Work2'], ], ], @@ -1615,7 +1622,8 @@ public function testSelectSingleValueWithNamespaceContextQueryDoesContainID(): v [ '_id' => [ _ID_RESOURCE => 'baseData:1', - _ID_CONTEXT => 'baseData:DefaultGraph'], + _ID_CONTEXT => 'baseData:DefaultGraph', + ], 'rdf:type' => 'acorn:Work', ], ], @@ -1643,15 +1651,18 @@ public function testSelectWithOperandWithNamespaceContextQueryContainsID(): void [ '_id' => [ _ID_RESOURCE => 'baseData:1', - _ID_CONTEXT => 'baseData:DefaultGraph'], + _ID_CONTEXT => 'baseData:DefaultGraph', + ], 'rdf:type' => 'acorn:Work', ], [ '_id' => [ _ID_RESOURCE => 'baseData:2', - _ID_CONTEXT => 'baseData:DefaultGraph'], + _ID_CONTEXT => 'baseData:DefaultGraph', + ], 'rdf:type' => ['acorn:Work', 'acorn:Work2'], - ]], + ], + ], ]; $actualResult = $this->tripod->select( ['_id' => ['$in' => [[_ID_RESOURCE => 'baseData:1'], [_ID_RESOURCE => 'baseData:2']]]], @@ -1676,13 +1687,15 @@ public function testSelectWithOperandWithNamespaceContextQueryDoesNotContainID() [ '_id' => [ _ID_RESOURCE => 'baseData:1', - _ID_CONTEXT => 'baseData:DefaultGraph'], + _ID_CONTEXT => 'baseData:DefaultGraph', + ], 'rdf:type' => 'acorn:Work', ], [ '_id' => [ _ID_RESOURCE => 'baseData:2', - _ID_CONTEXT => 'baseData:DefaultGraph'], + _ID_CONTEXT => 'baseData:DefaultGraph', + ], 'rdf:type' => ['acorn:Work', 'acorn:Work2'], ], ], @@ -2278,7 +2291,8 @@ public function testEtagIsMicrotimeFormat(): void $_id = [ 'r' => 'http://talisaspire.com/resources/testEtag', - 'c' => 'http://talisaspire.com/']; + 'c' => 'http://talisaspire.com/', + ]; $doc = [ '_id' => $_id, 'dct:title' => ['l' => 'etag'], diff --git a/test/unit/mongo/MongoTripodSearchDocumentsTest.php b/test/unit/mongo/MongoTripodSearchDocumentsTest.php index 4c5c821d..ba436de5 100644 --- a/test/unit/mongo/MongoTripodSearchDocumentsTest.php +++ b/test/unit/mongo/MongoTripodSearchDocumentsTest.php @@ -86,7 +86,10 @@ public function testGenerateSearchDocumentPreservesDiacritics(): void public function testGenerateSearchDocumentBasedOnSpecIdWithFieldNamePredicatesHavingNoValueInCollection(): void { - $searchSpecs = json_decode('{"_id":"i_search_resource","type":["bibo:Book"],"from":"CBD_testing","filter":[{"condition":{"dct:title.l":{"$exists":true}}}],"indices":[{"fieldName":"search_terms","predicates":["dct:title","dct:subject"]},{"fieldName":"other_terms","predicates":["rdf:type"]}],"fields":[{"fieldName":"result.title","predicates":["dct:title"],"limit":1},{"fieldName":"result.link","value":"link"},{"fieldName":"rdftype","predicates":["rdf:type"],"limit":1}],"joins":{"dct:creator":{"indices":[{"fieldName":"search_terms","predicates":["foaf:name"]}],"fields":[{"fieldName":"result.author","predicates":["foaf:name"],"limit":1}, {"fieldName":"result.role","predicates":["siocAccess:Role"], "limit":1}] } }}', true); + $searchSpecs = json_decode( + '{"_id":"i_search_resource","type":["bibo:Book"],"from":"CBD_testing","filter":[{"condition":{"dct:title.l":{"$exists":true}}}],"indices":[{"fieldName":"search_terms","predicates":["dct:title","dct:subject"]},{"fieldName":"other_terms","predicates":["rdf:type"]}],"fields":[{"fieldName":"result.title","predicates":["dct:title"],"limit":1},{"fieldName":"result.link","value":"link"},{"fieldName":"rdftype","predicates":["rdf:type"],"limit":1}],"joins":{"dct:creator":{"indices":[{"fieldName":"search_terms","predicates":["foaf:name"]}],"fields":[{"fieldName":"result.author","predicates":["foaf:name"],"limit":1}, {"fieldName":"result.role","predicates":["siocAccess:Role"], "limit":1}] } }}', + true + ); $mockSearchDocuments = $this->getMockBuilder(SearchDocuments::class) ->onlyMethods(['getSearchDocumentSpecification']) @@ -254,7 +257,8 @@ public function testRdfTypeTriggersGenerationOfSearchDocuments(): void $subjectsAndPredicatesOfChange = [ $labeller->uri_to_alias($uri) => [ - 'rdf:type', 'bibo:issn', + 'rdf:type', + 'bibo:issn', ], ]; diff --git a/test/unit/mongo/MongoTripodTablesTest.php b/test/unit/mongo/MongoTripodTablesTest.php index 81b7e3f4..31a41f6f 100644 --- a/test/unit/mongo/MongoTripodTablesTest.php +++ b/test/unit/mongo/MongoTripodTablesTest.php @@ -1051,7 +1051,8 @@ public function testRdfTypeTriggersGenerationOfTableRows(): void $subjectsAndPredicatesOfChange = [ $labeller->uri_to_alias($uri) => [ - 'rdf:type', 'bibo:issn', + 'rdf:type', + 'bibo:issn', ], ]; diff --git a/test/unit/mongo/MongoTripodViewsTest.php b/test/unit/mongo/MongoTripodViewsTest.php index 71420dbf..dcdf4cef 100644 --- a/test/unit/mongo/MongoTripodViewsTest.php +++ b/test/unit/mongo/MongoTripodViewsTest.php @@ -85,7 +85,8 @@ public function testGenerateView(): void '_id' => [ _ID_RESOURCE => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', _ID_CONTEXT => 'http://talisaspire.com/', - 'type' => 'v_resource_full'], + 'type' => 'v_resource_full', + ], 'value' => [ _GRAPHS => [ [ @@ -123,7 +124,11 @@ public function testGenerateView(): void ]; // get the view direct from mongo $collection = Config::getInstance()->getCollectionForView('tripod_php_testing', 'v_resource_full'); - $actualView = $collection->findOne(['_id' => ['r' => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', 'c' => 'http://talisaspire.com/', 'type' => 'v_resource_full']]); + $actualView = $collection->findOne(['_id' => [ + 'r' => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', + 'c' => 'http://talisaspire.com/', + 'type' => 'v_resource_full', + ]]); $this->assertEquals($expectedView['_id'], $actualView['_id']); $this->assertEquals($expectedView['value'], $actualView['value']); $this->assertInstanceOf(UTCDateTime::class, $actualView['_cts']); @@ -141,7 +146,8 @@ public function testGenerateViewWithFilterRemovesFilteredDataButKeepsResourcesIn '_id' => [ _ID_RESOURCE => 'http://talisaspire.com/resources/filter1', _ID_CONTEXT => 'http://talisaspire.com/', - 'type' => 'v_resource_filter1'], + 'type' => 'v_resource_filter1', + ], 'value' => [ _GRAPHS => [ // This Book should not be included in the view - we are filtering to include only chapters. @@ -192,7 +198,11 @@ public function testGenerateViewWithFilterRemovesFilteredDataButKeepsResourcesIn ]; // get the view direct from mongo $collection = Config::getInstance()->getCollectionForView('tripod_php_testing', 'v_resource_filter1'); - $actualView = $collection->findOne(['_id' => ['r' => 'http://talisaspire.com/resources/filter1', 'c' => 'http://talisaspire.com/', 'type' => 'v_resource_filter1']]); + $actualView = $collection->findOne(['_id' => [ + 'r' => 'http://talisaspire.com/resources/filter1', + 'c' => 'http://talisaspire.com/', + 'type' => 'v_resource_filter1', + ]]); $this->assertEquals($expectedView['_id'], $actualView['_id']); $this->assertEquals($expectedView['value'], $actualView['value']); $this->assertInstanceOf(UTCDateTime::class, $actualView['_cts']); @@ -210,7 +220,8 @@ public function testGenerateViewWithFilterOnLiteralValue(): void '_id' => [ _ID_RESOURCE => 'http://talisaspire.com/resources/filter1', _ID_CONTEXT => 'http://talisaspire.com/', - 'type' => 'v_resource_filter2'], + 'type' => 'v_resource_filter2', + ], 'value' => [ _GRAPHS => [ // http://talisaspire.com/works/filter2 has the matching literal @@ -273,7 +284,8 @@ public function testGenerateViewCorrectlyAfterUpdateAffectsFilter(): void '_id' => [ _ID_RESOURCE => 'http://talisaspire.com/resources/filter1', _ID_CONTEXT => 'http://talisaspire.com/', - 'type' => 'v_resource_filter1'], + 'type' => 'v_resource_filter1', + ], 'value' => [ _GRAPHS => [ // This Book should not be included in the view - we are filtering to include only chapters. @@ -344,7 +356,8 @@ public function testGenerateViewCorrectlyAfterUpdateAffectsFilter(): void '_id' => [ _ID_RESOURCE => 'http://talisaspire.com/resources/filter1', _ID_CONTEXT => 'http://talisaspire.com/', - 'type' => 'v_resource_filter1'], + 'type' => 'v_resource_filter1', + ], 'value' => [ _GRAPHS => [ // This work is now included as it's type has changed to Chapter @@ -393,7 +406,11 @@ public function testGenerateViewCorrectlyAfterUpdateAffectsFilter(): void ], ]; - $updatedView = $collection->findOne(['_id' => ['r' => 'http://talisaspire.com/resources/filter1', 'c' => 'http://talisaspire.com/', 'type' => 'v_resource_filter1']]); + $updatedView = $collection->findOne(['_id' => [ + 'r' => 'http://talisaspire.com/resources/filter1', + 'c' => 'http://talisaspire.com/', + 'type' => 'v_resource_filter1', + ]]); $this->assertEquals($expectedUpdatedView['_id'], $updatedView['_id']); $this->assertEquals($expectedUpdatedView['value'], $updatedView['value']); $this->assertInstanceOf(UTCDateTime::class, $updatedView['_cts']); @@ -411,7 +428,8 @@ public function testGenerateViewContainingRdfSequence(): void '_id' => [ _ID_RESOURCE => 'http://talisaspire.com/resources/filter1', _ID_CONTEXT => 'http://talisaspire.com/', - 'type' => 'v_resource_rdfsequence'], + 'type' => 'v_resource_rdfsequence', + ], 'value' => [ _GRAPHS => [ [ @@ -489,7 +507,8 @@ public function testGenerateViewWithTTL(): void '_id' => [ 'r' => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', 'c' => 'http://talisaspire.com/', - 'type' => 'v_resource_full_ttl'], + 'type' => 'v_resource_full_ttl', + ], 'value' => [ _GRAPHS => [ [ @@ -519,7 +538,11 @@ public function testGenerateViewWithTTL(): void ], ]; // get the view direct from mongo - $actualView = Config::getInstance()->getCollectionForView('tripod_php_testing', 'v_resource_full_ttl')->findOne(['_id' => ['r' => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', 'c' => 'http://talisaspire.com/', 'type' => 'v_resource_full_ttl']]); + $actualView = Config::getInstance()->getCollectionForView('tripod_php_testing', 'v_resource_full_ttl')->findOne(['_id' => [ + 'r' => 'http://talisaspire.com/resources/3SplCtWGPqEyXcDiyhHQpA', + 'c' => 'http://talisaspire.com/', + 'type' => 'v_resource_full_ttl', + ]]); $this->assertEquals($expectedView['_id'], $actualView['_id']); $this->assertEquals($expectedView['value'], $actualView['value']); $this->assertInstanceOf(UTCDateTime::class, $actualView['_cts']); @@ -699,7 +722,8 @@ public function testGenerateViewWithCountAggregate(): void '_id' => [ 'r' => 'http://talisaspire.com/works/4d101f63c10a6', 'c' => 'http://talisaspire.com/', - 'type' => 'v_counts'], + 'type' => 'v_counts', + ], 'value' => [ _GRAPHS => [ [ @@ -739,7 +763,11 @@ public function testGenerateViewWithCountAggregate(): void ], ]; - $actualView = Config::getInstance()->getCollectionForView('tripod_php_testing', 'v_counts')->findOne(['_id' => ['r' => 'http://talisaspire.com/works/4d101f63c10a6', 'c' => 'http://talisaspire.com/', 'type' => 'v_counts']]); + $actualView = Config::getInstance()->getCollectionForView('tripod_php_testing', 'v_counts')->findOne(['_id' => [ + 'r' => 'http://talisaspire.com/works/4d101f63c10a6', + 'c' => 'http://talisaspire.com/', + 'type' => 'v_counts', + ]]); $this->assertEquals($expectedView['_id'], $actualView['_id']); $this->assertEquals($expectedView['value'], $actualView['value']); $this->assertInstanceOf(UTCDateTime::class, $actualView['_cts']); @@ -974,7 +1002,9 @@ public function testDeletionOfResourceTriggersViewRegeneration(): void $subjectsAndPredicatesOfChange = [ $labeller->uri_to_alias($uri1) => [ - 'rdf:type', 'searchterms:topic', 'dct:isVersionOf', + 'rdf:type', + 'searchterms:topic', + 'dct:isVersionOf', ], ]; @@ -1123,13 +1153,15 @@ public function testDeletionOfResourceInImpactIndexTriggersViewRegeneration(): v $subjectsAndPredicatesOfChange = [ $labeller->uri_to_alias($uri2) => [ - 'rdf:type', 'dct:subject', + 'rdf:type', + 'dct:subject', ], ]; $mockTripod = $this->getMockBuilder(Driver::class) ->onlyMethods([ - 'getDataUpdater', 'getComposite', + 'getDataUpdater', + 'getComposite', ]) ->setConstructorArgs([ 'CBD_testing', @@ -1303,7 +1335,8 @@ public function testUpdateOfResourceInImpactIndexTriggersViewRegeneration(): voi $mockTripod = $this->getMockBuilder(Driver::class) ->onlyMethods([ - 'getDataUpdater', 'getComposite', + 'getDataUpdater', + 'getComposite', ]) ->setConstructorArgs([ 'CBD_testing', @@ -1479,7 +1512,8 @@ public function testUpdateOfResourceTriggersViewRegeneration(): void $mockTripod = $this->getMockBuilder(Driver::class) ->onlyMethods([ - 'getDataUpdater', 'getComposite', + 'getDataUpdater', + 'getComposite', ]) ->setConstructorArgs([ 'CBD_testing', @@ -1645,7 +1679,8 @@ public function testResourceUpdateNotCoveredBySpecStillTriggersOperations(): voi $mockTripod = $this->getMockBuilder(Driver::class) ->onlyMethods([ - 'getDataUpdater', 'getComposite', + 'getDataUpdater', + 'getComposite', ]) ->setConstructorArgs([ 'CBD_testing', @@ -2071,7 +2106,13 @@ public function testCursorNoExceptionThrownWhenCursorThrowsSomeExceptions(): voi ->getMock(); $mockCursor->expects($this->exactly(5)) - ->method('rewind')->willReturnOnConsecutiveCalls($this->throwException(new Exception('Exception thrown when cursoring to Mongo')), $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), $this->returnValue($mockCursor)); + ->method('rewind')->willReturnOnConsecutiveCalls( + $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), + $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), + $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), + $this->throwException(new Exception('Exception thrown when cursoring to Mongo')), + $this->returnValue($mockCursor) + ); $mockViewColl->expects($this->once())->method('find')->willReturn($mockCursor); diff --git a/test/unit/mongo/TriplesUtilTest.php b/test/unit/mongo/TriplesUtilTest.php index b83fffa1..44d685fb 100644 --- a/test/unit/mongo/TriplesUtilTest.php +++ b/test/unit/mongo/TriplesUtilTest.php @@ -20,9 +20,11 @@ public function testGetTArrayAbout(): void '_id' => ['r' => 'http://serials.talisaspire.com/issn/0893-0465', 'c' => 'http://talisaspire.com/'], 'foaf:page' => [ [ - 'u' => 'http://www.ingentaconnect.com/content/bpl/ciso'], + 'u' => 'http://www.ingentaconnect.com/content/bpl/ciso', + ], [ - 'u' => 'http://onlinelibrary.wiley.com/journal/10.1111/(ISSN)1548-744X'], + 'u' => 'http://onlinelibrary.wiley.com/journal/10.1111/(ISSN)1548-744X', + ], ], 'rdf:type' => [ 'u' => 'bibo:Journal', From 727c2433f5dbad5d8a7362117b66e7919d7de355 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 27 Feb 2026 14:30:21 +0000 Subject: [PATCH 15/56] Format scripts --- scripts/mongo/common.inc.php | 6 ++---- scripts/mongo/createSearchDocuments.php | 3 ++- scripts/mongo/createTables.php | 3 ++- scripts/mongo/createViews.php | 3 ++- scripts/mongo/triplesToBSON.php | 3 --- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/scripts/mongo/common.inc.php b/scripts/mongo/common.inc.php index 3b492815..0d4cd5e7 100644 --- a/scripts/mongo/common.inc.php +++ b/scripts/mongo/common.inc.php @@ -13,11 +13,9 @@ } if (!defined('TRIPOD_COMPOSER_INSTALL')) { - exit( - 'You need to set up the project dependencies using the following commands:' . PHP_EOL + exit('You need to set up the project dependencies using the following commands:' . PHP_EOL . 'curl -sS https://getcomposer.org/installer | php' . PHP_EOL - . 'php composer.phar install' . PHP_EOL - ); + . 'php composer.phar install' . PHP_EOL); } require TRIPOD_COMPOSER_INSTALL; diff --git a/scripts/mongo/createSearchDocuments.php b/scripts/mongo/createSearchDocuments.php index 2c4fd564..d49be645 100644 --- a/scripts/mongo/createSearchDocuments.php +++ b/scripts/mongo/createSearchDocuments.php @@ -42,7 +42,8 @@ function showUsage($scriptName): void echo $help; } -if ($options === [] || $options === false || isset($options['h']) || isset($options['help']) +if ( + $options === [] || $options === false || isset($options['h']) || isset($options['help']) || (!isset($options['c']) && !isset($options['config'])) || (!isset($options['s']) && !isset($options['storename'])) ) { diff --git a/scripts/mongo/createTables.php b/scripts/mongo/createTables.php index cb7dd1d2..19db8395 100644 --- a/scripts/mongo/createTables.php +++ b/scripts/mongo/createTables.php @@ -44,7 +44,8 @@ function showUsage(): void echo $help; } -if ($options === [] || $options === false || isset($options['h']) || isset($options['help']) +if ( + $options === [] || $options === false || isset($options['h']) || isset($options['help']) || (!isset($options['c']) && !isset($options['config'])) || (!isset($options['s']) && !isset($options['storename'])) ) { diff --git a/scripts/mongo/createViews.php b/scripts/mongo/createViews.php index 2e9334f8..7114302a 100644 --- a/scripts/mongo/createViews.php +++ b/scripts/mongo/createViews.php @@ -44,7 +44,8 @@ function showUsage(): void echo $help; } -if ($options === [] || $options === false || isset($options['h']) || isset($options['help']) +if ( + $options === [] || $options === false || isset($options['h']) || isset($options['help']) || (!isset($options['c']) && !isset($options['config'])) || (!isset($options['s']) && !isset($options['storename'])) ) { diff --git a/scripts/mongo/triplesToBSON.php b/scripts/mongo/triplesToBSON.php index 96553b34..84f76d20 100644 --- a/scripts/mongo/triplesToBSON.php +++ b/scripts/mongo/triplesToBSON.php @@ -43,6 +43,3 @@ // last doc echo json_encode($tu->getTArrayAbout($currentSubject, $triples, Config::getInstance()->getDefaultContextAlias())) . "\n"; - -?> - From 74ef976414713bd4e8c5bf71e400c58ea1535be8 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 3 Mar 2026 10:08:25 +0000 Subject: [PATCH 16/56] Format src --- src/classes/ExtendedGraph.php | 30 +++- src/classes/Labeller.php | 12 +- src/mongo/Config.php | 10 +- src/mongo/MongoGraph.php | 12 +- src/mongo/base/CompositeBase.php | 3 +- src/mongo/base/JobBase.php | 2 +- src/mongo/delegates/SearchDocuments.php | 3 +- src/mongo/delegates/SearchIndexer.php | 3 +- src/mongo/delegates/Tables.php | 3 +- src/mongo/delegates/Updates.php | 6 +- src/mongo/delegates/Views.php | 6 +- src/mongo/jobs/ApplyOperation.php | 2 +- src/mongo/providers/MongoSearchProvider.php | 180 +++++++++++++++++++- 13 files changed, 244 insertions(+), 28 deletions(-) diff --git a/src/classes/ExtendedGraph.php b/src/classes/ExtendedGraph.php index f0694495..ce00d7a5 100644 --- a/src/classes/ExtendedGraph.php +++ b/src/classes/ExtendedGraph.php @@ -26,9 +26,24 @@ class ExtendedGraph // FROM SimpleGraph public $_index = []; - public $_image_properties = ['http://xmlns.com/foaf/0.1/depiction', 'http://xmlns.com/foaf/0.1/img']; + public $_image_properties = [ + 'http://xmlns.com/foaf/0.1/depiction', + 'http://xmlns.com/foaf/0.1/img', + ]; - public $_property_order = ['http://www.w3.org/2004/02/skos/core#prefLabel', RDFS_LABEL, 'http://purl.org/dc/terms/title', DC_TITLE, FOAF_NAME, 'http://www.w3.org/2004/02/skos/core#definition', RDFS_COMMENT, 'http://purl.org/dc/terms/description', DC_DESCRIPTION, 'http://purl.org/vocab/bio/0.1/olb', RDF_TYPE]; + public $_property_order = [ + 'http://www.w3.org/2004/02/skos/core#prefLabel', + RDFS_LABEL, + 'http://purl.org/dc/terms/title', + DC_TITLE, + FOAF_NAME, + 'http://www.w3.org/2004/02/skos/core#definition', + RDFS_COMMENT, + 'http://purl.org/dc/terms/description', + DC_DESCRIPTION, + 'http://purl.org/vocab/bio/0.1/olb', + RDF_TYPE, + ]; public $parser_errors = []; @@ -1120,11 +1135,12 @@ public function merge(array ...$indices): array /* Make sure that bnode ids don't overlap: _:a in g1 isn't the same as _:a in g2 */ - if (substr($uri, 0, 2) == '_:') {// bnode + if (substr($uri, 0, 2) == '_:') { // bnode $old_id = $uri; $count = 1; - while (isset($current[$uri]) || $old_id != $uri && isset($newGraph[$uri]) || isset($old_bnodeids[$uri]) + while ( + isset($current[$uri]) || $old_id != $uri && isset($newGraph[$uri]) || isset($old_bnodeids[$uri]) ) { $uri .= $count++; } @@ -1146,7 +1162,8 @@ public function merge(array ...$indices): array } else { // bnode hasn't been transposed $old_bnode_id = $bnode; $count = 1; - while (isset($current[$bnode]) || $object['value'] != $bnode && isset($newGraph[$bnode]) || isset($old_bnodeids[$uri]) + while ( + isset($current[$bnode]) || $object['value'] != $bnode && isset($newGraph[$bnode]) || isset($old_bnodeids[$uri]) ) { $bnode .= $count++; } @@ -1688,8 +1705,7 @@ private function _add_arc2_triple_list(array &$triples): void if ($t['o_type'] === 'iri') { $obj['type'] = 'uri'; - } elseif (in_array($t['o_type'], ['literal1', 'literal2', 'long_literal1', 'long_literal2'], true) - ) { + } elseif (in_array($t['o_type'], ['literal1', 'literal2', 'long_literal1', 'long_literal2'], true)) { $obj['type'] = 'literal'; } else { $obj['type'] = $t['o_type']; diff --git a/src/classes/Labeller.php b/src/classes/Labeller.php index 990eb98b..6c15511b 100644 --- a/src/classes/Labeller.php +++ b/src/classes/Labeller.php @@ -350,7 +350,17 @@ public function get_prefix(string $ns): string $parts = preg_split('/[\/#]/', $ns); for ($i = count($parts) - 1; $i >= 0; $i--) { - if (preg_match('~^[a-zA-Z][a-zA-Z0-9\-]+$~', $parts[$i]) && !array_key_exists($parts[$i], $this->_ns) && $parts[$i] != 'schema' && $parts[$i] != 'ontology' && $parts[$i] != 'vocab' && $parts[$i] != 'terms' && $parts[$i] != 'ns' && $parts[$i] != 'core' && strlen($parts[$i]) > 3) { + if ( + preg_match('~^[a-zA-Z][a-zA-Z0-9\-]+$~', $parts[$i]) + && !array_key_exists($parts[$i], $this->_ns) + && $parts[$i] != 'schema' + && $parts[$i] != 'ontology' + && $parts[$i] != 'vocab' + && $parts[$i] != 'terms' + && $parts[$i] != 'ns' + && $parts[$i] != 'core' + && strlen($parts[$i]) > 3 + ) { $prefix = strtolower($parts[$i]); $this->_ns[$prefix] = $ns; diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 9f371fd8..6ec7c73e 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -1210,8 +1210,10 @@ protected function loadConfig(array $config) $fieldsThatAreArrays = 0; foreach ($cardinalityIndexFields as $field => $fieldVal) { $cardinalityField = str_replace('.value', '', $field); - if (!array_key_exists($cardinalityField, $this->cardinality[$storeName][$podName]) - || $this->cardinality[$storeName][$podName][$cardinalityField] != 1) { + if ( + !array_key_exists($cardinalityField, $this->cardinality[$storeName][$podName]) + || $this->cardinality[$storeName][$podName][$cardinalityField] != 1 + ) { $fieldsThatAreArrays++; } @@ -1381,7 +1383,9 @@ protected function validateTableSpecPart(array $spec, $depth = 0) $validComputingFieldFunctions = Tables::$computedFieldFunctions; if ($validationLevel == self::VALIDATE_MAX) { $availableFields = $this->getFieldNamesInSpec($spec); - $availableFields = array_map(function (string $field): string { return '$' . $field; }, $availableFields); + $availableFields = array_map(function (string $field): string { + return '$' . $field; + }, $availableFields); } foreach ($spec['computed_fields'] as $field) { diff --git a/src/mongo/MongoGraph.php b/src/mongo/MongoGraph.php index a8b9a924..a8ec4a29 100644 --- a/src/mongo/MongoGraph.php +++ b/src/mongo/MongoGraph.php @@ -172,7 +172,8 @@ private function toGraphValueObject(array $mongoValueObject): array // single value literal $simpleGraphValueObject[] = [ 'type' => 'literal', - 'value' => $mongoValueObject[VALUE_LITERAL]]; + 'value' => $mongoValueObject[VALUE_LITERAL], + ]; } } elseif (array_key_exists(VALUE_URI, $mongoValueObject)) { // only allow valid values @@ -180,7 +181,8 @@ private function toGraphValueObject(array $mongoValueObject): array // single value uri $simpleGraphValueObject[] = [ 'type' => 'uri', - 'value' => $this->_labeller->qname_to_alias($mongoValueObject[VALUE_URI])]; + 'value' => $this->_labeller->qname_to_alias($mongoValueObject[VALUE_URI]), + ]; } } else { // If we have an array of values @@ -203,7 +205,8 @@ private function toGraphValueObject(array $mongoValueObject): array $simpleGraphValueObject[] = [ 'type' => $valueTypeLabel, - 'value' => ($type == VALUE_URI) ? $this->_labeller->qname_to_alias($value) : $value]; + 'value' => ($type == VALUE_URI) ? $this->_labeller->qname_to_alias($value) : $value, + ]; } } } @@ -222,7 +225,8 @@ private function toMongoTripodValueObject(array $simpleGraphValueObject): array $valueTypeProp = ($simpleGraphValueObject['type'] == 'literal') ? VALUE_LITERAL : VALUE_URI; return [ - $valueTypeProp => ($simpleGraphValueObject['type'] == 'literal') ? $simpleGraphValueObject['value'] : $this->_labeller->uri_to_alias($simpleGraphValueObject['value'])]; + $valueTypeProp => ($simpleGraphValueObject['type'] == 'literal') ? $simpleGraphValueObject['value'] : $this->_labeller->uri_to_alias($simpleGraphValueObject['value']), + ]; } /** diff --git a/src/mongo/base/CompositeBase.php b/src/mongo/base/CompositeBase.php index 6655feab..679f0537 100644 --- a/src/mongo/base/CompositeBase.php +++ b/src/mongo/base/CompositeBase.php @@ -66,8 +66,7 @@ public function getImpactedSubjects(array $subjectsAndPredicatesOfChange, $conte $currentSubjectProperties = []; if (isset($subjectsAndPredicatesOfChange[$docResource])) { $currentSubjectProperties = $subjectsAndPredicatesOfChange[$docResource]; - } elseif (isset($subjectsToAlias[$docResource], $subjectsAndPredicatesOfChange[$subjectsToAlias[$docResource]]) - ) { + } elseif (isset($subjectsToAlias[$docResource], $subjectsAndPredicatesOfChange[$subjectsToAlias[$docResource]])) { $currentSubjectProperties = $subjectsAndPredicatesOfChange[$subjectsToAlias[$docResource]]; } diff --git a/src/mongo/base/JobBase.php b/src/mongo/base/JobBase.php index e14da8b3..ff130bac 100644 --- a/src/mongo/base/JobBase.php +++ b/src/mongo/base/JobBase.php @@ -78,7 +78,7 @@ public function tearDown(): void $this->timer->stop(); $this->debugLog( '[JOBID ' . $this->job->payload['id'] . '] ' . get_class($this) - . sprintf('::perform() done in %sms', $this->timer->result()) + . sprintf('::perform() done in %sms', $this->timer->result()) ); $this->getStat()->timer($this->getStatTimerSuccessKey(), $this->timer->result()); } diff --git a/src/mongo/delegates/SearchDocuments.php b/src/mongo/delegates/SearchDocuments.php index 123ee4e7..23c71040 100644 --- a/src/mongo/delegates/SearchDocuments.php +++ b/src/mongo/delegates/SearchDocuments.php @@ -66,7 +66,8 @@ public function generateSearchDocumentBasedOnSpecId(string $specId, $resource, $ // add id of current record to rules.. $indexRules['condition']['_id'] = [ 'r' => $this->labeller->uri_to_alias($resource), - 'c' => $this->labeller->uri_to_alias($context)]; + 'c' => $this->labeller->uri_to_alias($context), + ]; if ($this->getConfigInstance()->getCollectionForCBD($this->storeName, $irFrom)->findOne($indexRules['condition'])) { // match found, add this spec id to those that should be generated diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 3e3fbb84..741755d8 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -248,7 +248,8 @@ public function generateSearchDocuments( 'type' => $spec['type'], 'duration' => $t->result(), 'filter' => $filter, - 'from' => $from]); + 'from' => $from, + ]); $this->getStat()->timer(MONGO_CREATE_SEARCH_DOC . ('.' . $searchDocumentType), $t->result()); $stat = ['count' => $count]; diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index 8caf845d..ec442761 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -532,7 +532,8 @@ public function generateTableRows(string $tableType, $resource = null, $context 'type' => $tableSpec['type'], 'duration' => $t->result(), 'filter' => $filter, - 'from' => $from]); + 'from' => $from, + ]); $this->getStat()->timer(MONGO_CREATE_TABLE . ('.' . $tableType), $t->result()); $stat = ['count' => $count]; diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index d02bfc2b..5a71ecd8 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -99,7 +99,8 @@ public function __construct(Driver $tripod, $opts = []) OP_ASYNC => [OP_VIEWS => false, OP_TABLES => true, OP_SEARCH => true], 'stat' => null, 'readPreference' => ReadPreference::RP_PRIMARY_PREFERRED, - 'retriesToGetLock' => 20], $opts); + 'retriesToGetLock' => 20, + ], $opts); $this->readPreference = $opts['readPreference']; $this->config = $this->getConfigInstance(); @@ -1032,7 +1033,8 @@ protected function lockSingleDocument($s, $transaction_id, $contextAlias) [ _ID_KEY => [ _ID_RESOURCE => $this->labeller->uri_to_alias($s), - _ID_CONTEXT => $contextAlias], + _ID_CONTEXT => $contextAlias, + ], ] ); diff --git a/src/mongo/delegates/Views.php b/src/mongo/delegates/Views.php index 3f963451..fcec5bed 100644 --- a/src/mongo/delegates/Views.php +++ b/src/mongo/delegates/Views.php @@ -344,7 +344,8 @@ public function generateViewsForResourcesOfType($rdfType, $resource = null, $con // check for rdfType and rdfTypeAlias if ( ($viewSpec['type'] == $rdfType || (is_array($viewSpec['type']) && in_array($rdfType, $viewSpec['type']))) - || ($viewSpec['type'] == $rdfTypeAlias || (is_array($viewSpec['type']) && in_array($rdfTypeAlias, $viewSpec['type'])))) { + || ($viewSpec['type'] == $rdfTypeAlias || (is_array($viewSpec['type']) && in_array($rdfTypeAlias, $viewSpec['type']))) + ) { $foundSpec = true; $this->debugLog('Processing ' . $viewSpec['_id']); $this->generateView($key, $resource, $context); @@ -514,7 +515,8 @@ public function generateView(string $viewId, $resource = null, $context = null, 'view' => $viewSpec['type'], 'duration' => $t->result(), 'filter' => $filter, - 'from' => $from]); + 'from' => $from, + ]); $this->getStat()->timer(MONGO_CREATE_VIEW . ('.' . $viewId), $t->result()); $stat = ['count' => $count]; diff --git a/src/mongo/jobs/ApplyOperation.php b/src/mongo/jobs/ApplyOperation.php index e24d3224..895057f6 100644 --- a/src/mongo/jobs/ApplyOperation.php +++ b/src/mongo/jobs/ApplyOperation.php @@ -80,7 +80,7 @@ public function perform(): void $this->infoLog( '[JobGroupId ' . $jobGroup->getId()->__toString() . '] composite cleanup for ' - . $subject['operation'] . ' removed ' . $count . ' stale composite documents' + . $subject['operation'] . ' removed ' . $count . ' stale composite documents' ); } } diff --git a/src/mongo/providers/MongoSearchProvider.php b/src/mongo/providers/MongoSearchProvider.php index 2064567e..ee9df767 100644 --- a/src/mongo/providers/MongoSearchProvider.php +++ b/src/mongo/providers/MongoSearchProvider.php @@ -30,7 +30,182 @@ class MongoSearchProvider implements ISearchProvider */ private $labeller; - private $stopWords = ['a', 'about', 'above', 'after', 'again', 'against', 'all', 'am', 'an', 'and', 'any', 'are', "aren't", 'as', 'at', 'be', 'because', 'been', 'before', 'being', 'below', 'between', 'both', 'but', 'by', "can't", 'cannot', 'could', "couldn't", 'did', "didn't", 'do', 'does', "doesn't", 'doing', "don't", 'down', 'during', 'each', 'few', 'for', 'from', 'further', 'had', "hadn't", 'has', "hasn't", 'have', "haven't", 'having', 'he', "he'd", "he'll", "he's", 'her', 'here', "here's", 'hers', 'herself', 'him', 'himself', 'his', 'how', "how's", 'i', "i'd", "i'll", "i'm", "i've", 'if', 'in', 'into', 'is', "isn't", 'it', "it's", 'its', 'itself', "let's", 'me', 'more', 'most', "mustn't", 'my', 'myself', 'no', 'nor', 'not', 'of', 'off', 'on', 'once', 'only', 'or', 'other', 'ought', 'our', 'ours ', 'ourselves', 'out', 'over', 'own', 'same', "shan't", 'she', "she'd", "she'll", "she's", 'should', "shouldn't", 'so', 'some', 'such', 'than', 'that', "that's", 'the', 'their', 'theirs', 'them', 'themselves', 'then', 'there', "there's", 'these', 'they', "they'd", "they'll", "they're", "they've", 'this', 'those', 'through', 'to', 'too', 'under', 'until', 'up', 'very', 'was', "wasn't", 'we', "we'd", "we'll", "we're", "we've", 'were', "weren't", 'what', "what's", 'when', "when's", 'where', "where's", 'which', 'while', 'who', "who's", 'whom', 'why', "why's", 'with', "won't", 'would', "wouldn't", 'you', "you'd", "you'll", "you're", "you've", 'your', 'yours', 'yourself', 'yourselves']; + private $stopWords = [ + 'a', + 'about', + 'above', + 'after', + 'again', + 'against', + 'all', + 'am', + 'an', + 'and', + 'any', + 'are', + "aren't", + 'as', + 'at', + 'be', + 'because', + 'been', + 'before', + 'being', + 'below', + 'between', + 'both', + 'but', + 'by', + "can't", + 'cannot', + 'could', + "couldn't", + 'did', + "didn't", + 'do', + 'does', + "doesn't", + 'doing', + "don't", + 'down', + 'during', + 'each', + 'few', + 'for', + 'from', + 'further', + 'had', + "hadn't", + 'has', + "hasn't", + 'have', + "haven't", + 'having', + 'he', + "he'd", + "he'll", + "he's", + 'her', + 'here', + "here's", + 'hers', + 'herself', + 'him', + 'himself', + 'his', + 'how', + "how's", + 'i', + "i'd", + "i'll", + "i'm", + "i've", + 'if', + 'in', + 'into', + 'is', + "isn't", + 'it', + "it's", + 'its', + 'itself', + "let's", + 'me', + 'more', + 'most', + "mustn't", + 'my', + 'myself', + 'no', + 'nor', + 'not', + 'of', + 'off', + 'on', + 'once', + 'only', + 'or', + 'other', + 'ought', + 'our', + 'ours ', + 'ourselves', + 'out', + 'over', + 'own', + 'same', + "shan't", + 'she', + "she'd", + "she'll", + "she's", + 'should', + "shouldn't", + 'so', + 'some', + 'such', + 'than', + 'that', + "that's", + 'the', + 'their', + 'theirs', + 'them', + 'themselves', + 'then', + 'there', + "there's", + 'these', + 'they', + "they'd", + "they'll", + "they're", + "they've", + 'this', + 'those', + 'through', + 'to', + 'too', + 'under', + 'until', + 'up', + 'very', + 'was', + "wasn't", + 'we', + "we'd", + "we'll", + "we're", + "we've", + 'were', + "weren't", + 'what', + "what's", + 'when', + "when's", + 'where', + "where's", + 'which', + 'while', + 'who', + "who's", + 'whom', + 'why', + "why's", + 'with', + "won't", + 'would', + "wouldn't", + 'you', + "you'd", + "you'll", + "you're", + "you've", + 'your', + 'yours', + 'yourself', + 'yourselves', + ]; public function __construct(Driver $tripod) { @@ -268,7 +443,8 @@ public function search($q, $type, $indices = [], $fields = [], $limit = 10, $off ->find($query, [ 'projection' => $fieldsToReturn, 'limit' => $limit, - 'skip' => $offset]); + 'skip' => $offset, + ]); $searchResults = []; $searchResults['head'] = []; From 982da6089f70ae3f4da330ee02f5e71390d90bc9 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Thu, 5 Mar 2026 14:57:54 +0000 Subject: [PATCH 17/56] Tolerate null values in StatsD --- src/classes/StatsD.php | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/classes/StatsD.php b/src/classes/StatsD.php index 736d4fb6..7068077c 100644 --- a/src/classes/StatsD.php +++ b/src/classes/StatsD.php @@ -12,10 +12,10 @@ class StatsD implements ITripodStat /** @var int|string */ private $port; - /** @var string */ + /** @var string|null */ private $prefix; - /** @var string */ + /** @var string|null */ private $pivotValue; /** @@ -105,11 +105,9 @@ public function getPrefix() } /** - * @param string $prefix - * * @throws \InvalidArgumentException */ - public function setPrefix($prefix): void + public function setPrefix(?string $prefix): void { if ($this->isValidPathValue($prefix)) { $this->prefix = $prefix; @@ -159,11 +157,9 @@ public function getPivotValue() } /** - * @param string $pivotValue - * * @throws \InvalidArgumentException */ - public function setPivotValue($pivotValue): void + public function setPivotValue(?string $pivotValue): void { if ($this->isValidPathValue($pivotValue)) { $this->pivotValue = $pivotValue; @@ -257,11 +253,9 @@ protected function getAggregateStatPath(): string /** * StatsD paths cannot start with, end with, or have more than one consecutive '.'. - * - * @param string $value */ - protected function isValidPathValue($value): bool + protected function isValidPathValue(?string $value): bool { - return preg_match('/(^\.)|(\.\.+)|(\.$)/', $value) === 0; + return $value === null || preg_match('/(^\.)|(\.\.+)|(\.$)/', $value) === 0; } } From 900b332e4522e874e453b93047bc74a35c94d624 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 10 Mar 2026 14:55:58 +0000 Subject: [PATCH 18/56] Refactor checks in Config --- src/mongo/Config.php | 149 +++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 89 deletions(-) diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 6ec7c73e..c19934c0 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -259,19 +259,19 @@ public function checkModifierFunctions(array $array, $parent, $parentKey = null) // Check config // Valid configs can be top level modifiers and their attributes inside - you can have a top level modifier // inside a top level modifier - that's why we also check \Tripod\Mongo\Composites\Tables::$predicatesModifiers direct - if (!array_key_exists($k, $parent) && !array_key_exists($k, Tables::$predicateModifiers)) { + if (!isset($parent[$k]) && !isset(Tables::$predicateModifiers[$k])) { throw new ConfigException("Invalid modifier: '" . $k . "' in key '" . $parentKey . "'"); } // If this config value is a top level modifier, use that as the parent so that we can check the attributes - if (array_key_exists($k, Tables::$predicateModifiers)) { + if (isset(Tables::$predicateModifiers[$k])) { $this->checkModifierFunctions($v, Tables::$predicateModifiers[$k], $k); } else { $this->checkModifierFunctions($v, $parent[$k], $k); } } elseif (is_string($k)) { // Check key - if (!array_key_exists($k, $parent)) { + if (!isset($parent[$k])) { throw new ConfigException("Invalid modifier: '" . $k . "' in key '" . $parentKey . "'"); } } @@ -355,7 +355,7 @@ public function getIndexesGroupedByCollection($storeName) // also add the indexes for any views/tables $tableIndexes = []; foreach ($this->getTableSpecifications($storeName) as $tspec) { - if (array_key_exists('ensureIndexes', $tspec)) { + if (isset($tspec['ensureIndexes'])) { // Indexes should be keyed by data_source if (!isset($tableIndexes[$tspec['to_data_source']])) { $tableIndexes[$tspec['to_data_source']] = []; @@ -371,7 +371,7 @@ public function getIndexesGroupedByCollection($storeName) $viewIndexes = []; foreach ($this->getViewSpecifications($storeName) as $vspec) { - if (array_key_exists('ensureIndexes', $vspec)) { + if (isset($vspec['ensureIndexes'])) { // Indexes should be keyed by data_source if (!isset($viewIndexes[$vspec['to_data_source']])) { $viewIndexes[$vspec['to_data_source']] = []; @@ -406,7 +406,7 @@ public function getCardinality($storeName, $collName, $qName = null) } // Return the cardinality rule for the specified qname. - if (array_key_exists($qName, $this->cardinality[$storeName][$collName])) { + if (isset($this->cardinality[$storeName][$collName][$qName])) { return $this->cardinality[$storeName][$collName][$qName]; } @@ -421,7 +421,7 @@ public function getCardinality($storeName, $collName, $qName = null) */ public function isPodWithinStore($storeName, $pod): bool { - return array_key_exists($storeName, $this->podConnections) && array_key_exists($pod, $this->podConnections[$storeName]); + return isset($this->podConnections[$storeName][$pod]); } /** @@ -433,7 +433,7 @@ public function isPodWithinStore($storeName, $pod): bool */ public function getPods($storeName) { - return (array_key_exists($storeName, $this->podConnections)) ? array_keys($this->podConnections[$storeName]) : []; + return isset($this->podConnections[$storeName]) ? array_keys($this->podConnections[$storeName]) : []; } /** @@ -449,7 +449,7 @@ public function getPods($storeName) */ public function getDataSourceForPod($storeName, $podName) { - if (isset($this->podConnections[$storeName], $this->podConnections[$storeName][$podName])) { + if (isset($this->podConnections[$storeName][$podName])) { return $this->podConnections[$storeName][$podName]; } @@ -500,7 +500,7 @@ public function isReplicaSet($datasource): bool */ public function getDefaultDataSourceForStore($storeName) { - if (array_key_exists($storeName, $this->dbConfig)) { + if (isset($this->dbConfig[$storeName]['data_source'])) { return $this->dbConfig[$storeName]['data_source']; } @@ -534,7 +534,7 @@ public function getViewSpecification($storeName, $vid) */ public function getSearchDocumentSpecification($storeName, $sid) { - if (array_key_exists($storeName, $this->searchDocSpecs) && array_key_exists($sid, $this->searchDocSpecs[$storeName])) { + if (isset($this->searchDocSpecs[$storeName][$sid])) { return $this->searchDocSpecs[$storeName][$sid]; } @@ -552,7 +552,7 @@ public function getSearchDocumentSpecification($storeName, $sid) */ public function getSearchDocumentSpecifications($storeName, $type = null, $justReturnSpecId = false) { - if (!isset($this->searchDocSpecs[$storeName]) || empty($this->searchDocSpecs[$storeName])) { + if (empty($this->searchDocSpecs[$storeName])) { return []; } @@ -598,7 +598,7 @@ public function getSearchDocumentSpecifications($storeName, $type = null, $justR */ public function getTableSpecification($storeName, $tid) { - if (isset($this->tableSpecs[$storeName], $this->tableSpecs[$storeName][$tid])) { + if (isset($this->tableSpecs[$storeName][$tid])) { return $this->tableSpecs[$storeName][$tid]; } @@ -773,20 +773,20 @@ public function getCollectionForCBD($storeName, $podName, $readPreference = Read * @param string $viewId * @param string $readPreference * - * @return Collection - * * @throws ConfigException */ - public function getCollectionForView($storeName, $viewId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionForView($storeName, $viewId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { - if (isset($this->viewSpecs[$storeName], $this->viewSpecs[$storeName][$viewId])) { - return $this->getMongoCollection( - $this->getDatabase($storeName, $this->viewSpecs[$storeName][$viewId]['to_data_source'], $readPreference), - VIEWS_COLLECTION - ); + if (!isset($this->viewSpecs[$storeName][$viewId])) { + throw new ConfigException(sprintf("View id '%s' not in configuration for store '%s'", $viewId, $storeName)); } - throw new ConfigException(sprintf("View id '%s' not in configuration for store '%s'", $viewId, $storeName)); + $dataSource = $this->viewSpecs[$storeName][$viewId]['to_data_source'] ?? null; + + return $this->getMongoCollection( + $this->getDatabase($storeName, $dataSource, $readPreference), + VIEWS_COLLECTION + ); } /** @@ -794,20 +794,20 @@ public function getCollectionForView($storeName, $viewId, $readPreference = Read * @param string $searchDocumentId * @param string $readPreference * - * @return Collection - * * @throws ConfigException */ - public function getCollectionForSearchDocument($storeName, $searchDocumentId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionForSearchDocument($storeName, $searchDocumentId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { - if (array_key_exists($storeName, $this->searchDocSpecs) && array_key_exists($searchDocumentId, $this->searchDocSpecs[$storeName])) { - return $this->getMongoCollection( - $this->getDatabase($storeName, $this->searchDocSpecs[$storeName][$searchDocumentId]['to_data_source'], $readPreference), - SEARCH_INDEX_COLLECTION - ); + if (!isset($this->searchDocSpecs[$storeName][$searchDocumentId])) { + throw new ConfigException(sprintf("Search document id '%s' not in configuration for store '%s'", $searchDocumentId, $storeName)); } - throw new ConfigException(sprintf("Search document id '%s' not in configuration for store '%s'", $searchDocumentId, $storeName)); + $dataSource = $this->searchDocSpecs[$storeName][$searchDocumentId]['to_data_source'] ?? null; + + return $this->getMongoCollection( + $this->getDatabase($storeName, $dataSource, $readPreference), + SEARCH_INDEX_COLLECTION + ); } /** @@ -815,20 +815,20 @@ public function getCollectionForSearchDocument($storeName, $searchDocumentId, $r * @param string $tableId * @param string $readPreference * - * @return Collection - * * @throws ConfigException */ - public function getCollectionForTable($storeName, $tableId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionForTable($storeName, $tableId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { - if (isset($this->tableSpecs[$storeName][$tableId], $this->tableSpecs[$storeName][$tableId])) { - return $this->getMongoCollection( - $this->getDatabase($storeName, $this->tableSpecs[$storeName][$tableId]['to_data_source'], $readPreference), - TABLE_ROWS_COLLECTION - ); + if (!isset($this->tableSpecs[$storeName][$tableId])) { + throw new ConfigException(sprintf("Table id '%s' not in configuration for store '%s'", $tableId, $storeName)); } - throw new ConfigException(sprintf("Table id '%s' not in configuration for store '%s'", $tableId, $storeName)); + $dataSource = $this->tableSpecs[$storeName][$tableId]['to_data_source'] ?? null; + + return $this->getMongoCollection( + $this->getDatabase($storeName, $dataSource, $readPreference), + TABLE_ROWS_COLLECTION + ); } /** @@ -851,11 +851,10 @@ public function getCollectionsForTables($storeName, array $tables = [], $readPre $dataSources = []; foreach ($tables as $table) { - if (isset($this->tableSpecs[$storeName][$table])) { - $dataSources[] = $this->tableSpecs[$storeName][$table]['to_data_source']; - } else { + if (!isset($this->tableSpecs[$storeName][$table])) { throw new ConfigException(sprintf("Table id '%s' not in configuration for store '%s'", $table, $storeName)); } + $dataSources[] = $this->tableSpecs[$storeName][$table]['to_data_source'] ?? null; } $collections = []; @@ -889,11 +888,10 @@ public function getCollectionsForViews($storeName, array $views = [], $readPrefe $dataSources = []; foreach ($views as $view) { - if (isset($this->viewSpecs[$storeName][$view])) { - $dataSources[] = $this->viewSpecs[$storeName][$view]['to_data_source']; - } else { + if (!isset($this->viewSpecs[$storeName][$view])) { throw new ConfigException(sprintf("View id '%s' not in configuration for store '%s'", $view, $storeName)); } + $dataSources[] = $this->viewSpecs[$storeName][$view]['to_data_source'] ?? null; } $collections = []; @@ -927,11 +925,10 @@ public function getCollectionsForSearch($storeName, array $searchSpecIds = [], $ $dataSources = []; foreach ($searchSpecIds as $searchSpec) { - if (isset($this->searchDocSpecs[$storeName][$searchSpec])) { - $dataSources[] = $this->searchDocSpecs[$storeName][$searchSpec]['to_data_source']; - } else { + if (!isset($this->searchDocSpecs[$storeName][$searchSpec])) { throw new ConfigException(sprintf("Search document spec id '%s' not in configuration for store '%s'", $searchSpec, $storeName)); } + $dataSources[] = $this->searchDocSpecs[$storeName][$searchSpec]['to_data_source'] ?? null; } $collections = []; @@ -1123,18 +1120,18 @@ public function getBatchSize($operation) protected function loadConfig(array $config) { $this->config = $config; - if (array_key_exists('namespaces', $config)) { + if (isset($config['namespaces'])) { $this->ns = $config['namespaces']; } $this->defaultContext = $this->getMandatoryKey('defaultContext', $config); foreach ($this->getMandatoryKey('data_sources', $config) as $source => $c) { - if (!array_key_exists('type', $c)) { + if (!isset($c['type'])) { throw new ConfigException('No \'type\' set for data source ' . $source); } - if (!array_key_exists('connection', $c)) { + if (!isset($c['connection'])) { throw new ConfigException('No connection information set for data source ' . $source); } @@ -1169,7 +1166,7 @@ protected function loadConfig(array $config) $this->podConnections[$storeName][$podName] = $dataSource; // Set cardinality, also checking against defined namespaces - if (array_key_exists('cardinality', $podConfig)) { + if (isset($podConfig['cardinality'])) { // Test that the namespace exists for each cardinality rule defined $cardinality = $podConfig['cardinality']; foreach ($cardinality as $qname => $cardinalityValue) { @@ -1177,7 +1174,7 @@ protected function loadConfig(array $config) // just grab the first element $namespace = array_shift($namespaces); - if (array_key_exists($namespace, $this->ns)) { + if (isset($this->ns[$namespace])) { $this->cardinality[$storeName][$podName][] = $cardinality; } else { throw new ConfigException(sprintf("Cardinality '%s' does not have the namespace defined", $qname)); @@ -1187,10 +1184,10 @@ protected function loadConfig(array $config) $this->cardinality[$storeName][$podName] = []; } - $this->cardinality[$storeName][$podName] = array_key_exists('cardinality', $podConfig) ? $podConfig['cardinality'] : []; + $this->cardinality[$storeName][$podName] = $podConfig['cardinality'] ?? []; // Ensure indexes are legal - if (array_key_exists('indexes', $podConfig)) { + if (isset($podConfig['indexes'])) { $this->indexes[$storeName][$podName] = []; foreach ($podConfig['indexes'] as $indexName => $indexFields) { @@ -1211,7 +1208,7 @@ protected function loadConfig(array $config) foreach ($cardinalityIndexFields as $field => $fieldVal) { $cardinalityField = str_replace('.value', '', $field); if ( - !array_key_exists($cardinalityField, $this->cardinality[$storeName][$podName]) + !isset($this->cardinality[$storeName][$podName][$cardinalityField]) || $this->cardinality[$storeName][$podName][$cardinalityField] != 1 ) { $fieldsThatAreArrays++; @@ -1235,7 +1232,7 @@ protected function loadConfig(array $config) } } - $searchConfig = array_key_exists('search_config', $storeConfig) ? $storeConfig['search_config'] : []; + $searchConfig = $storeConfig['search_config'] ?? []; $this->searchDocSpecs[$storeName] = []; if (!empty($searchConfig)) { $this->searchProviderClassName[$storeName] = $this->getMandatoryKey('search_provider', $searchConfig, 'search'); @@ -1273,7 +1270,7 @@ protected function loadConfig(array $config) } // Load view specs - $viewSpecs = (array_key_exists('view_specifications', $storeConfig)) ? $storeConfig['view_specifications'] : []; + $viewSpecs = $storeConfig['view_specifications'] ?? []; $this->viewSpecs[$storeName] = []; foreach ($viewSpecs as $spec) { if (!isset($spec[_ID_KEY])) { @@ -1301,7 +1298,7 @@ protected function loadConfig(array $config) } // Load table specs - $tableSpecs = (array_key_exists('table_specifications', $storeConfig)) ? $storeConfig['table_specifications'] : []; + $tableSpecs = $storeConfig['table_specifications'] ?? []; $this->tableSpecs[$storeName] = []; foreach ($tableSpecs as $spec) { $this->validateTableSpec($spec); @@ -1944,18 +1941,18 @@ private function getSpecificationTypes(array $specifications, $podName = null): */ private function ifCountExistsWithoutTTLThrowException(array $spec): void { - if (array_key_exists('ttl', $spec)) { + if (isset($spec['ttl'])) { return; // ttl exists } - if (array_key_exists('joins', $spec)) { + if (isset($spec['joins'])) { // recurse foreach ($spec['joins'] as $join) { $this->ifCountExistsWithoutTTLThrowException($join); } } - if (array_key_exists('counts', $spec)) { + if (isset($spec['counts'])) { throw new ConfigException('Aggregate function counts exists in spec, but no TTL defined'); } } @@ -1978,32 +1975,6 @@ private function getMandatoryKey(string $key, array $a, string $configName = 'co return $a[$key]; } - /** - * Finds fields in a table specification. - * - * @param string $fieldName - * @param array $spec, a part of space ot complete spec - * - * @return array - */ - private function findFieldsInTableSpec($fieldName, $spec) - { - $fields = []; - if (is_array($spec) && $spec !== []) { - if (array_key_exists($fieldName, $spec)) { - $fields = $spec[$fieldName]; - } - - if (isset($spec['joins'])) { - foreach ($spec['joins'] as $join) { - $fields = array_merge($fields, $this->findFieldsInTableSpec($fieldName, $join)); - } - } - } - - return $fields; - } - /** * @return string */ From f57cdee4d2ca84baa6d3d324e7216575746b1abc Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 2 Mar 2026 22:08:50 +0000 Subject: [PATCH 19/56] Add .gitattributes to exclude non-dist files https://getcomposer.org/doc/02-libraries.md#light-weight-distribution-packages --- .gitattributes | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..ddcf46cb --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +/.circleci/ export-ignore +/docker export-ignore +/test export-ignore +.editorconfig export-ignore +.env export-ignore +.php-cs-fixer* export-ignore +*.log export-ignore +docker-compose*.yml export-ignore +logo.png export-ignore +phpunit.xml export-ignore From 25e8be9ac6c49d4d7b97459770ae9fd955c3332d Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 6 Mar 2026 14:13:56 +0000 Subject: [PATCH 20/56] Cast ms to int for UTCDateTime --- src/mongo/util/DateUtil.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mongo/util/DateUtil.php b/src/mongo/util/DateUtil.php index 2eaf5d75..9b18ac94 100644 --- a/src/mongo/util/DateUtil.php +++ b/src/mongo/util/DateUtil.php @@ -18,7 +18,11 @@ class DateUtil public static function getMongoDate($milliseconds = null): UTCDateTime { if (is_null($milliseconds)) { - $milliseconds = floor(microtime(true) * 1000); + $milliseconds = microtime(true) * 1000; + } + + if (is_float($milliseconds)) { + $milliseconds = (int) floor($milliseconds); } return new UTCDateTime($milliseconds); From 6aa5979f33cec5f127aea8091c2c543a7e9d2112 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 6 Mar 2026 14:14:27 +0000 Subject: [PATCH 21/56] Migrate utf8_(decode|encode) to mb_convert_encoding --- src/mongo/serializers/NQuadSerializer.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mongo/serializers/NQuadSerializer.php b/src/mongo/serializers/NQuadSerializer.php index 61e58784..335fa78b 100644 --- a/src/mongo/serializers/NQuadSerializer.php +++ b/src/mongo/serializers/NQuadSerializer.php @@ -116,7 +116,9 @@ public function getSerializedIndex($index, ?string $context): string public function escape($v) { $r = ''; - $v = (strpos(utf8_decode(str_replace('?', '', $v)), '?') === false) ? utf8_decode($v) : $v; + $v = (strpos(mb_convert_encoding(str_replace('?', '', $v), 'ISO-8859-1', 'UTF-8'), '?') === false) + ? mb_convert_encoding($v, 'ISO-8859-1', 'UTF-8') + : $v; if ($this->raw) { return $v; } @@ -138,7 +140,7 @@ public function escape($v) */ public function getCharNo($c): int { - $c_utf = utf8_encode($c); + $c_utf = mb_convert_encoding($c, 'UTF-8', 'ISO-8859-1'); $bl = strlen($c_utf); // binary length $r = 0; From 74ee5e8dd9714ceae9d16253e532711ae04b2e38 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 9 Mar 2026 10:47:33 +0000 Subject: [PATCH 22/56] Fix trying to access array offset on null --- src/mongo/delegates/SearchIndexer.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 741755d8..324a56bb 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -181,14 +181,16 @@ public function generateSearchDocuments( $from = $spec['from'] ?? $this->podName; $types = []; - if (is_array($spec['type'])) { - foreach ($spec['type'] as $type) { - $types[] = ['rdf:type.u' => $this->labeller->qname_to_alias($type)]; - $types[] = ['rdf:type.u' => $this->labeller->uri_to_alias($type)]; + if (isset($spec['type'])) { + if (is_array($spec['type'])) { + foreach ($spec['type'] as $type) { + $types[] = ['rdf:type.u' => $this->labeller->qname_to_alias($type)]; + $types[] = ['rdf:type.u' => $this->labeller->uri_to_alias($type)]; + } + } else { + $types[] = ['rdf:type.u' => $this->labeller->qname_to_alias($spec['type'])]; + $types[] = ['rdf:type.u' => $this->labeller->uri_to_alias($spec['type'])]; } - } else { - $types[] = ['rdf:type.u' => $this->labeller->qname_to_alias($spec['type'])]; - $types[] = ['rdf:type.u' => $this->labeller->uri_to_alias($spec['type'])]; } $filter = ['$or' => $types]; @@ -245,7 +247,7 @@ public function generateSearchDocuments( $t->stop(); $this->timingLog(MONGO_CREATE_TABLE, [ - 'type' => $spec['type'], + 'type' => $spec['type'] ?? null, 'duration' => $t->result(), 'filter' => $filter, 'from' => $from, From 6184a2896bb321cdb79005166b0ee82975b2c1a4 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 9 Mar 2026 12:21:30 +0000 Subject: [PATCH 23/56] Profile performance tests --- .circleci/config.yml | 2 + .gitignore | 1 + composer.json | 3 +- docker/Dockerfile-php73 | 2 +- docker/Dockerfile-php74 | 2 +- test/performance/mongo/LargeGraphTest.php | 4 ++ .../mongo/MongoTripodPerformanceTestBase.php | 48 +++++++++++++++++-- 7 files changed, 55 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 231f88af..09da84a3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,6 +57,8 @@ commands: path: test-results/junit.xml - store_artifacts: path: test-results/junit.xml + - store_artifacts: + path: profiler jobs: lint: diff --git a/.gitignore b/.gitignore index dfa7f653..ad315119 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ tags atlassian-ide-plugin.xml composer.lock +profiler test-results .phpunit.result.cache .php-cs-fixer.cache diff --git a/composer.json b/composer.json index cdc4437c..a304db33 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,8 @@ "require-dev": { "phpunit/phpunit": "^9.6.20", "resque/php-resque": "v1.3.6", - "friendsofphp/php-cs-fixer": "^3.4" + "friendsofphp/php-cs-fixer": "^3.4", + "perftools/php-profiler": "^1.2" }, "autoload": { "classmap": ["src/"] diff --git a/docker/Dockerfile-php73 b/docker/Dockerfile-php73 index 56b1bced..54a06d99 100644 --- a/docker/Dockerfile-php73 +++ b/docker/Dockerfile-php73 @@ -15,4 +15,4 @@ RUN curl -sLo /tmp/mongosh.deb https://downloads.mongodb.com/compass/mongodb-mon COPY --from=mlocati/php-extension-installer:2.3.2 /usr/bin/install-php-extensions /usr/local/bin/ COPY --from=composer:2.7.7 /usr/bin/composer /usr/local/bin/ -RUN install-php-extensions pcntl mongodb-1.6.1 +RUN install-php-extensions pcntl mongodb-1.6.1 xhprof diff --git a/docker/Dockerfile-php74 b/docker/Dockerfile-php74 index 45947dac..86d86b60 100644 --- a/docker/Dockerfile-php74 +++ b/docker/Dockerfile-php74 @@ -15,4 +15,4 @@ RUN curl -sLo /tmp/mongosh.deb https://downloads.mongodb.com/compass/mongodb-mon COPY --from=mlocati/php-extension-installer:2.3.2 /usr/bin/install-php-extensions /usr/local/bin/ COPY --from=composer:2.7.7 /usr/bin/composer /usr/local/bin/ -RUN install-php-extensions pcntl mongodb-1.19.3 +RUN install-php-extensions pcntl mongodb-1.19.3 xhprof diff --git a/test/performance/mongo/LargeGraphTest.php b/test/performance/mongo/LargeGraphTest.php index 5c359bf6..42d8a016 100644 --- a/test/performance/mongo/LargeGraphTest.php +++ b/test/performance/mongo/LargeGraphTest.php @@ -37,6 +37,8 @@ public function testUpdateSingleTripleOfLargeGraph(): void $testStartTime = microtime(); + $this->startProfiler(); + $graph = new ExtendedGraph(); $graph->add_literal_triple($uri, 'http://rdfs.org/sioc/spec/name', 'new name'); @@ -57,6 +59,8 @@ public function testDescribeOfLargeGraph(): void $testStartTime = microtime(); + $this->startProfiler(); + $graph = new ExtendedGraph(); $graph->add_literal_triple($uri, 'http://rdfs.org/sioc/spec/name', 'new name'); diff --git a/test/performance/mongo/MongoTripodPerformanceTestBase.php b/test/performance/mongo/MongoTripodPerformanceTestBase.php index 5fad7116..32c800ab 100644 --- a/test/performance/mongo/MongoTripodPerformanceTestBase.php +++ b/test/performance/mongo/MongoTripodPerformanceTestBase.php @@ -2,17 +2,22 @@ declare(strict_types=1); +use Xhgui\Profiler\Profiler; + abstract class MongoTripodPerformanceTestBase extends MongoTripodTestBase { + /** @var Profiler|null */ + private $profiler; + /** * Helper function to calculate difference between two microtime values. * - * @param $microTime1, time string from microtime() - * @param $microTime2, time string from microtime() + * @param string $microTime1, time string from microtime() + * @param string $microTime2, time string from microtime() * - * @return float, time difference in ms + * @return float time difference in ms */ - protected function getTimeDifference($microTime1, $microTime2) + protected function getTimeDifference(string $microTime1, string $microTime2): float { [$endTimeMicroSeconds, $endTimeSeconds] = explode(' ', $microTime2); [$startTimeMicroSeconds, $startTimeSeconds] = explode(' ', $microTime1); @@ -21,4 +26,39 @@ protected function getTimeDifference($microTime1, $microTime2) return round(($differenceInMilliSeconds + ((float) $endTimeMicroSeconds * 1000)) - (float) $startTimeMicroSeconds * 1000); } + + protected function startProfiler(): void + { + $this->profiler = $this->getProfiler(); + $this->profiler->start(); + } + + /** + * @after + */ + protected function stopProfiler(): void + { + if ($this->profiler) { + $this->profiler->stop(); + $this->profiler = null; + } + } + + private function getProfiler(): Profiler + { + $profilerDir = __DIR__ . '/../../../profiler'; + if (!is_dir($profilerDir)) { + mkdir($profilerDir, 0777, true); + } + + return new Profiler([ + 'save.handler' => Profiler::SAVER_FILE, + 'save.handler.file' => [ + 'filename' => $profilerDir . '/xhgui.data.jsonl', + ], + 'profiler.replace_url' => function () { + return $this->getName(true) . ($this->hasFailed() ? ' FAIL' : ''); + }, + ]); + } } From 06be561ab251f4fc9714a42f2f755d0d803e79d3 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 9 Mar 2026 12:30:54 +0000 Subject: [PATCH 24/56] Move performance suite after unit tests --- phpunit.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpunit.xml b/phpunit.xml index 83a2fac8..e5c703ab 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -5,11 +5,11 @@ - - test/performance - test/unit + + test/performance + From 4a4640d98366c099be0308538e00848967f8dc9d Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Wed, 11 Mar 2026 21:16:37 +0000 Subject: [PATCH 25/56] Refactor __debugInfo()['readPreference'] to getReadPreference() --- src/mongo/Driver.php | 2 +- src/mongo/delegates/Updates.php | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index 78db3c5f..2895be82 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -704,7 +704,7 @@ protected function getLabeller(): Labeller protected function getDataUpdater() { if (!property_exists($this, 'updates') || $this->updates === null) { - $readPreference = $this->collection->__debugInfo()['readPreference']->getMode(); + $readPreference = $this->collection->getReadPreference()->getMode(); $opts = [ 'defaultContext' => $this->defaultContext, diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 5a71ecd8..97c2549f 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -431,8 +431,7 @@ protected function setReadPreferenceToPrimary() */ protected function resetOriginalReadPreference() { - /** @var ReadPreference $dbReadPref */ - $dbReadPref = $this->db->__debugInfo()['readPreference']; + $dbReadPref = $this->db->getReadPreference(); if ($this->originalDbReadPreference !== $dbReadPref->getMode()) { $pref = $this->originalDbReadPreference ?? $this->readPreference; $dbTagsets = $dbReadPref->getTagsets(); @@ -443,8 +442,7 @@ protected function resetOriginalReadPreference() } // Reset collection object - /** @var ReadPreference $collReadPref */ - $collReadPref = $this->getCollection()->__debugInfo()['readPreference']; + $collReadPref = $this->getCollection()->getReadPreference(); if ($this->originalCollectionReadPreference !== $collReadPref->getMode()) { $pref = $this->originalCollectionReadPreference ?? $this->readPreference; $collTagsets = $collReadPref->getTagsets(); From 5eaa2f8358df18f400c6c63a8b1a7a088989a83b Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Wed, 11 Mar 2026 22:18:03 +0000 Subject: [PATCH 26/56] Stricter interfaces --- src/IDriver.php | 101 ++----- src/IEventHook.php | 8 +- src/ITripodConfigSerializer.php | 6 +- src/TripodConfigFactory.php | 4 +- src/mongo/Config.php | 331 ++++++---------------- src/mongo/Driver.php | 169 +++-------- src/mongo/IComposite.php | 12 +- src/mongo/IConfigInstance.php | 236 +++++---------- src/mongo/base/CompositeBase.php | 21 +- src/mongo/delegates/SearchIndexer.php | 21 +- src/mongo/delegates/Tables.php | 16 +- src/mongo/delegates/Views.php | 80 ++---- test/unit/mongo/MongoTripodDriverTest.php | 2 +- test/unit/mongo/MongoTripodTestBase.php | 2 +- test/unit/mongo/TestConfigGenerator.php | 3 +- 15 files changed, 276 insertions(+), 736 deletions(-) diff --git a/src/IDriver.php b/src/IDriver.php index 79213355..2b9fa0d0 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -17,132 +17,94 @@ interface IDriver * * @return mixed */ - public function graph(array $filter, array $includeProperties = []); + public function graph(array $filter, array $includeProperties = []): ExtendedGraph; /** * Return (DESCRIBE) the concise bound description of a resource. * * @param string $resource uri resource you'd like to describe * @param string|null $context string uri of the context, or named graph, you'd like to describe from - * - * @return ExtendedGraph */ - public function describeResource($resource, $context = null); + public function describeResource(string $resource, ?string $context = null): ExtendedGraph; /** * Return (DESCRIBE) the concise bound descriptions of a bunch of resources. * * @param array $resources uris of resources you'd like to describe * @param string|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); + public function describeResources(array $resources, ?string $context = null): ExtendedGraph; /** * Get a view of a given type for a given resource. * - * @param string $resource uri of the resource you'd like the view for - * @param string $viewType string type of view - * - * @return ExtendedGraph + * @param string|null $resource uri of the resource you'd like the view for + * @param string $viewType string type of view */ - public function getViewForResource($resource, $viewType); + public function getViewForResource(?string $resource, string $viewType): ExtendedGraph; /** * Get views for multiple resources in one graph. * - * @param array $resources uris of resources you'd like to describe - * @param string $viewType type of view - * - * @return ExtendedGraph + * @param string[] $resources uris of resources you'd like to describe + * @param string $viewType type of view */ - public function getViewForResources(array $resources, $viewType); + public function getViewForResources(array $resources, string $viewType): ExtendedGraph; /** * Get views based on a pattern-match $filter. * * @param array $filter pattern to match to select views * @param string $viewType type of view - * - * @return ExtendedGraph */ - public function getViews(array $filter, $viewType); + public function getViews(array $filter, string $viewType): ExtendedGraph; /** * Returns the etag of a resource, useful for caching. - * - * @param string $resource - * @param string|null $context - * - * @return string */ - public function getETag($resource, $context = null); + public function getETag(string $resource, ?string $context = null): string; /** * Select data in a tabular format. * - * @param array $fields array of fields, in the same format as prescribed by MongoPHP - * @param int|null $limit - * @param int $offset - * @param string|null $context - * - * @return array + * @param array $fields array of fields, in the same format as prescribed by MongoPHP */ - public function select(array $query, array $fields, ?array $sortBy = null, $limit = null, $offset = 0, $context = null); + public function select(array $query, array $fields, ?array $sortBy = null, ?int $limit = null, int $offset = 0, ?string $context = null): array; /** * Select data from a table. - * - * @param string $tableType - * @param int $offset - * @param int $limit - * - * @return array */ public function getTableRows( - $tableType, + string $tableType, array $filter = [], array $sortBy = [], - $offset = 0, - $limit = 10, + int $offset = 0, + int $limit = 10, array $options = [] - ); + ): array; - /** - * @param string $tableType - * @param string $fieldName - * - * @return array - */ - public function getDistinctTableColumnValues($tableType, $fieldName, array $filter = []); + public function getDistinctTableColumnValues(string $tableType, string $fieldName, array $filter = []): array; /** * Get a count of resources matching the pattern in $query. Optionally group counts by specifying a $groupBy predicate. * - * @param string|null $groupBy - * @param int|null $ttl acceptable time to live if you're willing to accept a cached version of this request + * @param int|null $ttl acceptable time to live if you're willing to accept a cached version of this request * * @return array|int multidimensional array with int values if grouped by, otherwise int */ - public function getCount(array $query, $groupBy = null, $ttl = null); + public function getCount(array $query, ?string $groupBy = null, ?int $ttl = null); /** * Save the changes between $oldGraph -> $newGraph. * - * @param string|null $context - * @param string|null $description - * * @return bool true or throws exception on error */ - public function saveChanges(ExtendedGraph $oldGraph, ExtendedGraph $newGraph, $context = null, $description = null); + public function saveChanges(ExtendedGraph $oldGraph, ExtendedGraph $newGraph, ?string $context = null, ?string $description = null): bool; /** * Register an event hook, which will be executed when the event fires. - * - * @param string $eventType */ - public function registerHook($eventType, IEventHook $hook); + public function registerHook(string $eventType, IEventHook $hook); // START Deprecated methods that will be removed in 1.x.x @@ -152,21 +114,15 @@ public function registerHook($eventType, IEventHook $hook); * @deprecated Use graph() instead * * @param array $filter conditions to filter by - * - * @return ExtendedGraph */ - public function describe($filter); + public function describe(array $filter): ExtendedGraph; /** * 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 string $tableType - * @param string|null $resource - * @param string|null $context */ - public function generateTableRows($tableType, $resource = null, $context = null); + public function generateTableRows(string $tableType, ?string $resource = null, ?string $context = null): void; /** * Submits search params to configured search provider @@ -188,7 +144,7 @@ public function generateTableRows($tableType, $resource = null, $context = null) * @throws Exception - if search provider cannot be found * @throws SearchException - if something goes wrong */ - public function search(array $params); + public function search(array $params): array; /** * Get any documents that were left in a locked state. @@ -200,19 +156,16 @@ public function search(array $params); * * @return array of locked documents */ - public function getLockedDocuments($fromDateTime = null, $tillDateTime = null); + public function getLockedDocuments(?string $fromDateTime = null, ?string $tillDateTime = null): array; /** * 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 string $transaction_id - * @param string $reason - * * @return bool true or throws exception on error */ - public function removeInertLocks($transaction_id, $reason); + public function removeInertLocks(string $transaction_id, string $reason): bool; // END Deprecated methods that will be removed in 1.x.x } diff --git a/src/IEventHook.php b/src/IEventHook.php index 8ee67de2..cc88373d 100644 --- a/src/IEventHook.php +++ b/src/IEventHook.php @@ -23,7 +23,7 @@ interface IEventHook * * @param $args array of arguments */ - public function pre(array $args); + public function pre(array $args): void; /** * This method gets called after the event has successfully completed. The arguments passed depend on the event in @@ -32,12 +32,10 @@ public function pre(array $args); * * @param $args array of arguments */ - public function success(array $args); + public function success(array $args): void; /** * This method gets called if the event failed for any reason. The arguments passed should be the same as IEventHook::pre. - * - * @return mixed */ - public function failure(array $args); + public function failure(array $args): void; } diff --git a/src/ITripodConfigSerializer.php b/src/ITripodConfigSerializer.php index d1d2341a..1f015ff9 100644 --- a/src/ITripodConfigSerializer.php +++ b/src/ITripodConfigSerializer.php @@ -11,12 +11,10 @@ interface ITripodConfigSerializer /** * This should return an array that self::deserialize() can roundtrip into an Tripod Config object. */ - public function serialize(); + public function serialize(): array; /** * When given a valid config, returns a Tripod Config object. - * - * @return IConfigInstance */ - public static function deserialize(array $config); + public static function deserialize(array $config): IConfigInstance; } diff --git a/src/TripodConfigFactory.php b/src/TripodConfigFactory.php index fd8174f3..d44c9660 100644 --- a/src/TripodConfigFactory.php +++ b/src/TripodConfigFactory.php @@ -13,10 +13,8 @@ class TripodConfigFactory * ITripodConfigSerializer instance. * * @param array $config The Tripod config or serialized ITripodConfigSerializer array - * - * @return IConfigInstance */ - public static function create(array $config) + public static function create(array $config): IConfigInstance { if (Config::getConfig() !== $config) { Config::setConfig($config); diff --git a/src/mongo/Config.php b/src/mongo/Config.php index c19934c0..7d57b59a 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -104,6 +104,9 @@ class Config implements IConfigInstance */ protected $mongoCursorTimeout = 30000; + /** + * @var array + */ protected $batchSize = [ OP_TABLES => 100, OP_SEARCH => 100, @@ -175,18 +178,12 @@ class Config implements IConfigInstance */ private function __construct() {} - /** - * @return int - */ - public function getMongoCursorTimeout() + public function getMongoCursorTimeout(): int { return $this->mongoCursorTimeout; } - /** - * @param int $mongoCursorTimeout - */ - public function setMongoCursorTimeout($mongoCursorTimeout): void + public function setMongoCursorTimeout(int $mongoCursorTimeout): void { $this->mongoCursorTimeout = $mongoCursorTimeout; } @@ -209,18 +206,12 @@ public function validateTableSpec(array $spec): void $this->validateTableSpecPart($spec, 0); } - /** - * @return string - */ - public function getValidationLevel() + public function getValidationLevel(): string { return self::$validationLevel; } - /** - * @param string $validationLevel - */ - public static function setValidationLevel($validationLevel): void + public static function setValidationLevel(string $validationLevel): void { self::$validationLevel = $validationLevel; } @@ -228,13 +219,8 @@ public static function setValidationLevel($validationLevel): void /** * Returns an array of associated predicates in a table or search document specification * Note: will not return viewSpec predicates. - * - * @param string $storename - * @param string $specId - * - * @return array */ - public function getDefinedPredicatesInSpec($storename, $specId) + public function getDefinedPredicatesInSpec(string $storename, string $specId): array { if (!isset($this->specPredicates[$storename])) { $this->specPredicates[$storename] = $this->getDefinedPredicatesInSpecs($storename); @@ -246,12 +232,11 @@ public function getDefinedPredicatesInSpec($storename, $specId) /** * Check modifier functions against fields. * - * @param array|bool $parent - * @param string|null $parentKey + * @param array|bool $parent * * @throws ConfigException */ - public function checkModifierFunctions(array $array, $parent, $parentKey = null): void + public function checkModifierFunctions(array $array, $parent, ?string $parentKey = null): void { foreach ($array as $k => $v) { // You can have recursive modifiers so we check if the value is an array. @@ -280,10 +265,8 @@ public function checkModifierFunctions(array $array, $parent, $parentKey = null) /** * Returns an alias curie of the default context (i.e. graph name). - * - * @return string */ - public function getDefaultContextAlias() + public function getDefaultContextAlias(): string { return $this->getLabeller()->uri_to_alias($this->defaultContext); } @@ -337,12 +320,8 @@ public static function getConfig(): array /** * Returns a list of the configured indexes grouped by collection. - * - * @param string $storeName - * - * @return array */ - public function getIndexesGroupedByCollection($storeName) + public function getIndexesGroupedByCollection(string $storeName): array { $indexes = $this->indexes[$storeName]; // TODO: if we have much more default indexes we should find a better way of doing this @@ -398,7 +377,7 @@ public function getIndexesGroupedByCollection($storeName) * @return array|int if no qname is specified then returns an array of cardinality options, * otherwise returns the cardinality value for the given qname */ - public function getCardinality($storeName, $collName, $qName = null) + public function getCardinality(string $storeName, string $collName, ?string $qName = null) { // If no qname specified the return all cardinality rules for this db/collection. if (empty($qName)) { @@ -415,23 +394,16 @@ public function getCardinality($storeName, $collName, $qName = null) /** * Returns a boolean reflecting whether or not the database and collection are defined in the config. - * - * @param string $storeName - * @param string $pod */ - public function isPodWithinStore($storeName, $pod): bool + public function isPodWithinStore(string $storeName, string $pod): bool { return isset($this->podConnections[$storeName][$pod]); } /** * Returns an array of collection configurations for the supplied database name. - * - * @param string $storeName - * - * @return array */ - public function getPods($storeName) + public function getPods(string $storeName): array { return isset($this->podConnections[$storeName]) ? array_keys($this->podConnections[$storeName]) : []; } @@ -440,14 +412,9 @@ public function getPods($storeName) * Returns the name of the data source for the request pod. This may be the default for the store or the pod may * have overridden it in the config. * - * @param string $storeName - * @param string $podName - * - * @return string - * * @throws ConfigException */ - public function getDataSourceForPod($storeName, $podName) + public function getDataSourceForPod(string $storeName, string $podName): string { if (isset($this->podConnections[$storeName][$podName])) { return $this->podConnections[$storeName][$podName]; @@ -458,12 +425,8 @@ public function getDataSourceForPod($storeName, $podName) /** * Returns a replica set name for the database, if one has been defined. - * - * @param string $datasource - * - * @return string|null */ - public function getReplicaSetName($datasource) + public function getReplicaSetName(string $datasource): ?string { if (empty($this->dataSources[$datasource])) { throw new ConfigException(sprintf("Data source '%s' not in configuration", $datasource)); @@ -487,18 +450,13 @@ public function getReplicaSetName($datasource) /** * Returns a boolean reflecting whether or not a replica set has been defined for the supplied database name. - * - * @param string $datasource */ - public function isReplicaSet($datasource): bool + public function isReplicaSet(string $datasource): bool { return $this->getReplicaSetName($datasource) !== null; } - /** - * @param string $storeName - */ - public function getDefaultDataSourceForStore($storeName) + public function getDefaultDataSourceForStore(string $storeName): ?string { if (isset($this->dbConfig[$storeName]['data_source'])) { return $this->dbConfig[$storeName]['data_source']; @@ -509,13 +467,8 @@ public function getDefaultDataSourceForStore($storeName) /** * Return the view specification document for the supplied id, if it exists. - * - * @param string $storeName - * @param string $vid - * - * @return array|null */ - public function getViewSpecification($storeName, $vid) + public function getViewSpecification(string $storeName, string $vid): ?array { if (isset($this->viewSpecs[$storeName], $this->viewSpecs[$storeName][$vid])) { return $this->viewSpecs[$storeName][$vid]; @@ -526,13 +479,8 @@ public function getViewSpecification($storeName, $vid) /** * Returns the search document specification for the supplied id, if it exists. - * - * @param string $storeName - * @param string $sid - * - * @return array|null */ - public function getSearchDocumentSpecification($storeName, $sid) + public function getSearchDocumentSpecification(string $storeName, string $sid): ?array { if (isset($this->searchDocSpecs[$storeName][$sid])) { return $this->searchDocSpecs[$storeName][$sid]; @@ -544,13 +492,10 @@ public function getSearchDocumentSpecification($storeName, $sid) /** * Returns an array of all search document specifications, or specification ids. * - * @param string $storeName * @param string|null $type When supplied, will only return search document specifications that are triggered by this rdf:type * @param bool $justReturnSpecId default is false. If true will only return an array of specification _id's, otherwise returns the array of specification documents - * - * @return array */ - public function getSearchDocumentSpecifications($storeName, $type = null, $justReturnSpecId = false) + public function getSearchDocumentSpecifications(string $storeName, ?string $type = null, bool $justReturnSpecId = false): array { if (empty($this->searchDocSpecs[$storeName])) { return []; @@ -590,13 +535,8 @@ public function getSearchDocumentSpecifications($storeName, $type = null, $justR /** * Returns the requested table specification, if it exists. - * - * @param string $storeName - * @param string $tid - * - * @return array|null */ - public function getTableSpecification($storeName, $tid) + public function getTableSpecification(string $storeName, string $tid): ?array { if (isset($this->tableSpecs[$storeName][$tid])) { return $this->tableSpecs[$storeName][$tid]; @@ -609,12 +549,8 @@ public function getTableSpecification($storeName, $tid) * Returns all defined table specifications. * * @codeCoverageIgnore - * - * @param string $storeName - * - * @return array */ - public function getTableSpecifications($storeName) + public function getTableSpecifications(string $storeName): array { return $this->tableSpecs[$storeName] ?? []; } @@ -623,12 +559,8 @@ public function getTableSpecifications($storeName) * Returns all defined view specification. * * @codeCoverageIgnore - * - * @param string $storeName - * - * @return array */ - public function getViewSpecifications($storeName) + public function getViewSpecifications(string $storeName): array { return $this->viewSpecs[$storeName] ?? []; } @@ -636,11 +568,9 @@ public function getViewSpecifications($storeName) /** * This method returns a unique list of every rdf type configured in a specifications ['type'] restriction. * - * @param string $storeName - * * @return array of types */ - public function getAllTypesInSpecifications($storeName): array + public function getAllTypesInSpecifications(string $storeName): array { $viewTypes = $this->getTypesInViewSpecifications($storeName); $tableTypes = $this->getTypesInTableSpecifications($storeName); @@ -652,33 +582,24 @@ public function getAllTypesInSpecifications($storeName): array /** * Returns a unique list of every rdf type configured in the view spec ['type'] restriction. - * - * @param string $storeName - * @param string|null $pod */ - public function getTypesInViewSpecifications($storeName, $pod = null): array + public function getTypesInViewSpecifications(string $storeName, ?string $pod = null): array { return array_unique($this->getSpecificationTypes($this->getViewSpecifications($storeName), $pod)); } /** * Returns a unique list of every rdf type configured in the table spec ['type'] restriction. - * - * @param string $storeName - * @param string|null $pod */ - public function getTypesInTableSpecifications($storeName, $pod = null): array + public function getTypesInTableSpecifications(string $storeName, ?string $pod = null): array { return array_unique($this->getSpecificationTypes($this->getTableSpecifications($storeName), $pod)); } /** * Returns a unique list of every rdf type configured in the search doc spec ['type'] restriction. - * - * @param string $storeName - * @param string|null $pod */ - public function getTypesInSearchSpecifications($storeName, $pod = null): array + public function getTypesInSearchSpecifications(string $storeName, ?string $pod = null): array { return array_unique($this->getSpecificationTypes($this->getSearchDocumentSpecifications($storeName), $pod)); } @@ -693,44 +614,31 @@ public function getDbs(): array /** * Returns an array of defined namespaces. - * - * @return array */ - public function getNamespaces() + public function getNamespaces(): array { return $this->ns; } /** * Getter for transaction log connection config. - * - * @return array */ - public function getTransactionLogConfig() + public function getTransactionLogConfig(): array { return $this->tConfig; } - /** - * @param string $storeName - * - * @return string|null - */ - public function getSearchProviderClassName($storeName) + public function getSearchProviderClassName(string $storeName): ?string { return $this->searchProviderClassName[$storeName] ?? null; } /** - * @param string $storeName - * @param string|null $dataSource - * @param string $readPreference - * - * @return Database + * @param int|string $readPreference * * @throws ConfigException */ - public function getDatabase($storeName, $dataSource = null, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getDatabase(string $storeName, ?string $dataSource = null, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Database { if (!isset($this->dbConfig[$storeName])) { throw new ConfigException(sprintf("Store name '%s' not in configuration", $storeName)); @@ -748,15 +656,11 @@ public function getDatabase($storeName, $dataSource = null, $readPreference = Re } /** - * @param string $storeName - * @param string $podName - * @param string $readPreference - * - * @return Collection + * @param int|string $readPreference * * @throws ConfigException */ - public function getCollectionForCBD($storeName, $podName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionForCBD(string $storeName, string $podName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { if (isset($this->podConnections[$storeName], $this->podConnections[$storeName][$podName])) { return $this->getMongoCollection( @@ -769,13 +673,11 @@ public function getCollectionForCBD($storeName, $podName, $readPreference = Read } /** - * @param string $storeName - * @param string $viewId - * @param string $readPreference + * @param int|string $readPreference * * @throws ConfigException */ - public function getCollectionForView($storeName, $viewId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection + public function getCollectionForView(string $storeName, string $viewId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { if (!isset($this->viewSpecs[$storeName][$viewId])) { throw new ConfigException(sprintf("View id '%s' not in configuration for store '%s'", $viewId, $storeName)); @@ -790,13 +692,11 @@ public function getCollectionForView($storeName, $viewId, $readPreference = Read } /** - * @param string $storeName - * @param string $searchDocumentId - * @param string $readPreference + * @param int|string $readPreference * * @throws ConfigException */ - public function getCollectionForSearchDocument($storeName, $searchDocumentId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection + public function getCollectionForSearchDocument(string $storeName, string $searchDocumentId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { if (!isset($this->searchDocSpecs[$storeName][$searchDocumentId])) { throw new ConfigException(sprintf("Search document id '%s' not in configuration for store '%s'", $searchDocumentId, $storeName)); @@ -811,13 +711,11 @@ public function getCollectionForSearchDocument($storeName, $searchDocumentId, $r } /** - * @param string $storeName - * @param string $tableId - * @param string $readPreference + * @param int|string $readPreference * * @throws ConfigException */ - public function getCollectionForTable($storeName, $tableId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection + public function getCollectionForTable(string $storeName, string $tableId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { if (!isset($this->tableSpecs[$storeName][$tableId])) { throw new ConfigException(sprintf("Table id '%s' not in configuration for store '%s'", $tableId, $storeName)); @@ -832,14 +730,13 @@ public function getCollectionForTable($storeName, $tableId, $readPreference = Re } /** - * @param string $storeName - * @param string $readPreference + * @param int|string $readPreference * * @return Collection[] * * @throws ConfigException */ - public function getCollectionsForTables($storeName, array $tables = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): array + public function getCollectionsForTables(string $storeName, array $tables = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): array { if (!isset($this->tableSpecs[$storeName])) { return []; @@ -869,14 +766,13 @@ public function getCollectionsForTables($storeName, array $tables = [], $readPre } /** - * @param string $storeName - * @param string $readPreference + * @param int|string $readPreference * * @return Collection[] * * @throws ConfigException */ - public function getCollectionsForViews($storeName, array $views = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): array + public function getCollectionsForViews(string $storeName, array $views = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): array { if (!isset($this->viewSpecs[$storeName])) { return []; @@ -906,14 +802,13 @@ public function getCollectionsForViews($storeName, array $views = [], $readPrefe } /** - * @param string $storeName - * @param string $readPreference + * @param int|string $readPreference * * @return Collection[] * * @throws ConfigException */ - public function getCollectionsForSearch($storeName, array $searchSpecIds = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): array + public function getCollectionsForSearch(string $storeName, array $searchSpecIds = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): array { if (!isset($this->searchDocSpecs[$storeName])) { return []; @@ -943,12 +838,9 @@ public function getCollectionsForSearch($storeName, array $searchSpecIds = [], $ } /** - * @param string $storeName - * @param string $readPreference - * - * @return Collection + * @param int|string $readPreference */ - public function getCollectionForTTLCache($storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionForTTLCache(string $storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { return $this->getMongoCollection( $this->getDatabase($storeName, $this->dbConfig[$storeName]['data_source'], $readPreference), @@ -957,12 +849,9 @@ public function getCollectionForTTLCache($storeName, $readPreference = ReadPrefe } /** - * @param string $storeName - * @param string $readPreference - * - * @return Collection + * @param int|string $readPreference */ - public function getCollectionForLocks($storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionForLocks(string $storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { return $this->getMongoCollection( $this->getDatabase($storeName, $this->dbConfig[$storeName]['data_source'], $readPreference), @@ -971,12 +860,9 @@ public function getCollectionForLocks($storeName, $readPreference = ReadPreferen } /** - * @param string $storeName - * @param string $readPreference - * - * @return Collection + * @param int|string $readPreference */ - public function getCollectionForManualRollbackAudit($storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionForManualRollbackAudit(string $storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { return $this->getMongoCollection( $this->getDatabase($storeName, $this->dbConfig[$storeName]['data_source'], $readPreference), @@ -985,12 +871,9 @@ public function getCollectionForManualRollbackAudit($storeName, $readPreference } /** - * @param string $storeName - * @param string $readPreference - * - * @return Collection + * @param int|string $readPreference */ - public function getCollectionForJobGroups($storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getCollectionForJobGroups(string $storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection { return $this->getMongoCollection( $this->getDatabase($storeName, $this->dbConfig[$storeName]['data_source'], $readPreference), @@ -999,13 +882,11 @@ public function getCollectionForJobGroups($storeName, $readPreference = ReadPref } /** - * @param string $readPreference - * - * @return Database + * @param int|string $readPreference * * @throws ConfigException */ - public function getTransactionLogDatabase($readPreference = ReadPreference::RP_PRIMARY_PREFERRED) + public function getTransactionLogDatabase($readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Database { $client = $this->getConnectionForDataSource($this->tConfig['data_source']); $db = $client->selectDatabase($this->tConfig['database']); @@ -1013,34 +894,22 @@ public function getTransactionLogDatabase($readPreference = ReadPreference::RP_P return $db->withOptions(['readPreference' => new ReadPreference($readPreference)]); } - /** - * @return string - */ - public static function getDiscoverQueueName() + public static function getDiscoverQueueName(): string { return self::getQueueName(TRIPOD_DISCOVER_QUEUE, 'discover'); } - /** - * @return string - */ - public static function getApplyQueueName() + public static function getApplyQueueName(): string { return self::getQueueName(TRIPOD_APPLY_QUEUE, 'apply'); } - /** - * @return string - */ - public static function getEnsureIndexesQueueName() + public static function getEnsureIndexesQueueName(): string { return self::getQueueName(TRIPOD_ENSURE_INDEXES_QUEUE, 'ensureindexes'); } - /** - * @return string - */ - public static function getResqueServer() + public static function getResqueServer(): string { $resqueServer = self::getenv(RESQUE_SERVER, ''); if (empty($resqueServer)) { @@ -1060,10 +929,8 @@ public static function getResqueServer() /** * @static - * - * @return LoggerInterface */ - public static function getLogger() + public static function getLogger(): LoggerInterface { if (self::$logger == null) { $log = new Logger('TRIPOD'); @@ -1076,7 +943,7 @@ public static function getLogger() /** * Sets the Tripod config. */ - public static function deserialize(array $config) + public static function deserialize(array $config): IConfigInstance { if (isset($config['class'], $config['config'])) { $config = $config['config']; @@ -1090,10 +957,8 @@ public static function deserialize(array $config) /** * Serializes the config into an array that can be passed to jobs, etc. - * - * @return array */ - public function serialize() + public function serialize(): array { return $this->config; } @@ -1102,10 +967,8 @@ public function serialize() * Return the maximum batch size for async operations. * * @param string $operation Async operation, e.g. OP_TABLES, OP_VIEWS - * - * @return int */ - public function getBatchSize($operation) + public function getBatchSize($operation): int { return $this->batchSize[$operation] ?? 1; } @@ -1117,7 +980,7 @@ public function getBatchSize($operation) * * @throws ConfigException */ - protected function loadConfig(array $config) + protected function loadConfig(array $config): void { $this->config = $config; if (isset($config['namespaces'])) { @@ -1317,12 +1180,11 @@ protected function loadConfig(array $config) } /** - * @param int $depth * @param array $spec * * @throws ConfigException */ - protected function validateTableSpecPart(array $spec, $depth = 0) + protected function validateTableSpecPart(array $spec, int $depth = 0): void { $validationLevel = $this->getValidationLevel(); if (!isset($spec['fields']) && !isset($spec['joins']) && !isset($spec['counts']) && !isset($spec['computed_fields'])) { @@ -1426,7 +1288,7 @@ protected function validateTableSpecPart(array $spec, $depth = 0) * @param string[] $availableFields * @param array $spec */ - protected function validateComputedFieldSpec(string $type, array $spec, array $availableFields) + protected function validateComputedFieldSpec(string $type, array $spec, array $availableFields): void { switch ($type) { case 'conditional': @@ -1452,7 +1314,7 @@ protected function validateComputedFieldSpec(string $type, array $spec, array $a * * @throws ConfigException */ - protected function validateComputedConditionalSpec(array $spec, array $availableFields) + protected function validateComputedConditionalSpec(array $spec, array $availableFields): void { if (!isset($spec['if'])) { throw new ConfigException("Computed conditional spec does not contain an 'if' value"); @@ -1527,7 +1389,7 @@ protected function validateComputedConditionalSpec(array $spec, array $available * * @throws ConfigException */ - protected function validateSpecVariableReplacement($value, array $availableFields) + protected function validateSpecVariableReplacement($value, array $availableFields): void { if (is_string($value)) { if (strpos($value, '$') === 0 && !in_array($value, $availableFields)) { @@ -1546,7 +1408,7 @@ protected function validateSpecVariableReplacement($value, array $availableField * * @throws ConfigException */ - protected function validateComputedReplaceSpec(array $spec, array $availableFields) + protected function validateComputedReplaceSpec(array $spec, array $availableFields): void { if (!isset($spec['search'])) { throw new ConfigException("Computed replace spec does not contain 'search' value"); @@ -1571,7 +1433,7 @@ protected function validateComputedReplaceSpec(array $spec, array $availableFiel * * @throws ConfigException */ - protected function validateComputedArithmeticSpec(array $spec, array $availableFields) + protected function validateComputedArithmeticSpec(array $spec, array $availableFields): void { if (count($spec) !== 3) { throw new ConfigException('Computed arithmetic spec must contain 3 values'); @@ -1645,10 +1507,8 @@ protected function getFieldNamesInSpec(array $spec): array /** * Creates an associative array of all predicates/properties associated with all table and search document specifications. - * - * @param string $storename */ - protected function getDefinedPredicatesInSpecs($storename): array + protected function getDefinedPredicatesInSpecs(string $storename): array { $predicates = []; $specs = array_merge($this->getTableSpecifications($storename), $this->getSearchDocumentSpecifications($storename)); @@ -1764,12 +1624,8 @@ protected function getPredicateAliasesFromPredicateProperty($predicate): array /** * When given an array as input, will traverse any predicate functions and return the predicate strings. - * - * @param array $array - * - * @return array */ - protected function getPredicatesFromPredicateFunctions($array) + protected function getPredicatesFromPredicateFunctions(array $array): array { $predicates = []; if (is_array($array)) { @@ -1786,11 +1642,9 @@ protected function getPredicatesFromPredicateFunctions($array) /** * Parses a specDocument's "filter" parameter for any predicates. * - * @param array $filter - * * @return string[] */ - protected function getPredicatesFromFilterCondition($filter): array + protected function getPredicatesFromFilterCondition(array $filter): array { $predicates = []; $regex = '/(^|\b)(\w+\:\w+)\.(l|u)(\b|$)/'; @@ -1819,10 +1673,7 @@ protected function getPredicatesFromFilterCondition($filter): array return $predicates; } - /** - * @return Labeller - */ - protected function getLabeller() + protected function getLabeller(): Labeller { if ($this->labeller == null) { $this->labeller = new Labeller(); @@ -1832,14 +1683,10 @@ protected function getLabeller() } /** - * @param string $dataSource - * - * @return Client - * * @throws ConfigException * @throws ConnectionTimeoutException */ - protected function getConnectionForDataSource($dataSource) + protected function getConnectionForDataSource(string $dataSource): Client { if (!isset($this->dataSources[$dataSource])) { throw new ConfigException(sprintf("Data source '%s' not in configuration", $dataSource)); @@ -1886,10 +1733,8 @@ protected function getConnectionForDataSource($dataSource) /** * Create a Mongo Client - used for mocking. - * - * @param string $connectionString */ - protected function getMongoClient($connectionString, array $connectionOptions = []): Client + protected function getMongoClient(string $connectionString, array $connectionOptions = []): Client { return new Client( $connectionString, @@ -1898,10 +1743,7 @@ protected function getMongoClient($connectionString, array $connectionOptions = ); } - /** - * @return Collection - */ - protected function getMongoCollection(Database $db, string $collectionName) + protected function getMongoCollection(Database $db, string $collectionName): Collection { return $db->selectCollection($collectionName); } @@ -1909,10 +1751,8 @@ protected function getMongoCollection(Database $db, string $collectionName) // PRIVATE FUNCTIONS /** * Returns a unique list of every rdf type configured in the supplied specs' ['type'] restriction. - * - * @param string|null $podName */ - private function getSpecificationTypes(array $specifications, $podName = null): array + private function getSpecificationTypes(array $specifications, ?string $podName = null): array { $types = []; foreach ($specifications as $spec) { @@ -1975,18 +1815,15 @@ private function getMandatoryKey(string $key, array $a, string $configName = 'co return $a[$key]; } - /** - * @return string - */ - private static function getQueueName(string $envVar, string $type) + private static function getQueueName(string $envVar, string $type): string { - $default = (defined('APP_ENV')) ? 'tripod::' . constant('APP_ENV') . ('::' . $type) : 'tripod::' . $type; + $default = defined('APP_ENV') ? 'tripod::' . constant('APP_ENV') . ('::' . $type) : 'tripod::' . $type; return self::getenv($envVar, $default); } /** - * @param bool $default + * @param bool|string $default * * @return bool|string * diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index 2895be82..5d319af3 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -4,8 +4,6 @@ namespace Tripod\Mongo; -// @noinspection PhpIncludeInspection - use MongoDB\BSON\UTCDateTime; use MongoDB\Driver\ReadPreference; use Tripod\Exceptions\Exception; @@ -14,7 +12,6 @@ use Tripod\IDriver; use Tripod\IEventHook; use Tripod\ISearchProvider; -use Tripod\Mongo\Composites\IComposite; use Tripod\Mongo\Composites\SearchIndexer; use Tripod\Mongo\Composites\Tables; use Tripod\Mongo\Composites\Views; @@ -55,16 +52,14 @@ class Driver extends DriverBase implements IDriver /** * Constructor for Driver. * - * @param string $podName - * @param string $storeName - * @param array $opts an Array of options:
    - *
  • defaultContext: (string) to use where a specific default context is not defined. Default is Null
  • - *
  • async: (array) determines the async behaviour of views, tables and search. For each of these array keys, if set to true, generation of these elements will be done asyncronously on save. Default is array(OP_VIEWS=>false,OP_TABLES=>true,OP_SEARCH=>true)
  • - *
  • stat: this sets the stats object to use to record statistics around operations performed by Driver. Default is null
  • - *
  • readPreference: The Read preference to set for Mongo: Default is ReadPreference::RP_PRIMARY_PREFERRED
  • - *
  • retriesToGetLock: Retries to do when unable to get lock on a document, default is 20
+ * @param array $opts an Array of options:
    + *
  • defaultContext: (string) to use where a specific default context is not defined. Default is Null
  • + *
  • async: (array) determines the async behaviour of views, tables and search. For each of these array keys, if set to true, generation of these elements will be done asyncronously on save. Default is array(OP_VIEWS=>false,OP_TABLES=>true,OP_SEARCH=>true)
  • + *
  • stat: this sets the stats object to use to record statistics around operations performed by Driver. Default is null
  • + *
  • readPreference: The Read preference to set for Mongo: Default is ReadPreference::RP_PRIMARY_PREFERRED
  • + *
  • retriesToGetLock: Retries to do when unable to get lock on a document, default is 20
*/ - public function __construct($podName, $storeName, $opts = []) + public function __construct(string $podName, string $storeName, array $opts = []) { $opts = array_merge([ 'defaultContext' => null, @@ -127,10 +122,8 @@ public function __construct($podName, $storeName, $opts = []) * * @param string $resource uri resource you'd like to describe * @param string|null $context string uri of the context, or named graph, you'd like to describe from - * - * @return MongoGraph */ - public function describeResource($resource, $context = null) + public function describeResource(string $resource, ?string $context = null): MongoGraph { $resource = $this->labeller->uri_to_alias($resource); $query = [ @@ -145,12 +138,8 @@ public function describeResource($resource, $context = null) /** * Pass subjects as to $resources and have mongo return a DESCRIBE etc. - * - * @param string|null $context - * - * @return MongoGraph */ - public function describeResources(array $resources, $context = null) + public function describeResources(array $resources, ?string $context = null): MongoGraph { $ids = []; foreach ($resources as $resource) { @@ -166,52 +155,32 @@ public function describeResources(array $resources, $context = null) return $this->fetchGraph($query, MONGO_MULTIDESCRIBE); } - /** - * @param string $resource - * @param string $viewType - * - * @return MongoGraph - */ - public function getViewForResource($resource, $viewType) + public function getViewForResource(?string $resource, string $viewType): MongoGraph { return $this->getTripodViews()->getViewForResource($resource, $viewType); } /** - * @param string $viewType - * - * @return MongoGraph + * @param string[] $resources */ - public function getViewForResources(array $resources, $viewType) + public function getViewForResources(array $resources, string $viewType): MongoGraph { return $this->getTripodViews()->getViewForResources($resources, $viewType); } - /** - * @param string $viewType - * - * @return MongoGraph - */ - public function getViews(array $filter, $viewType) + public function getViews(array $filter, string $viewType): MongoGraph { return $this->getTripodViews()->getViews($filter, $viewType); } - /** - * @param string $tableType - * @param int $offset - * @param int $limit - * - * @return array - */ public function getTableRows( - $tableType, + string $tableType, array $filter = [], array $sortBy = [], - $offset = 0, - $limit = 10, + int $offset = 0, + int $limit = 10, array $options = [] - ) { + ): array { return $this->getTripodTables()->getTableRows( $tableType, $filter, @@ -222,23 +191,12 @@ public function getTableRows( ); } - /** - * @param string $tableType - * @param string|null $resource - * @param string|null $context - */ - public function generateTableRows($tableType, $resource = null, $context = null): void + public function generateTableRows(string $tableType, ?string $resource = null, ?string $context = null): void { $this->getTripodTables()->generateTableRows($tableType, $resource, $context); } - /** - * @param string $tableType - * @param string $fieldName - * - * @return array - */ - public function getDistinctTableColumnValues($tableType, $fieldName, array $filter = []) + public function getDistinctTableColumnValues(string $tableType, string $fieldName, array $filter = []): array { return $this->getTripodTables()->distinct($tableType, $fieldName, $filter); } @@ -246,31 +204,21 @@ public function getDistinctTableColumnValues($tableType, $fieldName, array $filt /** * Create and apply a changeset which is the delta between $oldGraph and $newGraph. * - * @param string $context - * @param string|null $description - * - * @return bool - * * @throws Exception */ public function saveChanges( ExtendedGraph $oldGraph, ExtendedGraph $newGraph, - $context = null, - $description = null - ) { + ?string $context = null, + ?string $description = null + ): bool { return $this->getDataUpdater()->saveChanges($oldGraph, $newGraph, $context, $description); } /** * Get locked documents for a date range or all documents if no date range is given. - * - * @param string $fromDateTime - * @param string $tillDateTime - * - * @return array */ - public function getLockedDocuments($fromDateTime = null, $tillDateTime = null) + public function getLockedDocuments(?string $fromDateTime = null, ?string $tillDateTime = null): array { return $this->getDataUpdater()->getLockedDocuments($fromDateTime, $tillDateTime); } @@ -278,14 +226,9 @@ public function getLockedDocuments($fromDateTime = null, $tillDateTime = null) /** * Remove locks that are there forever, creates a audit entry to keep track who and why removed these locks. * - * @param string $transaction_id - * @param string $reason - * - * @return bool - * * @throws \Exception, if something goes wrong when unlocking documents, or creating audit entries */ - public function removeInertLocks($transaction_id, $reason) + public function removeInertLocks(string $transaction_id, string $reason): bool { return $this->getDataUpdater()->removeInertLocks($transaction_id, $reason); } @@ -308,7 +251,7 @@ public function removeInertLocks($transaction_id, $reason) * @throws Exception - if search provider cannot be found * @throws SearchException - if something goes wrong */ - public function search(array $params) + public function search(array $params): array { $q = $params['q']; $type = $params['type']; @@ -340,13 +283,12 @@ public function search(array $params) /** * Returns a count according to the $query and $groupBy conditions. * - * @param array $query Mongo query object - * @param string|null $groupBy - * @param int|null $ttl acceptable time to live if you're willing to accept a cached version of this request + * @param array $query Mongo query object + * @param int|null $ttl acceptable time to live if you're willing to accept a cached version of this request * * @return array|int */ - public function getCount(array $query, $groupBy = null, $ttl = null) + public function getCount(array $query, ?string $groupBy = null, ?int $ttl = null) { $t = new Timer(); $t->start(); @@ -417,14 +359,11 @@ public function getCount(array $query, $groupBy = null, $ttl = null) * Selects $fields from the result set determined by $query. * Returns an array of all results, each array element is a CBD graph, keyed by r. * - * @param array $fields array of fields, in the same format as prescribed by MongoPHP - * @param int|null $limit - * @param int $offset - * @param string|null $context + * @param array $fields array of fields, in the same format as prescribed by MongoPHP * * @return array> */ - public function select(array $query, array $fields, ?array $sortBy = null, $limit = null, $offset = 0, $context = null): array + public function select(array $query, array $fields, ?array $sortBy = null, ?int $limit = null, int $offset = 0, ?string $context = null): array { $t = new Timer(); $t->start(); @@ -516,12 +455,8 @@ public function select(array $query, array $fields, ?array $sortBy = null, $limi * Returns a graph as the result of $query. Useful replacement for DESCRIBE ... WHERE. * * @deprecated use getGraph - * - * @param $query array - * - * @return MongoGraph */ - public function describe($query) + public function describe(array $query): MongoGraph { return $this->fetchGraph($query, MONGO_DESCRIBE_WITH_CONDITION); } @@ -534,21 +469,16 @@ public function describe($query) * * @param array $filter conditions to filter by * @param array $includeProperties only include these predicates, empty array means return all predicates - * - * @return MongoGraph */ - public function graph(array $filter, array $includeProperties = []) + public function graph(array $filter, array $includeProperties = []): MongoGraph { return $this->fetchGraph($filter, MONGO_GET_GRAPH, null, $includeProperties); } /** - * Retuns the eTag of the $resource, useful for cache control or optimistic concurrency control. - * - * @param string $resource - * @param string|null $context + * Returns the eTag of the $resource, useful for cache control or optimistic concurrency control. */ - public function getETag($resource, $context = null): string + public function getETag(string $resource, ?string $context = null): string { $this->getStat()->increment(MONGO_GET_ETAG); $resource = $this->labeller->uri_to_alias($resource); @@ -575,10 +505,7 @@ public function getETag($resource, $context = null): string return str_pad(number_format($seconds - floor($seconds), 6), 10, '0', STR_PAD_RIGHT) . ' ' . floor($seconds); } - /** - * @return Views - */ - public function getTripodViews() + public function getTripodViews(): Views { if ($this->tripod_views == null) { $this->tripod_views = new Views( @@ -593,10 +520,7 @@ public function getTripodViews() return $this->tripod_views; } - /** - * @return Tables - */ - public function getTripodTables() + public function getTripodTables(): Tables { if ($this->tripod_tables == null) { $this->tripod_tables = new Tables( @@ -611,10 +535,7 @@ public function getTripodTables() return $this->tripod_tables; } - /** - * @return SearchIndexer - */ - public function getSearchIndexer() + public function getSearchIndexer(): SearchIndexer { if ($this->searchIndexer == null) { $this->searchIndexer = new SearchIndexer($this, $this->readPreference); @@ -634,10 +555,8 @@ public function setTransactionLog(TransactionLog $transactionLog): void * * @param string|null $fromDate only transactions after this specified date. This must be a datetime string i.e. '2010-01-15 00:00:00' * @param string|null $toDate only transactions before this specified date. This must be a datetime string i.e. '2010-01-15 00:00:00' - * - * @return bool */ - public function replayTransactionLog($fromDate = null, $toDate = null) + public function replayTransactionLog(?string $fromDate = null, ?string $toDate = null): bool { return $this->getDataUpdater()->replayTransactionLog($fromDate, $toDate); } @@ -645,11 +564,9 @@ public function replayTransactionLog($fromDate = null, $toDate = null) /** * Register an event hook, which will be executed when the event fires. * - * @param string $eventType - * * @throws Exception when an unrecognised event type is given */ - public function registerHook($eventType, IEventHook $hook): void + public function registerHook(string $eventType, IEventHook $hook): void { switch ($eventType) { case IEventHook::EVENT_SAVE_CHANGES: @@ -667,7 +584,7 @@ public function registerHook($eventType, IEventHook $hook): void * * @param $operation string must be either OP_VIEWS, OP_TABLES or OP_SEARCH * - * @return IComposite + * @return SearchIndexer|Tables|Views * * @throws Exception when an unsupported operation is requested */ @@ -698,12 +615,10 @@ protected function getLabeller(): Labeller /** * Returns the delegate object for saving data in Mongo. - * - * @return Updates */ - protected function getDataUpdater() + protected function getDataUpdater(): Updates { - if (!property_exists($this, 'updates') || $this->updates === null) { + if ($this->updates === null) { $readPreference = $this->collection->getReadPreference()->getMode(); $opts = [ diff --git a/src/mongo/IComposite.php b/src/mongo/IComposite.php index 7cf629ee..b7d86a7e 100644 --- a/src/mongo/IComposite.php +++ b/src/mongo/IComposite.php @@ -10,22 +10,16 @@ interface IComposite { /** * Returns the operation this composite can satisfy. - * - * @return string */ - public function getOperationType(); + public function getOperationType(): string; /** * Returns the subjects that this composite will need to regenerate given changes made to the underlying dataset. - * - * @param string $contextAlias - * - * @return mixed */ - public function getImpactedSubjects(array $subjectsAndPredicatesOfChange, $contextAlias); + public function getImpactedSubjects(array $subjectsAndPredicatesOfChange, string $contextAlias): array; /** * Invalidate/regenerate the composite based on the impacted subject. */ - public function update(ImpactedSubject $subject); + public function update(ImpactedSubject $subject): void; } diff --git a/src/mongo/IConfigInstance.php b/src/mongo/IConfigInstance.php index 5d507b7e..bb706e04 100644 --- a/src/mongo/IConfigInstance.php +++ b/src/mongo/IConfigInstance.php @@ -13,15 +13,12 @@ interface IConfigInstance extends ITripodConfigSerializer { - /** - * @return int - */ - public function getMongoCursorTimeout(); + public function getMongoCursorTimeout(): int; /** * @param int $mongoCursorTimeout Timeout in ms */ - public function setMongoCursorTimeout($mongoCursorTimeout); + public function setMongoCursorTimeout(int $mongoCursorTimeout); /** * Returns an array of associated predicates in a table or search document specification @@ -29,26 +26,20 @@ public function setMongoCursorTimeout($mongoCursorTimeout); * * @param string $storename Store name * @param string $specId Composite spec id - * - * @return array */ - public function getDefinedPredicatesInSpec($storename, $specId); + public function getDefinedPredicatesInSpec(string $storename, string $specId): array; /** * Returns an alias curie of the default context (i.e. graph name). - * - * @return string */ - public function getDefaultContextAlias(); + public function getDefaultContextAlias(): string; /** * Returns a list of the configured indexes grouped by collection. * * @param string $storeName Store name - * - * @return array */ - public function getIndexesGroupedByCollection($storeName); + public function getIndexesGroupedByCollection(string $storeName): array; /** * Get the cardinality values for a DB/Collection. @@ -60,59 +51,46 @@ public function getIndexesGroupedByCollection($storeName); * @return array|int if no qname is specified then returns an array of cardinality options, * otherwise returns the cardinality value for the given qname */ - public function getCardinality($storeName, $collName, $qName = null); + public function getCardinality(string $storeName, string $collName, ?string $qName = null); /** * Returns a boolean reflecting whether or not the database and collection are defined in the config. * * @param string $storeName Store name * @param string $pod Pod name - * - * @return bool */ - public function isPodWithinStore($storeName, $pod); + public function isPodWithinStore(string $storeName, string $pod): bool; /** * Returns an array of collection configurations for the supplied database name. * * @param string $storeName Store name - * - * @return array */ - public function getPods($storeName); + public function getPods(string $storeName): array; /** * Returns the name of the data source for the request pod. This may be the default for the store or the pod may * have overridden it in the config. * - * @param string $storeName - * @param string $podName - * - * @return string - * * @throws ConfigException */ - public function getDataSourceForPod($storeName, $podName); + public function getDataSourceForPod(string $storeName, string $podName): string; /** * Return the view specification document for the supplied id, if it exists. * * @param string $storeName Store name * @param string $vid View spec ID - * - * @return array|null */ - public function getViewSpecification($storeName, $vid); + public function getViewSpecification(string $storeName, string $vid): ?array; /** * Returns the search document specification for the supplied id, if it exists. * * @param string $storeName Store name * @param string $sid Search document spec ID - * - * @return array|null */ - public function getSearchDocumentSpecification($storeName, $sid); + public function getSearchDocumentSpecification(string $storeName, string $sid): ?array; /** * Returns an array of all search document specifications, or specification ids. @@ -120,276 +98,216 @@ public function getSearchDocumentSpecification($storeName, $sid); * @param string $storeName Store name * @param string|null $type When supplied, will only return search document specifications that are triggered by this rdf:type * @param bool $justReturnSpecId default is false. If true will only return an array of specification _id's, otherwise returns the array of specification documents - * - * @return array */ - public function getSearchDocumentSpecifications($storeName, $type = null, $justReturnSpecId = false); + public function getSearchDocumentSpecifications(string $storeName, ?string $type = null, bool $justReturnSpecId = false): array; /** * Returns the requested table specification, if it exists. * * @param string $storeName Store name * @param string $tid Table spec ID - * - * @return array|null */ - public function getTableSpecification($storeName, $tid); + public function getTableSpecification(string $storeName, string $tid): ?array; /** * Returns all defined table specifications. * * @param string $storeName Store name - * - * @return array */ - public function getTableSpecifications($storeName); + public function getTableSpecifications(string $storeName): array; /** * Returns all defined view specification. * * @param string $storeName Store name - * - * @return array */ - public function getViewSpecifications($storeName); + public function getViewSpecifications(string $storeName): array; /** * Returns a unique list of every rdf type configured in the view spec ['type'] restriction. * * @param string $storeName Store name * @param string|null $pod Pod name - * - * @return array */ - public function getTypesInViewSpecifications($storeName, $pod = null); + public function getTypesInViewSpecifications(string $storeName, ?string $pod = null): array; /** * Returns a unique list of every rdf type configured in the table spec ['type'] restriction. * * @param string $storeName Store name * @param string|null $pod Pod name - * - * @return array */ - public function getTypesInTableSpecifications($storeName, $pod = null); + public function getTypesInTableSpecifications(string $storeName, ?string $pod = null): array; /** * Returns a unique list of every rdf type configured in the search doc spec ['type'] restriction. * * @param string $storeName Store name * @param string|null $pod Pod name - * - * @return array */ - public function getTypesInSearchSpecifications($storeName, $pod = null); + public function getTypesInSearchSpecifications(string $storeName, ?string $pod = null): array; /** * Returns an array of database names. - * - * @return array */ - public function getDbs(); + public function getDbs(): array; /** * Returns an array of defined namespaces. - * - * @return array */ - public function getNamespaces(); + public function getNamespaces(): array; /** * Getter for transaction log connection config. - * - * @return array */ - public function getTransactionLogConfig(); + public function getTransactionLogConfig(): array; /** * @param string $storeName Store name - * - * @return string|null */ - public function getSearchProviderClassName($storeName); + public function getSearchProviderClassName(string $storeName): ?string; /** * @param string $storeName Store (database) name * @param string|null $dataSource Database server identifier - * @param string $readPreference Mongo read preference - * - * @return Database + * @param int|string $readPreference Mongo read preference * * @throws ConfigException */ - public function getDatabase($storeName, $dataSource = null, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED); + public function getDatabase(string $storeName, ?string $dataSource = null, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Database; /** - * @param string $storeName Store (database) name - * @param string $podName Pod (collection) name - * @param string $readPreference Mongo read preference - * - * @return Collection + * @param string $storeName Store (database) name + * @param string $podName Pod (collection) name + * @param int|string $readPreference Mongo read preference * * @throws ConfigException */ - public function getCollectionForCBD($storeName, $podName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED); + public function getCollectionForCBD(string $storeName, string $podName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection; /** - * @param string $storeName Store (database) name - * @param string $viewId View spec ID - * @param string $readPreference Mongo read preference - * - * @return Collection + * @param string $storeName Store (database) name + * @param string $viewId View spec ID + * @param int|string $readPreference Mongo read preference * * @throws ConfigException */ - public function getCollectionForView($storeName, $viewId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED); + public function getCollectionForView(string $storeName, string $viewId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection; /** - * @param string $storeName Store (database) name - * @param string $searchDocumentId Search document spec ID - * @param string $readPreference Mongo read preference - * - * @return Collection + * @param string $storeName Store (database) name + * @param string $searchDocumentId Search document spec ID + * @param int|string $readPreference Mongo read preference * * @throws ConfigException */ public function getCollectionForSearchDocument( - $storeName, - $searchDocumentId, + string $storeName, + string $searchDocumentId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED - ); + ): Collection; /** - * @param string $storeName Store (database) name - * @param string $tableId Table spec ID - * @param string $readPreference Mongo read preference - * - * @return Collection + * @param string $storeName Store (database) name + * @param string $tableId Table spec ID + * @param int|string $readPreference Mongo read preference * * @throws ConfigException */ - public function getCollectionForTable($storeName, $tableId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED); + public function getCollectionForTable(string $storeName, string $tableId, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection; /** - * @param string $storeName Store (database) name - * @param array $tables Array of table spec IDs - * @param string $readPreference Mongo read preference + * @param string $storeName Store (database) name + * @param array $tables Array of table spec IDs + * @param int|string $readPreference Mongo read preference * * @return Collection[] * * @throws ConfigException */ public function getCollectionsForTables( - $storeName, + string $storeName, array $tables = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED - ); + ): array; /** - * @param string $storeName Store (database) name - * @param array $views Array of view spec IDs - * @param string $readPreference Mongo read preference + * @param string $storeName Store (database) name + * @param array $views Array of view spec IDs + * @param int|string $readPreference Mongo read preference * * @return Collection[] * * @throws ConfigException */ public function getCollectionsForViews( - $storeName, + string $storeName, array $views = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED - ); + ): array; /** - * @param string $storeName Store (database) name - * @param array $searchSpecIds Array of search document spec IDs - * @param string $readPreference Mongo read preference + * @param string $storeName Store (database) name + * @param array $searchSpecIds Array of search document spec IDs + * @param int|string $readPreference Mongo read preference * * @return Collection[] * * @throws ConfigException */ public function getCollectionsForSearch( - $storeName, + string $storeName, array $searchSpecIds = [], $readPreference = ReadPreference::RP_PRIMARY_PREFERRED - ); + ): array; /** - * @param string $storeName Store (database) name - * @param string $readPreference Mongo read preference - * - * @return Collection + * @param string $storeName Store (database) name + * @param int|string $readPreference Mongo read preference */ - public function getCollectionForTTLCache($storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED); + public function getCollectionForTTLCache(string $storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection; /** - * @param string $storeName - * @param string $readPreference - * - * @return Collection + * @param int|string $readPreference */ - public function getCollectionForLocks($storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED); + public function getCollectionForLocks(string $storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection; /** - * @param string $storeName Store (database) name - * @param string $readPreference Mongo read preference - * - * @return Collection + * @param string $storeName Store (database) name + * @param int|string $readPreference Mongo read preference */ public function getCollectionForManualRollbackAudit( - $storeName, + string $storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED - ); + ): Collection; /** - * @param string $storeName Store (database) name - * @param string $readPreference Mongo read preference - * - * @return Collection + * @param string $storeName Store (database) name + * @param int|string $readPreference Mongo read preference */ - public function getCollectionForJobGroups($storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED); + public function getCollectionForJobGroups(string $storeName, $readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Collection; /** - * @param $readPreference Mongo read preference - * - * @return Database + * @param int|string $readPreference Mongo read preference * * @throws ConfigException */ - public function getTransactionLogDatabase($readPreference = ReadPreference::RP_PRIMARY_PREFERRED); + public function getTransactionLogDatabase($readPreference = ReadPreference::RP_PRIMARY_PREFERRED): Database; /** * Return the maximum batch size for async operations. * * @param string $operation Async operation, e.g. OP_TABLES, OP_VIEWS - * - * @return int */ - public function getBatchSize($operation); + public function getBatchSize(string $operation): int; - /** - * @return string - */ - public static function getDiscoverQueueName(); + public static function getDiscoverQueueName(): string; - /** - * @return string - */ - public static function getApplyQueueName(); + public static function getApplyQueueName(): string; - /** - * @return string - */ - public static function getEnsureIndexesQueueName(); + public static function getEnsureIndexesQueueName(): string; - /** - * @return string - */ - public static function getResqueServer(); + public static function getResqueServer(): string; - /** - * @return LoggerInterface - */ - public static function getLogger(); + public static function getLogger(): LoggerInterface; } diff --git a/src/mongo/base/CompositeBase.php b/src/mongo/base/CompositeBase.php index 679f0537..65ebde3a 100644 --- a/src/mongo/base/CompositeBase.php +++ b/src/mongo/base/CompositeBase.php @@ -20,11 +20,9 @@ abstract class CompositeBase extends DriverBase implements IComposite /** * Returns an array of ImpactedSubjects based on the subjects and predicates of change. * - * @param string $contextAlias - * * @return ImpactedSubject[] */ - public function getImpactedSubjects(array $subjectsAndPredicatesOfChange, $contextAlias) + public function getImpactedSubjects(array $subjectsAndPredicatesOfChange, string $contextAlias): array { $candidates = []; $filter = []; @@ -128,27 +126,18 @@ public function getImpactedSubjects(array $subjectsAndPredicatesOfChange, $conte /** * Returns an array of the rdf types that will trigger the specification. - * - * @return array */ - abstract public function getTypesInSpecifications(); + abstract public function getTypesInSpecifications(): array; /** - * @param string $contextAlias - * - * @return mixed + * @return mixed[] */ - abstract public function findImpactedComposites(array $resourcesAndPredicates, $contextAlias); + abstract public function findImpactedComposites(array $resourcesAndPredicates, string $contextAlias): array; /** * Returns the specification config. - * - * @param string $storeName - * @param string $specId The specification id - * - * @return array|null */ - abstract public function getSpecification($storeName, $specId); + abstract public function getSpecification(string $storeName, string $specId): ?array; /** * Test if the a particular type appears in the array of types associated with a particular spec and that the changeset diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 324a56bb..3c569841 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -63,10 +63,7 @@ public function update(ImpactedSubject $subject): void ); } - /** - * @return array - */ - public function getTypesInSpecifications() + public function getTypesInSpecifications(): array { return $this->config->getTypesInSearchSpecifications($this->storeName, $this->getPodName()); } @@ -79,13 +76,7 @@ public function getOperationType(): string return OP_SEARCH; } - /** - * @param string $storeName - * @param string $specId - * - * @return array|null - */ - public function getSpecification($storeName, $specId) + public function getSpecification(string $storeName, string $specId): ?array { return $this->config->getSearchDocumentSpecification($storeName, $specId); } @@ -263,13 +254,11 @@ public function generateSearchDocuments( } /** - * @param string $context - * - * @return array|mixed + * @return mixed[] */ - public function findImpactedComposites(array $resourcesAndPredicates, $context) + public function findImpactedComposites(array $resourcesAndPredicates, string $contextAlias): array { - return $this->getSearchProvider()->findImpactedDocuments($resourcesAndPredicates, $context); + return $this->getSearchProvider()->findImpactedDocuments($resourcesAndPredicates, $contextAlias); } /** diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index ec442761..90616cf3 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -117,10 +117,8 @@ public function update(ImpactedSubject $subject): void /** * Returns an array of the rdf types that will trigger the table specification. - * - * @return array */ - public function getTypesInSpecifications() + public function getTypesInSpecifications(): array { return $this->config->getTypesInTableSpecifications($this->storeName, $this->getPodName()); } @@ -128,9 +126,9 @@ public function getTypesInSpecifications() /** * Returns an array of table rows that are impacted by the changes. * - * @param string $contextAlias + * @return mixed[] */ - public function findImpactedComposites(array $resourcesAndPredicates, $contextAlias): array + public function findImpactedComposites(array $resourcesAndPredicates, string $contextAlias): array { $contextAlias = $this->getContextAlias($contextAlias); // belt and braces @@ -209,13 +207,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl return $affectedTableRows; } - /** - * @param string $storeName - * @param string $tableSpecId - * - * @return array|null - */ - public function getSpecification($storeName, $tableSpecId) + public function getSpecification(string $storeName, string $tableSpecId): ?array { return $this->config->getTableSpecification($storeName, $tableSpecId); } diff --git a/src/mongo/delegates/Views.php b/src/mongo/delegates/Views.php index fcec5bed..d16b5285 100644 --- a/src/mongo/delegates/Views.php +++ b/src/mongo/delegates/Views.php @@ -8,6 +8,7 @@ use MongoDB\Collection; use MongoDB\Driver\ReadPreference; use Tripod\Exceptions\ViewException; +use Tripod\ExtendedGraph; use Tripod\ITripodStat; use Tripod\Mongo\DateUtil; use Tripod\Mongo\ImpactedSubject; @@ -22,11 +23,9 @@ class Views extends CompositeBase * Construct accepts actual objects rather than strings as this class is a delegate of * Tripod and should inherit connections set up there. * - * @param string $storeName - * @param string|null $defaultContext - * @param string $readPreference + * @param int|string $readPreference */ - public function __construct($storeName, Collection $collection, $defaultContext, ?ITripodStat $stat = null, $readPreference = ReadPreference::RP_PRIMARY) + public function __construct(string $storeName, Collection $collection, ?string $defaultContext, ?ITripodStat $stat = null, $readPreference = ReadPreference::RP_PRIMARY) { $this->storeName = $storeName; $this->labeller = new Labeller(); @@ -57,20 +56,15 @@ public function update(ImpactedSubject $subject): void $this->generateViews([$resourceUri], $context); } - /** - * @return array - */ - public function getTypesInSpecifications() + public function getTypesInSpecifications(): array { return $this->config->getTypesInViewSpecifications($this->storeName, $this->getPodName()); } /** - * @param string $contextAlias - * * @return mixed[] */ - public function findImpactedComposites(array $resourcesAndPredicates, $contextAlias): array + public function findImpactedComposites(array $resourcesAndPredicates, string $contextAlias): array { // This should never happen, but in the event that we have been passed an empty array or something if ($resourcesAndPredicates === []) { @@ -129,13 +123,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, $contextAl return $affectedViews; } - /** - * @param string $storeName - * @param string $viewSpecId - * - * @return array|null - */ - public function getSpecification($storeName, $viewSpecId) + public function getSpecification(string $storeName, string $viewSpecId): ?array { return $this->config->getViewSpecification($storeName, $viewSpecId); } @@ -143,12 +131,9 @@ public function getSpecification($storeName, $viewSpecId) /** * Return all views, restricted by $filter conditions, for given $viewType. * - * @param array $filter - an array, keyed by predicate, to filter by - * @param mixed $viewType - * - * @return MongoGraph + * @param array $filter - an array, keyed by predicate, to filter by */ - public function getViews(array $filter, $viewType) + public function getViews(array $filter, string $viewType): MongoGraph { $query = ['_id.type' => $viewType]; foreach ($filter as $predicate => $object) { @@ -173,13 +158,8 @@ public function getViews(array $filter, $viewType) /** * For given $resource, return the view of type $viewType. - * - * @param string|null $resource - * @param string|null $context - * - * @return MongoGraph */ - public function getViewForResource($resource, string $viewType, $context = null) + public function getViewForResource(?string $resource, string $viewType, ?string $context = null): MongoGraph { if (empty($resource)) { return new MongoGraph(); @@ -220,13 +200,8 @@ public function getViewForResource($resource, string $viewType, $context = null) /** * For given $resources, return the views of type $viewType. - * - * @param string $viewType - * @param string|null $context - * - * @return MongoGraph */ - public function getViewForResources(array $resources, $viewType, $context = null) + public function getViewForResources(array $resources, string $viewType, ?string $context = null): MongoGraph { $contextAlias = $this->getContextAlias($context); @@ -278,11 +253,8 @@ public function getViewForResources(array $resources, $viewType, $context = null /** * Autodiscovers the multiple view specification that may be applicable for a given resource, and submits each for generation. - * - * @param array $resources - * @param string|null $context */ - public function generateViews($resources, $context = null): void + public function generateViews(array $resources, ?string $context = null): void { $contextAlias = $this->getContextAlias($context); @@ -328,13 +300,9 @@ public function generateViews($resources, $context = null): void /** * This method finds all the view specs for the given $rdfType and generates the views for the $resource one by one. * - * @param string $rdfType - * @param string|null $resource - * @param string|null $context - * * @throws \Exception */ - public function generateViewsForResourcesOfType($rdfType, $resource = null, $context = null): void + public function generateViewsForResourcesOfType(string $rdfType, ?string $resource = null, ?string $context = null): void { $rdfType = $this->labeller->qname_to_alias($rdfType); $rdfTypeAlias = $this->labeller->uri_to_alias($rdfType); @@ -362,8 +330,8 @@ public function generateViewsForResourcesOfType($rdfType, $resource = null, $con /** * This method will delete all views where the _id.type of the viewmatches the specified $viewId. * - * @param string $viewId View spec ID - * @param UTCDateTime|null $timestamp Optional timestamp to delete all views that are older than + * @param string $viewId View spec ID + * @param int|UTCDateTime|null $timestamp Optional timestamp to delete all views that are older than * * @return int The number of views deleted */ @@ -397,13 +365,11 @@ public function deleteViewsByViewId(string $viewId, $timestamp = null) /** * Given a specific $viewId, generates a single view for the $resource. * - * @param string|null $resource - * @param string|null $context * @param string|null $queueName Queue for background bulk generation * * @throws ViewException */ - public function generateView(string $viewId, $resource = null, $context = null, $queueName = null): ?array + public function generateView(string $viewId, ?string $resource = null, ?string $context = null, ?string $queueName = null): ?array { $contextAlias = $this->getContextAlias($context); $viewSpec = $this->getConfigInstance()->getViewSpecification($this->storeName, $viewId); @@ -532,10 +498,8 @@ public function generateView(string $viewId, $resource = null, $context = null, * * @param string $viewSpec View spec ID * @param array $filters Query filters to get count on - * - * @return int */ - public function count($viewSpec, array $filters = []) + public function count(string $viewSpec, array $filters = []): int { $filters['_id.type'] = $viewSpec; @@ -649,13 +613,8 @@ protected function doJoins(array $source, $joins, array &$dest, $from, $contextA /** * Check to see if a linkMatch matches a filter. - * - * @param string $linkMatchType - * @param string $linkMatchValue - * @param string $filterType - * @param string $filterMatch */ - protected function matchesFilter($linkMatchType, $linkMatchValue, $filterType, $filterMatch): bool + protected function matchesFilter(string $linkMatchType, string $linkMatchValue, string $filterType, string $filterMatch): bool { if ($linkMatchType !== $filterType) { return false; @@ -668,11 +627,10 @@ protected function matchesFilter($linkMatchType, $linkMatchValue, $filterType, $ * Returns a document with properties extracted from $source, according to $viewSpec. Useful for partial representations * of CBDs in a view. * - * @param mixed $source + * @param array $source * @param array $viewSpec - * @param mixed $from */ - protected function extractProperties(array $source, array $viewSpec, $from): array + protected function extractProperties(array $source, array $viewSpec, string $from): array { $obj = []; if (isset($viewSpec['include'])) { diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index de08cd7d..0abad686 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -2359,7 +2359,7 @@ class TripodDriverTestConfig extends Tripod\Mongo\Config */ public function __construct() {} - protected function loadConfig(array $config) + protected function loadConfig(array $config): void { parent::loadConfig($config); } diff --git a/test/unit/mongo/MongoTripodTestBase.php b/test/unit/mongo/MongoTripodTestBase.php index fb61a8f2..76a0ffe2 100644 --- a/test/unit/mongo/MongoTripodTestBase.php +++ b/test/unit/mongo/MongoTripodTestBase.php @@ -423,7 +423,7 @@ class TripodTestConfig extends Tripod\Mongo\Config */ public function __construct() {} - public function loadConfig(array $config) + public function loadConfig(array $config): void { parent::loadConfig($config); } diff --git a/test/unit/mongo/TestConfigGenerator.php b/test/unit/mongo/TestConfigGenerator.php index 4f23a1a2..141c85ea 100644 --- a/test/unit/mongo/TestConfigGenerator.php +++ b/test/unit/mongo/TestConfigGenerator.php @@ -1,6 +1,7 @@ get_class($this), 'filename' => $this->fileName]; } - public static function deserialize(array $config) + public static function deserialize(array $config): IConfigInstance { $instance = new self(); $instance->fileName = $config['filename']; From f5be98e9e5af2008b6b3d9d35e6ad1311c340071 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Wed, 11 Mar 2026 23:03:56 +0000 Subject: [PATCH 27/56] Fix test --- test/unit/mongo/MongoTripodSearchIndexerTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/unit/mongo/MongoTripodSearchIndexerTest.php b/test/unit/mongo/MongoTripodSearchIndexerTest.php index 31c664a5..9220eca1 100644 --- a/test/unit/mongo/MongoTripodSearchIndexerTest.php +++ b/test/unit/mongo/MongoTripodSearchIndexerTest.php @@ -531,10 +531,11 @@ public function testBatchSearchDocumentsGeneration(): void $configInstance->expects($this->atLeastOnce())->method('getCollectionForCBD')->willReturn($collection); $tripod = $this->getMockBuilder(Driver::class) - ->onlyMethods(['getConfigInstance']) - ->setConstructorArgs(['tripod_php_testing', 'CBD_testing']) + ->onlyMethods(['getStoreName']) + ->setConstructorArgs(['CBD_testing', 'tripod_php_testing']) ->disableOriginalConstructor() ->getMock(); + $tripod->expects($this->atLeastOnce())->method('getStoreName')->willReturn('tripod_php_testing'); $search = $this->getMockBuilder(SearchIndexer::class) ->onlyMethods(['setSearchProvider', 'getConfigInstance', 'queueApplyJob', 'getJobGroup']) From a87df41e5b0fb2ff5bee01674ae575c5ca65413d Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Wed, 11 Mar 2026 23:44:21 +0000 Subject: [PATCH 28/56] Apply rector #2 --- scripts/mongo/createSearchDocuments.php | 11 +- scripts/mongo/createTables.php | 9 +- scripts/mongo/createViews.php | 8 +- scripts/mongo/detectNamespaces.php | 62 +------- scripts/mongo/discoverUnnamespacedUris.php | 2 + scripts/mongo/loadTriples.php | 3 +- scripts/mongo/triplesToBSON.php | 1 + src/IDriver.php | 2 - src/classes/ChangeSet.php | 20 ++- src/classes/ExtendedGraph.php | 138 +++++++++--------- src/classes/Labeller.php | 10 +- src/classes/StatsD.php | 19 +-- src/mongo/Config.php | 37 ++--- src/mongo/Driver.php | 15 +- src/mongo/Labeller.php | 2 +- src/mongo/MongoGraph.php | 12 +- src/mongo/base/CompositeBase.php | 4 +- src/mongo/base/DriverBase.php | 8 +- src/mongo/delegates/SearchDocuments.php | 5 +- src/mongo/delegates/SearchIndexer.php | 3 +- src/mongo/delegates/Tables.php | 24 ++- src/mongo/delegates/Updates.php | 32 ++-- src/mongo/delegates/Views.php | 11 +- src/mongo/jobs/ApplyOperation.php | 2 +- src/mongo/providers/MongoSearchProvider.php | 12 +- src/mongo/serializers/NQuadSerializer.php | 12 ++ src/mongo/util/IndexUtils.php | 2 +- src/mongo/util/TriplesUtil.php | 17 +-- .../mongo/MongoTripodPerformanceTestBase.php | 2 +- test/stubs.php | 4 +- test/unit/ExtendedGraphTest.php | 97 ++++++------ test/unit/mongo/ConfigGeneratorTest.php | 2 +- test/unit/mongo/MongoGraphTest.php | 10 +- test/unit/mongo/MongoTransactionLogTest.php | 2 +- test/unit/mongo/MongoTripodConfigUnitTest.php | 8 +- .../mongo/MongoTripodNQuadSerializerTest.php | 2 +- test/unit/mongo/MongoTripodStatTest.php | 4 +- test/unit/mongo/MongoTripodTablesTest.php | 12 +- test/unit/mongo/MongoTripodTestBase.php | 27 ++-- .../MongoTripodTransactionRollbackTest.php | 2 +- test/unit/mongo/TriplesUtilTest.php | 2 +- 41 files changed, 266 insertions(+), 391 deletions(-) diff --git a/scripts/mongo/createSearchDocuments.php b/scripts/mongo/createSearchDocuments.php index d49be645..f2c8d475 100644 --- a/scripts/mongo/createSearchDocuments.php +++ b/scripts/mongo/createSearchDocuments.php @@ -1,7 +1,7 @@ getSearchDocumentSpecification($storeName, $specId); if (array_key_exists('from', $spec)) { diff --git a/scripts/mongo/createTables.php b/scripts/mongo/createTables.php index 19db8395..8ad3894f 100644 --- a/scripts/mongo/createTables.php +++ b/scripts/mongo/createTables.php @@ -59,13 +59,10 @@ function showUsage(): void require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; /** - * @param string|null $id - * @param string|null $tableId - * @param string|null $storeName - * @param ITripodStat|null $stat - * @param string|null $queue + * @param string|null $tableId + * @param string|null $storeName */ -function generateTables($id, $tableId, $storeName, $stat = null, $queue = null): void +function generateTables(?string $id, string $tableId, string $storeName, ?ITripodStat $stat = null, ?string $queue = null): void { $tableSpec = Config::getInstance()->getTableSpecification($storeName, $tableId); if (array_key_exists('from', $tableSpec)) { diff --git a/scripts/mongo/createViews.php b/scripts/mongo/createViews.php index 7114302a..e3d78c36 100644 --- a/scripts/mongo/createViews.php +++ b/scripts/mongo/createViews.php @@ -59,13 +59,9 @@ function showUsage(): void require_once dirname(__FILE__, 3) . '/src/tripod.inc.php'; /** - * @param string|null $id - * @param string|null $viewId - * @param string $storeName - * @param ITripodStat|null $stat - * @param string $queue + * @param string|null $viewId */ -function generateViews($id, $viewId, $storeName, $stat, $queue): void +function generateViews(?string $id, string $viewId, string $storeName, ?ITripodStat $stat = null, ?string $queue = null): void { $viewSpec = Config::getInstance()->getViewSpecification($storeName, $viewId); if (array_key_exists('from', $viewSpec)) { diff --git a/scripts/mongo/detectNamespaces.php b/scripts/mongo/detectNamespaces.php index 8c22091a..dc3f6a5a 100644 --- a/scripts/mongo/detectNamespaces.php +++ b/scripts/mongo/detectNamespaces.php @@ -71,7 +71,7 @@ $currentSubject = $subject; } elseif ($currentSubject != $subject) { // once subject changes, we have all triples for that subject, flush to Mongo $ns = $util->extractMissingPredicateNs($triples); - if (count($ns) > 0) { + if ($ns !== []) { $newNsConfig = []; foreach ($ns as $n) { $prefix = $util->suggestPrefix($n); @@ -87,7 +87,7 @@ } $ns = $util->extractMissingObjectNs($triples); - if (count($ns) > 0) { + if ($ns !== []) { $newNsConfig = []; foreach ($ns as $n) { if (array_key_exists($n, $objectNs)) { @@ -118,60 +118,4 @@ } echo "Suggested namespace configuration:\n\n"; - -/** - * @param string $json - */ -function indent($json): string -{ - $result = ''; - $pos = 0; - $strLen = strlen($json); - $indentStr = ' '; - $newLine = "\n"; - $prevChar = ''; - $outOfQuotes = true; - - for ($i = 0; $i <= $strLen; $i++) { - // Grab the next character in the string. - $char = substr($json, $i, 1); - - // Are we inside a quoted string? - if ($char === '"' && $prevChar !== '\\') { - $outOfQuotes = !$outOfQuotes; - - // If this character is the end of an element, - // output a new line and indent the next line. - } elseif (($char === '}' || $char === ']') && $outOfQuotes) { - $result .= $newLine; - $pos--; - for ($j = 0; $j < $pos; $j++) { - $result .= $indentStr; - } - } - - // Add the character to the result string. - $result .= $char; - - // If the last character was the beginning of an element, - // output a new line and indent the next line. - if (in_array($char, [',', '{', '[']) && $outOfQuotes) { - $result .= $newLine; - if ($char === '{' || $char === '[') { - $pos++; - } - - for ($j = 0; $j < $pos; $j++) { - $result .= $indentStr; - } - } - - $prevChar = $char; - } - - return $result; -} - -$json = json_encode(['namespaces' => $config['namespaces']]); - -echo indent($json); +echo json_encode(['namespaces' => $config['namespaces']], JSON_PRETTY_PRINT); diff --git a/scripts/mongo/discoverUnnamespacedUris.php b/scripts/mongo/discoverUnnamespacedUris.php index 04dccf8d..48e92dda 100644 --- a/scripts/mongo/discoverUnnamespacedUris.php +++ b/scripts/mongo/discoverUnnamespacedUris.php @@ -72,9 +72,11 @@ function isUnNamespaced($uri, $baseUri = null): bool if (!isset($v['u'])) { continue; } + if (!isUnNamespaced($v['u'], $argv[2] ?? null)) { continue; } + echo sprintf(' Un-namespaced object uri (multiple value): %s%s', $v['u'], PHP_EOL); $count++; } diff --git a/scripts/mongo/loadTriples.php b/scripts/mongo/loadTriples.php index 540bf302..a7077460 100644 --- a/scripts/mongo/loadTriples.php +++ b/scripts/mongo/loadTriples.php @@ -9,9 +9,8 @@ /** * @param string $podName - * @param string $storeName */ -function load(TriplesUtil $loader, string $subject, array $triples, array &$errors, $podName, $storeName): void +function load(TriplesUtil $loader, string $subject, array $triples, array &$errors, $podName, string $storeName): void { try { $loader->loadTriplesAbout($subject, $triples, $storeName, $podName); diff --git a/scripts/mongo/triplesToBSON.php b/scripts/mongo/triplesToBSON.php index 84f76d20..b9220daa 100644 --- a/scripts/mongo/triplesToBSON.php +++ b/scripts/mongo/triplesToBSON.php @@ -11,6 +11,7 @@ exit; } + array_shift($argv); $config = json_decode(file_get_contents($argv[0]), true); diff --git a/src/IDriver.php b/src/IDriver.php index 2b9fa0d0..da8ee76e 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -14,8 +14,6 @@ interface IDriver * * @param array $filter conditions to filter by * @param array $includeProperties only include these predicates, empty array means return all predicates - * - * @return mixed */ public function graph(array $filter, array $includeProperties = []): ExtendedGraph; diff --git a/src/classes/ChangeSet.php b/src/classes/ChangeSet.php index b65ae7e8..f5eac9b3 100644 --- a/src/classes/ChangeSet.php +++ b/src/classes/ChangeSet.php @@ -156,18 +156,16 @@ protected function __init() and linking to the Statements from the appropriate changeset */ $reifiedAdditions = ExtendedGraph::reify($additions, 'Add'); - if (!empty($reifiedAdditions)) { - foreach ($reifiedAdditions as $nodeID => $props) { - $subject = $props['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject'][0]['value']; - if (in_array($subject, $subjectIndex)) { - $csID = $csIndex[$subject]; - $this->addT($csID, $CSNS . 'addition', $nodeID, 'bnode'); - } + foreach ($reifiedAdditions as $nodeID => $props) { + $subject = $props['http://www.w3.org/1999/02/22-rdf-syntax-ns#subject'][0]['value']; + if (in_array($subject, $subjectIndex)) { + $csID = $csIndex[$subject]; + $this->addT($csID, $CSNS . 'addition', $nodeID, 'bnode'); + } - // if dc:source is given in the instantiating arguments, add it to the statement as provenance - if (isset($this->a['http://purl.org/dc/terms/source'])) { - $this->addT($nodeID, 'http://purl.org/dc/terms/source', $this->a['http://purl.org/dc/terms/source'], 'uri'); - } + // if dc:source is given in the instantiating arguments, add it to the statement as provenance + if (isset($this->a['http://purl.org/dc/terms/source'])) { + $this->addT($nodeID, 'http://purl.org/dc/terms/source', $this->a['http://purl.org/dc/terms/source'], 'uri'); } } diff --git a/src/classes/ExtendedGraph.php b/src/classes/ExtendedGraph.php index ce00d7a5..c7bf1616 100644 --- a/src/classes/ExtendedGraph.php +++ b/src/classes/ExtendedGraph.php @@ -326,85 +326,83 @@ public function to_html($s = null, bool $guess_labels = true): string $subjects = $this->get_subjects(); } - if (count($subjects) > 0) { - foreach ($subjects as $subject) { - if (count($subjects) > 1) { - $h .= '

' . htmlspecialchars($this->get_label($subject)) . '

' . "\n"; - } + foreach ($subjects as $subject) { + if (count($subjects) > 1) { + $h .= '

' . htmlspecialchars($this->get_label($subject)) . '

' . "\n"; + } - $h .= '
' . htmlspecialchars($this->get_label($p, true)) . ''; - for ($i = 0; $i < count($this->_index[$subject][$p]); $i++) { + $counter = count($this->_index[$subject][$p]); + for ($i = 0; $i < $counter; $i++) { if ($i > 0) { $h .= '
'; } + if ($this->_index[$subject][$p][$i]['type'] === 'literal') { $h .= htmlspecialchars($this->_index[$subject][$p][$i]['value']); } else { @@ -343,6 +354,7 @@ public function to_html($s = null, $guess_labels = true) $h .= ''; } } + $h .= '
' . htmlspecialchars($this->get_inverse_label($backlink_p, true)) . ''; - for ($i = 0; $i < count($backlink_values); $i++) { + $counter = count($backlink_values); + for ($i = 0; $i < $counter; $i++) { if ($i > 0) { $h .= '
'; } @@ -378,6 +392,7 @@ public function to_html($s = null, $guess_labels = true) $h .= ''; } + $h .= '
' . "\n"; + $h .= '
' . "\n"; - $properties = $this->get_subject_properties($subject, true); - $priority_properties = array_intersect($properties, $this->_property_order); - $properties = array_merge($priority_properties, array_diff($properties, $priority_properties)); + $properties = $this->get_subject_properties($subject, true); + $priority_properties = array_intersect($properties, $this->_property_order); + $properties = array_merge($priority_properties, array_diff($properties, $priority_properties)); - foreach ($properties as $p) { - $h .= ''; - $h .= ''; + $h .= ''; - $h .= '' . "\n"; + $h .= ''; + } } - $backlinks = []; - foreach ($this->_index as $rev_subj => $rev_subj_info) { - foreach ($rev_subj_info as $rev_subj_p => $rev_subj_p_list) { - foreach ($rev_subj_p_list as $rev_value) { - if (($rev_value['type'] == 'uri' || $rev_value['type'] == 'bnode') && $rev_value['value'] === $subject) { - if (!isset($backlinks[$rev_subj_p])) { - $backlinks[$rev_subj_p] = []; - } + $h .= ''; + $h .= '' . "\n"; + } - $backlinks[$rev_subj_p][] = $rev_subj; + $backlinks = []; + foreach ($this->_index as $rev_subj => $rev_subj_info) { + foreach ($rev_subj_info as $rev_subj_p => $rev_subj_p_list) { + foreach ($rev_subj_p_list as $rev_value) { + if (($rev_value['type'] == 'uri' || $rev_value['type'] == 'bnode') && $rev_value['value'] === $subject) { + if (!isset($backlinks[$rev_subj_p])) { + $backlinks[$rev_subj_p] = []; } + + $backlinks[$rev_subj_p][] = $rev_subj; } } } + } - foreach ($backlinks as $backlink_p => $backlink_values) { - $h .= ''; - $h .= ''; + $h .= ''; - $h .= '' . "\n"; + $h .= ''; } - $h .= '
' . htmlspecialchars($this->get_label($p, true)) . ''; - $counter = count($this->_index[$subject][$p]); - for ($i = 0; $i < $counter; $i++) { - if ($i > 0) { - $h .= '
'; - } + foreach ($properties as $p) { + $h .= '
' . htmlspecialchars($this->get_label($p, true)) . ''; + $counter = count($this->_index[$subject][$p]); + for ($i = 0; $i < $counter; $i++) { + if ($i > 0) { + $h .= '
'; + } - if ($this->_index[$subject][$p][$i]['type'] === 'literal') { - $h .= htmlspecialchars($this->_index[$subject][$p][$i]['value']); + if ($this->_index[$subject][$p][$i]['type'] === 'literal') { + $h .= htmlspecialchars($this->_index[$subject][$p][$i]['value']); + } else { + $h .= ''; + if ($guess_labels) { + $h .= htmlspecialchars($this->get_label($this->_index[$subject][$p][$i]['value'])); } else { - $h .= ''; - if ($guess_labels) { - $h .= htmlspecialchars($this->get_label($this->_index[$subject][$p][$i]['value'])); - } else { - $h .= htmlspecialchars($this->_index[$subject][$p][$i]['value']); - } - - $h .= ''; + $h .= htmlspecialchars($this->_index[$subject][$p][$i]['value']); } - } - $h .= '
' . htmlspecialchars($this->get_inverse_label($backlink_p, true)) . ''; - $counter = count($backlink_values); - for ($i = 0; $i < $counter; $i++) { - if ($i > 0) { - $h .= '
'; - } - - $h .= ''; - if ($guess_labels) { - $h .= htmlspecialchars($this->get_label($backlink_values[$i])); - } else { - $h .= htmlspecialchars($backlink_values[$i]); - } + foreach ($backlinks as $backlink_p => $backlink_values) { + $h .= '
' . htmlspecialchars($this->get_inverse_label($backlink_p, true)) . ''; + $counter = count($backlink_values); + for ($i = 0; $i < $counter; $i++) { + if ($i > 0) { + $h .= '
'; + } - $h .= ''; + $h .= ''; + if ($guess_labels) { + $h .= htmlspecialchars($this->get_label($backlink_values[$i])); + } else { + $h .= htmlspecialchars($backlink_values[$i]); } - $h .= '
' . "\n"; + $h .= ''; + $h .= '' . "\n"; } + + $h .= '' . "\n"; } return $h; @@ -555,7 +553,7 @@ public function remove_triples_about(string $s): void */ public function from_rdfxml(string $rdfxml, string $base = ''): void { - if ($rdfxml) { + if ($rdfxml !== '' && $rdfxml !== '0') { $this->remove_all_triples(); $this->add_rdfxml($rdfxml, $base); } @@ -570,7 +568,7 @@ public function from_rdfxml(string $rdfxml, string $base = ''): void */ public function from_json(string $json): void { - if ($json) { + if ($json !== '' && $json !== '0') { $this->remove_all_triples(); $index = json_decode($json, true); if (is_array($index)) { @@ -588,7 +586,7 @@ public function from_json(string $json): void */ public function add_json(string $json): void { - if ($json) { + if ($json !== '' && $json !== '0') { $json_index = json_decode($json, true); if (is_array($json_index)) { $this->_index = $this->merge($this->_index, $json_index); @@ -638,7 +636,7 @@ public function add_rdf(string $rdf, string $base = ''): void */ public function add_rdfxml(string $rdfxml, string $base = ''): void { - if ($rdfxml) { + if ($rdfxml !== '' && $rdfxml !== '0') { /** @var \ARC2_RDFXMLParser $parser */ $parser = \ARC2::getRDFXMLParser(); $parser->parse($base, $rdfxml); @@ -658,7 +656,7 @@ public function add_rdfxml(string $rdfxml, string $base = ''): void */ public function from_turtle(string $turtle, string $base = ''): void { - if ($turtle) { + if ($turtle !== '' && $turtle !== '0') { $this->remove_all_triples(); $this->add_turtle($turtle, $base); } @@ -674,7 +672,7 @@ public function from_turtle(string $turtle, string $base = ''): void */ public function add_turtle(string $turtle, string $base = ''): void { - if ($turtle) { + if ($turtle !== '' && $turtle !== '0') { /** @var \ARC2_TurtleParser $parser */ $parser = \ARC2::getTurtleParser(); $parser->parse($base, $turtle); @@ -692,7 +690,7 @@ public function add_turtle(string $turtle, string $base = ''): void */ public function from_rdfa(string $html, string $base = ''): void { - if ($html) { + if ($html !== '' && $html !== '0') { $this->remove_all_triples(); $this->add_rdfa($html, $base); } @@ -706,7 +704,7 @@ public function from_rdfa(string $html, string $base = ''): void */ public function add_rdfa(string $html, string $base = ''): void { - if ($html) { + if ($html !== '' && $html !== '0') { /** @var \ARC2_SemHTMLParser $parser */ $parser = \ARC2::getSemHTMLParser(); $parser->parse($base, $html); @@ -1278,7 +1276,7 @@ public function replace_resource(string $look_for, string $replace_with): void public function get_list_values(string $listUri): array { $array = []; - while (!empty($listUri) && $listUri != RDF_NIL) { + while (!empty($listUri) && $listUri !== RDF_NIL) { $array[] = $this->get_first_resource($listUri, RDF_FIRST); $listUri = $this->get_first_resource($listUri, RDF_REST); } @@ -1333,7 +1331,7 @@ public function get_triple_count(?string $s = null, ?string $p = null, $o = null { $index = $this->get_index(); - if (empty($index)) { + if ($index === []) { return 0; } @@ -1508,7 +1506,7 @@ public function add_resource_to_sequence_in_position(string $s, string $o, int $ { $sequenceValues = $this->get_sequence_values($s); - if (empty($sequenceValues) || $position > count($sequenceValues)) { + if ($sequenceValues === [] || $position > count($sequenceValues)) { $this->add_resource_to_sequence($s, $o); } else { array_splice($sequenceValues, $position - 1, 1, [$o, $sequenceValues[$position - 1]]); @@ -1594,7 +1592,7 @@ public function is_equal_to(ExtendedGraph $otherGraph): bool $diffThisAndThat = $this->diff($this->get_index(), $otherGraph->get_index()); $diffThatAndThis = $this->diff($otherGraph->get_index(), $this->get_index()); - return empty($diffThisAndThat) && empty($diffThatAndThis); + return $diffThisAndThat === [] && $diffThatAndThis === []; } public function remove_subjects_of_type(string $type): void diff --git a/src/classes/Labeller.php b/src/classes/Labeller.php index 6c15511b..56532426 100644 --- a/src/classes/Labeller.php +++ b/src/classes/Labeller.php @@ -313,6 +313,7 @@ public function qname_to_uri(?string $qName): ?string if ($qName === null || !preg_match('~^(.+):(.+)$~', $qName, $m)) { return null; } + if (isset($this->_ns[$m[1]])) { return $this->_ns[$m[1]] . $m[2]; } @@ -391,7 +392,7 @@ public function get_ns(): array public function get_label(string $uri, ?ExtendedGraph $g = null, bool $capitalize = false, bool $use_qnames = false): string { - if ($g) { + if ($g instanceof ExtendedGraph) { $label = $g->get_first_literal($uri, 'http://www.w3.org/2004/02/skos/core#prefLabel', '', 'en'); if (strlen($label) !== 0) { return $label; @@ -477,6 +478,7 @@ public function get_label(string $uri, ?ExtendedGraph $g = null, bool $capitaliz return $label; } + if ($capitalize && preg_match('~^[a-z]~', $localname)) { return ucfirst($localname); } @@ -489,7 +491,7 @@ public function get_label(string $uri, ?ExtendedGraph $g = null, bool $capitaliz public function get_plural_label(string $uri, ?ExtendedGraph $g = null, bool $capitalize = false, bool $use_qnames = false): string { - if ($g) { + if ($g instanceof ExtendedGraph) { $label = $g->get_first_literal($uri, 'http://purl.org/net/vocab/2004/03/label#plural', '', 'en'); if (strlen($label) !== 0) { return $label; @@ -506,7 +508,7 @@ public function get_plural_label(string $uri, ?ExtendedGraph $g = null, bool $ca return $label; } - if ($use_qnames == false && preg_match('~^.*[\/\#]([a-z]+)$~', $uri, $m)) { + if ($use_qnames === false && preg_match('~^.*[\/\#]([a-z]+)$~', $uri, $m)) { return $m[1] . 's'; } @@ -520,7 +522,7 @@ public function get_plural_label(string $uri, ?ExtendedGraph $g = null, bool $ca public function get_inverse_label(string $uri, ?ExtendedGraph $g = null, bool $capitalize = false, bool $use_qnames = false): string { - if ($g) { + if ($g instanceof ExtendedGraph) { $label = $g->get_first_literal($uri, 'http://purl.org/net/vocab/2004/03/label#inverseSingular', '', 'en'); if (strlen($label) !== 0) { return $label; diff --git a/src/classes/StatsD.php b/src/classes/StatsD.php index 7068077c..a0a286eb 100644 --- a/src/classes/StatsD.php +++ b/src/classes/StatsD.php @@ -21,9 +21,8 @@ class StatsD implements ITripodStat /** * @param string $host * @param int|string $port - * @param string $prefix */ - public function __construct($host, $port, $prefix = '') + public function __construct($host, $port, ?string $prefix = '') { $this->host = $host; $this->port = $port; @@ -33,10 +32,8 @@ public function __construct($host, $port, $prefix = '') /** * @param string $operation * @param int $inc - * - * @return void */ - public function increment($operation, $inc = 1) + public function increment($operation, $inc = 1): void { $this->send( $this->generateStatData($operation, $inc . '|c') @@ -46,10 +43,8 @@ public function increment($operation, $inc = 1) /** * @param string $operation * @param number $duration - * - * @return void */ - public function timer($operation, $duration) + public function timer($operation, $duration): void { $this->send( $this->generateStatData($operation, ['1|c', $duration . '|ms']) @@ -58,10 +53,8 @@ public function timer($operation, $duration) /** * Record an arbitrary value. - * - * @param string $operation */ - public function gauge($operation, string $value): void + public function gauge(string $operation, string $value): void { $this->send( $this->generateStatData($operation, $value . '|g') @@ -71,7 +64,7 @@ public function gauge($operation, string $value): void /** * @return array|class-string> */ - public function getConfig() + public function getConfig(): array { return [ 'class' => get_class($this), @@ -83,7 +76,7 @@ public function getConfig() ]; } - public static function createFromConfig(array $config) + public static function createFromConfig(array $config): self { if (isset($config['config'])) { $config = $config['config']; diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 7d57b59a..35ddcee9 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -384,12 +384,7 @@ public function getCardinality(string $storeName, string $collName, ?string $qNa return $this->cardinality[$storeName][$collName]; } - // Return the cardinality rule for the specified qname. - if (isset($this->cardinality[$storeName][$collName][$qName])) { - return $this->cardinality[$storeName][$collName][$qName]; - } - - return -1; + return $this->cardinality[$storeName][$collName][$qName] ?? -1; } /** @@ -458,11 +453,7 @@ public function isReplicaSet(string $datasource): bool public function getDefaultDataSourceForStore(string $storeName): ?string { - if (isset($this->dbConfig[$storeName]['data_source'])) { - return $this->dbConfig[$storeName]['data_source']; - } - - return null; + return $this->dbConfig[$storeName]['data_source'] ?? null; } /** @@ -482,11 +473,7 @@ public function getViewSpecification(string $storeName, string $vid): ?array */ public function getSearchDocumentSpecification(string $storeName, string $sid): ?array { - if (isset($this->searchDocSpecs[$storeName][$sid])) { - return $this->searchDocSpecs[$storeName][$sid]; - } - - return null; + return $this->searchDocSpecs[$storeName][$sid] ?? null; } /** @@ -538,11 +525,7 @@ public function getSearchDocumentSpecifications(string $storeName, ?string $type */ public function getTableSpecification(string $storeName, string $tid): ?array { - if (isset($this->tableSpecs[$storeName][$tid])) { - return $this->tableSpecs[$storeName][$tid]; - } - - return null; + return $this->tableSpecs[$storeName][$tid] ?? null; } /** @@ -751,6 +734,7 @@ public function getCollectionsForTables(string $storeName, array $tables = [], $ if (!isset($this->tableSpecs[$storeName][$table])) { throw new ConfigException(sprintf("Table id '%s' not in configuration for store '%s'", $table, $storeName)); } + $dataSources[] = $this->tableSpecs[$storeName][$table]['to_data_source'] ?? null; } @@ -787,6 +771,7 @@ public function getCollectionsForViews(string $storeName, array $views = [], $re if (!isset($this->viewSpecs[$storeName][$view])) { throw new ConfigException(sprintf("View id '%s' not in configuration for store '%s'", $view, $storeName)); } + $dataSources[] = $this->viewSpecs[$storeName][$view]['to_data_source'] ?? null; } @@ -823,6 +808,7 @@ public function getCollectionsForSearch(string $storeName, array $searchSpecIds if (!isset($this->searchDocSpecs[$storeName][$searchSpec])) { throw new ConfigException(sprintf("Search document spec id '%s' not in configuration for store '%s'", $searchSpec, $storeName)); } + $dataSources[] = $this->searchDocSpecs[$storeName][$searchSpec]['to_data_source'] ?? null; } @@ -991,7 +977,7 @@ protected function loadConfig(array $config): void foreach ($this->getMandatoryKey('data_sources', $config) as $source => $c) { if (!isset($c['type'])) { - throw new ConfigException('No \'type\' set for data source ' . $source); + throw new ConfigException("No 'type' set for data source " . $source); } if (!isset($c['connection'])) { @@ -1198,7 +1184,7 @@ protected function validateTableSpecPart(array $spec, int $depth = 0): void } if (isset($field['predicates'])) { - if ($validationLevel == self::VALIDATE_MAX) { + if ($validationLevel === self::VALIDATE_MAX) { foreach ($field['predicates'] as $p) { // If predicates is an array we've got modifiers if (is_array($p)) { @@ -1240,7 +1226,7 @@ protected function validateTableSpecPart(array $spec, int $depth = 0): void } $validComputingFieldFunctions = Tables::$computedFieldFunctions; - if ($validationLevel == self::VALIDATE_MAX) { + if ($validationLevel === self::VALIDATE_MAX) { $availableFields = $this->getFieldNamesInSpec($spec); $availableFields = array_map(function (string $field): string { return '$' . $field; @@ -1270,7 +1256,7 @@ protected function validateTableSpecPart(array $spec, int $depth = 0): void throw new ConfigException('Computed field spec contains more than one function'); } - if ($validationLevel == self::VALIDATE_MAX) { + if ($validationLevel === self::VALIDATE_MAX) { $this->validateComputedFieldSpec($functions[0], $field['value'], $availableFields); } } @@ -1386,6 +1372,7 @@ protected function validateComputedConditionalSpec(array $spec, array $available /** * @param array|string $value + * @param string[] $availableFields * * @throws ConfigException */ diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index 5d319af3..7662df41 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -52,12 +52,12 @@ class Driver extends DriverBase implements IDriver /** * Constructor for Driver. * - * @param array $opts an Array of options:
    - *
  • defaultContext: (string) to use where a specific default context is not defined. Default is Null
  • - *
  • async: (array) determines the async behaviour of views, tables and search. For each of these array keys, if set to true, generation of these elements will be done asyncronously on save. Default is array(OP_VIEWS=>false,OP_TABLES=>true,OP_SEARCH=>true)
  • - *
  • stat: this sets the stats object to use to record statistics around operations performed by Driver. Default is null
  • - *
  • readPreference: The Read preference to set for Mongo: Default is ReadPreference::RP_PRIMARY_PREFERRED
  • - *
  • retriesToGetLock: Retries to do when unable to get lock on a document, default is 20
+ * @param array $opts an Array of options:
    + *
  • defaultContext: (string) to use where a specific default context is not defined. Default is Null
  • + *
  • async: (array) determines the async behaviour of views, tables and search. For each of these array keys, if set to true, generation of these elements will be done asyncronously on save. Default is array(OP_VIEWS=>false,OP_TABLES=>true,OP_SEARCH=>true)
  • + *
  • stat: this sets the stats object to use to record statistics around operations performed by Driver. Default is null
  • + *
  • readPreference: The Read preference to set for Mongo: Default is ReadPreference::RP_PRIMARY_PREFERRED
  • + *
  • retriesToGetLock: Retries to do when unable to get lock on a document, default is 20
*/ public function __construct(string $podName, string $storeName, array $opts = []) { @@ -397,7 +397,7 @@ public function select(array $query, array $fields, ?array $sortBy = null, ?int 'projection' => $fields, ]; if (!empty($limit)) { - $findOptions['skip'] = (int) $offset; + $findOptions['skip'] = $offset; $findOptions['limit'] = (int) $limit; } @@ -495,6 +495,7 @@ public function getETag(string $resource, ?string $context = null): string if ($lastUpdatedDate === null) { return ''; } + // PHP 5.3 used MongoDate::__toString() to generate the etag. // This is incompatible with UTCDate::__toString() so we convert it into a microtime representation. // This ensures that if it is required to dual run 2 PHP versions, there are no etag compatibility issues. diff --git a/src/mongo/Labeller.php b/src/mongo/Labeller.php index ec101193..d34f3e7c 100644 --- a/src/mongo/Labeller.php +++ b/src/mongo/Labeller.php @@ -74,7 +74,7 @@ public function qname_to_uri(?string $qName): ?string public function get_prefix(string $ns): string { $prefix = array_search($ns, $this->_ns, true); - if ($prefix !== null && $prefix !== false) { + if ($prefix !== false) { return $prefix; } diff --git a/src/mongo/MongoGraph.php b/src/mongo/MongoGraph.php index a8ec4a29..32e7e03e 100644 --- a/src/mongo/MongoGraph.php +++ b/src/mongo/MongoGraph.php @@ -34,7 +34,7 @@ public function __construct() * * @throws \InvalidArgumentException if you do not specify a context */ - public function to_nquads($context) + public function to_nquads($context): string { if (empty($context)) { throw new \InvalidArgumentException('You must specify the context when serializing to nquads'); @@ -75,10 +75,8 @@ public function add_tripod_array($tarray): void * * @param mixed $docId * @param mixed $context - * - * @return array */ - public function to_tripod_array($docId, $context) + public function to_tripod_array($docId, ?string $context): ?array { $docId = $this->_labeller->qname_to_alias($docId); $contextAlias = $this->_labeller->uri_to_alias($context); @@ -103,9 +101,9 @@ public function to_tripod_array($docId, $context) * @param mixed $docId * @param mixed $context * - * @return array|array> + * @return array */ - public function to_tripod_view_array($docId, $context): array + public function to_tripod_view_array($docId, ?string $context): array { $subjects = $this->get_subjects(); $contextAlias = $this->_labeller->uri_to_alias($context); @@ -142,7 +140,7 @@ private function add_tarray_to_index(array $tarray): void $predicate = $this->qname_to_uri($key); $graphValueObject = $this->toGraphValueObject($value); // Only add if valid values have been found - if (!empty($graphValueObject)) { + if ($graphValueObject !== []) { $predObjects[$predicate] = $graphValueObject; } } elseif ($key == '_id') { diff --git a/src/mongo/base/CompositeBase.php b/src/mongo/base/CompositeBase.php index 65ebde3a..44e64a4a 100644 --- a/src/mongo/base/CompositeBase.php +++ b/src/mongo/base/CompositeBase.php @@ -143,11 +143,9 @@ abstract public function getSpecification(string $storeName, string $specId): ?a * Test if the a particular type appears in the array of types associated with a particular spec and that the changeset * includes rdf:type (or is empty, meaning addition or deletion vs. update). * - * @param string $rdfType - * * @return bool */ - protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes, array $subjectPredicates) + protected function checkIfTypeShouldTriggerOperation(?string $rdfType, array $validTypes, array $subjectPredicates) { // We don't know if this is an alias or a fqURI, nor what is in the valid types, necessarily $types = [$rdfType]; diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index d6556b64..053638a8 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -489,10 +489,8 @@ final class NoStat implements ITripodStat /** * @param string $operation * @param int|number $inc - * - * @return void */ - public function increment($operation, $inc = 1) + public function increment($operation, $inc = 1): void { // do nothing } @@ -500,10 +498,8 @@ public function increment($operation, $inc = 1) /** * @param string $operation * @param number $duration - * - * @return void */ - public function timer($operation, $duration) + public function timer($operation, $duration): void { // do nothing } diff --git a/src/mongo/delegates/SearchDocuments.php b/src/mongo/delegates/SearchDocuments.php index 23c71040..22043e3c 100644 --- a/src/mongo/delegates/SearchDocuments.php +++ b/src/mongo/delegates/SearchDocuments.php @@ -276,10 +276,8 @@ protected function addFields(array $source, array $fieldsOrIndices, array &$targ /** * @param mixed $specId - * - * @return array|null */ - protected function getSearchDocumentSpecification($specId) + protected function getSearchDocumentSpecification(string $specId): ?array { return $this->getConfigInstance()->getSearchDocumentSpecification($this->storeName, $specId); } @@ -298,6 +296,7 @@ private function addValuesToTarget(array $values, array $field, array &$target): $objName = $parts[0]; $name = $parts[1]; } + $limit = $field['limit'] ?? count($values); if ($values !== []) { diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 3c569841..1ef65e83 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -86,10 +86,9 @@ public function getSpecification(string $storeName, string $specId): ?array * * @param string $resourceUri * @param string $context - * @param string $podName * @param array|string|null $specType */ - public function generateAndIndexSearchDocuments($resourceUri, $context, $podName, $specType = []): void + public function generateAndIndexSearchDocuments($resourceUri, $context, string $podName, $specType = []): void { $mongoCollection = $this->config->getCollectionForCBD($this->storeName, $podName); diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index 90616cf3..4f0a305d 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -79,7 +79,6 @@ class Tables extends CompositeBase * Tripod and should inherit connections set up there. * * @param string $storeName - * @param string $defaultContext * @param ITripodStat|null $stat * @param string $readPreference * todo: MongoCollection -> podName @@ -87,7 +86,7 @@ class Tables extends CompositeBase public function __construct( $storeName, Collection $collection, - $defaultContext, + ?string $defaultContext, $stat = null, $readPreference = ReadPreference::RP_PRIMARY ) { @@ -544,7 +543,7 @@ public function generateTableRows(string $tableType, $resource = null, $context * * @return int */ - public function count($tableSpec, array $filters = []) + public function count(string $tableSpec, array $filters = []) { $filters['_id.type'] = $tableSpec; @@ -556,7 +555,7 @@ public function count($tableSpec, array $filters = []) * @param string|null $context Optional context * @param array|string|null $specType Optional table type or array of table types to delete from */ - protected function deleteTableRowsForResource($resource, $context = null, $specType = null) + protected function deleteTableRowsForResource(?string $resource, $context = null, $specType = null) { $t = new Timer(); $t->start(); @@ -591,11 +590,10 @@ protected function deleteTableRowsForResource($resource, $context = null, $specT * This method handles invalidation and regeneration of table rows based on impact index, before delegating to * generateTableRowsForType() for re-generation of any table rows for the $resource. * - * @param string $resource * @param string|null $context * @param array $specTypes */ - protected function generateTableRowsForResource($resource, $context = null, $specTypes = []) + protected function generateTableRowsForResource(?string $resource, $context = null, $specTypes = []) { $resourceAlias = $this->labeller->uri_to_alias($resource); $contextAlias = $this->getContextAlias($context); @@ -635,7 +633,7 @@ protected function generateTableRowsForResource($resource, $context = null, $spe * If an exception in thrown because a field is too large to index, the field is * truncated and the save is retried. * - * @param array|array $generatedRow the rows to save + * @param array $generatedRow the rows to save * * @throws \Exception */ @@ -757,7 +755,8 @@ protected function getComputedValue(string $function, array $spec, array &$dest) } /** - * @param array $equation + * @param array $equation + * @param array $dest * * @return float|int|null * @@ -818,7 +817,7 @@ protected function computeArithmeticValue(array $equation, array &$dest) /** * @param array $replaceSpec The replace value spec - * @param array $dest The table row document to save + * @param array $dest The table row document to save * * @return mixed */ @@ -844,7 +843,7 @@ protected function generateReplaceValue(array $replaceSpec, array &$dest) /** * @param array $conditionalSpec The conditional spec - * @param array $dest The table row document to save + * @param array $dest The table row document to save * * @return mixed The computed value */ @@ -1049,6 +1048,7 @@ protected function doConditional($left, $operator, $right) * * @param array $source * @param array $spec + * @param array $dest */ protected function addFields(array $source, array $spec, array &$dest) { @@ -1324,10 +1324,8 @@ protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes * For mocking. * * @param string $tableSpecId Table spec ID - * - * @return Collection */ - protected function getCollectionForTableSpec($tableSpecId) + protected function getCollectionForTableSpec(string $tableSpecId): Collection { return $this->getConfigInstance()->getCollectionForTable($this->storeName, $tableSpecId); } diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 97c2549f..fa0de4d8 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -265,12 +265,11 @@ public function getLockedDocuments($fromDateTime = null, $tillDateTime = null): /** * Remove locks that are there forever, creates a audit entry to keep track who and why removed these locks. * - * @param string $transaction_id * @param string $reason * * @throws \Exception, if something goes wrong when unlocking documents, or creating audit entries */ - public function removeInertLocks($transaction_id, $reason): bool + public function removeInertLocks(string $transaction_id, $reason): bool { $query = [_LOCKED_FOR_TRANS => $transaction_id]; $docs = $this->getLocksCollection()->find($query); @@ -828,10 +827,8 @@ protected function getDocumentForUpdate($subjectOfChange, $contextAlias, array $ /** * Processes each subject synchronously. - * - * @param string $contextAlias */ - protected function processSyncOperations(array $subjectsAndPredicatesOfChange, $contextAlias) + protected function processSyncOperations(array $subjectsAndPredicatesOfChange, string $contextAlias) { foreach ($this->getSyncOperations() as $op) { /** @var IComposite $composite */ @@ -871,7 +868,7 @@ protected function processSyncOperations(array $subjectsAndPredicatesOfChange, $ protected function queueASyncOperations(array $subjectsAndPredicatesOfChange, $contextAlias) { $operations = $this->getAsyncOperations(); - if (!empty($operations)) { + if ($operations !== []) { $data = [ 'changes' => $subjectsAndPredicatesOfChange, 'operations' => $operations, @@ -1024,7 +1021,7 @@ protected function unlockAllDocuments(string $transaction_id): bool * * @return array */ - protected function lockSingleDocument($s, $transaction_id, $contextAlias) + protected function lockSingleDocument(?string $s, $transaction_id, $contextAlias) { $countEntriesInLocksCollection = $this->getLocksCollection() ->count( @@ -1102,11 +1099,7 @@ protected function lockSingleDocument($s, $transaction_id, $contextAlias) } // / Collection methods - - /** - * @return Collection - */ - protected function getAuditManualRollbacksCollection() + protected function getAuditManualRollbacksCollection(): Collection { return $this->config->getCollectionForManualRollbackAudit($this->storeName); } @@ -1116,10 +1109,7 @@ protected function generateIdForNewMongoDocument(): ObjectId return new ObjectId(); } - /** - * @return UTCDateTime - */ - protected function getMongoDate() + protected function getMongoDate(): UTCDateTime { return DateUtil::getMongoDate(); } @@ -1169,9 +1159,9 @@ protected function getTripod(array $data): Driver /** * This proxy method allows us to mock updates against $this->collection. * - * @param mixed $query - * @param mixed $update - * @param mixed $options + * @param mixed $query + * @param mixed $update + * @param array $options * * @return bool */ @@ -1223,7 +1213,7 @@ protected function getLocksCollection() * * @param mixed $changeUri */ - private function getAdditionsRemovalsGroupedByNsPredicate(ChangeSet $cs, $changeUri): array + private function getAdditionsRemovalsGroupedByNsPredicate(ChangeSet $cs, string $changeUri): array { $additionsGroupedByNsPredicate = $this->getChangesGroupedByNsPredicate($cs, $changeUri, $this->labeller->qname_to_uri('cs:addition')); $removalsGroupedByNsPredicate = $this->getChangesGroupedByNsPredicate($cs, $changeUri, $this->labeller->qname_to_uri('cs:removal')); @@ -1256,7 +1246,7 @@ private function getAdditionsRemovalsGroupedByNsPredicate(ChangeSet $cs, $change * * @throws Exception */ - private function getChangesGroupedByNsPredicate(ChangeSet $cs, $changeUri, $changePredicate): array + private function getChangesGroupedByNsPredicate(ChangeSet $cs, string $changeUri, $changePredicate): array { $changes = $cs->get_subject_property_values($changeUri, $changePredicate); diff --git a/src/mongo/delegates/Views.php b/src/mongo/delegates/Views.php index d16b5285..7a87f381 100644 --- a/src/mongo/delegates/Views.php +++ b/src/mongo/delegates/Views.php @@ -742,22 +742,15 @@ protected function extractProperties(array $source, array $viewSpec, string $fro return $obj; } - /** - * @param string $viewSpecId - * - * @return Collection - */ - protected function getCollectionForViewSpec($viewSpecId) + protected function getCollectionForViewSpec(string $viewSpecId): Collection { return $this->getConfigInstance()->getCollectionForView($this->storeName, $viewSpecId); } /** * @param array|string $resourceUriOrArray - * @param string $context - * @param string $viewType */ - private function createTripodViewIdsFromResourceUris(array $resourceUriOrArray, $context, $viewType): array + private function createTripodViewIdsFromResourceUris(array $resourceUriOrArray, ?string $context, string $viewType): array { $contextAlias = $this->getContextAlias($context); $ret = []; diff --git a/src/mongo/jobs/ApplyOperation.php b/src/mongo/jobs/ApplyOperation.php index 895057f6..d9db5bf4 100644 --- a/src/mongo/jobs/ApplyOperation.php +++ b/src/mongo/jobs/ApplyOperation.php @@ -103,7 +103,7 @@ public function createJob(array $subjects, $queueName = null, $otherData = []): $data = [ self::SUBJECTS_KEY => array_map( - function (ImpactedSubject $subject) { + function (ImpactedSubject $subject): array { return $subject->toArray(); }, $subjects diff --git a/src/mongo/providers/MongoSearchProvider.php b/src/mongo/providers/MongoSearchProvider.php index ee9df767..c9cc896c 100644 --- a/src/mongo/providers/MongoSearchProvider.php +++ b/src/mongo/providers/MongoSearchProvider.php @@ -535,7 +535,7 @@ public function deleteSearchDocumentsByTypeId($typeId, $timestamp = null) * * @return int */ - public function count($searchSpec, array $filters = []) + public function count(string $searchSpec, array $filters = []) { $filters['_id.type'] = $searchSpec; @@ -544,12 +544,8 @@ public function count($searchSpec, array $filters = []) /** * Returns the search document specification for the supplied type. - * - * @param string $typeId - * - * @return array|null */ - protected function getSearchDocumentSpecification($typeId) + protected function getSearchDocumentSpecification(string $typeId): ?array { return $this->config->getSearchDocumentSpecification($this->storeName, $typeId); } @@ -558,10 +554,8 @@ protected function getSearchDocumentSpecification($typeId) * For mocking. * * @param string $searchSpecId Search spec ID - * - * @return Collection */ - protected function getCollectionForSearchSpec($searchSpecId) + protected function getCollectionForSearchSpec(string $searchSpecId): Collection { return $this->config->getCollectionForSearchDocument($this->storeName, $searchSpecId); } diff --git a/src/mongo/serializers/NQuadSerializer.php b/src/mongo/serializers/NQuadSerializer.php index 335fa78b..3e97264e 100644 --- a/src/mongo/serializers/NQuadSerializer.php +++ b/src/mongo/serializers/NQuadSerializer.php @@ -180,50 +180,62 @@ public function getEscapedChar($c, $no) if ($no < 9) { return '\u' . sprintf('%04X', $no); } + // #x0-#x8 (0-8) if ($no == 9) { return '\t'; } + // #x9 (9) if ($no == 10) { return '\n'; } + // #xA (10) if ($no < 13) { return '\u' . sprintf('%04X', $no); } + // #xB-#xC (11-12) if ($no == 13) { return '\r'; } + // #xD (13) if ($no < 32) { return '\u' . sprintf('%04X', $no); } + // #xE-#x1F (14-31) if ($no < 34) { return $c; } + // #x20-#x21 (32-33) if ($no == 34) { return '\"'; } + // #x22 (34) if ($no < 92) { return $c; } + // #x23-#x5B (35-91) if ($no == 92) { return '\\\\'; } + // #x5C (92) if ($no < 127) { return $c; } + // #x5D-#x7E (93-126) if ($no < 65536) { return '\u' . sprintf('%04X', $no); } + // #x7F-#xFFFF (128-65535) if ($no < 1114112) { return '\U' . sprintf('%08X', $no); diff --git a/src/mongo/util/IndexUtils.php b/src/mongo/util/IndexUtils.php index 3103c608..4683f190 100644 --- a/src/mongo/util/IndexUtils.php +++ b/src/mongo/util/IndexUtils.php @@ -127,7 +127,7 @@ public function ensureIndexes($reindex = false, $storeName = null, $background = } // index search documents - foreach ($config->getSearchDocumentSpecifications($storeName) as $searchId => $spec) { + foreach (array_keys($config->getSearchDocumentSpecifications($storeName)) as $searchId) { $collection = $config->getCollectionForSearchDocument($storeName, $searchId); if ($collection) { $indexes = [ diff --git a/src/mongo/util/TriplesUtil.php b/src/mongo/util/TriplesUtil.php index 9bb29a11..2c717bdb 100644 --- a/src/mongo/util/TriplesUtil.php +++ b/src/mongo/util/TriplesUtil.php @@ -30,12 +30,11 @@ public function __construct() * Make them quads with a $context. * * @param mixed $subject - * @param string $storeName * @param string $podName * @param string|null $context * @param string[]|null $allowableTypes */ - public function loadTriplesAbout($subject, array $triples, $storeName, $podName, $context = null, $allowableTypes = null): void + public function loadTriplesAbout($subject, array $triples, string $storeName, $podName, $context = null, $allowableTypes = null): void { $context = ($context == null) ? Config::getInstance()->getDefaultContextAlias() : $this->labeller->uri_to_alias($context); if (array_key_exists($podName, $this->collections)) { @@ -62,7 +61,7 @@ public function loadTriplesAbout($subject, array $triples, $storeName, $podName, if ($allowableTypes != null && is_array($allowableTypes)) { $types = $graph->get_resource_triple_values($subject, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); - if ($types == null || empty($types)) { + if ($types == null || $types === []) { return; } @@ -86,10 +85,8 @@ public function loadTriplesAbout($subject, array $triples, $storeName, $podName, * * @param string $subject * @param string|null $context - * - * @return array */ - public function bsonizeTriplesAbout($subject, array $triples, $context = null) + public function bsonizeTriplesAbout($subject, array $triples, $context = null): ?array { $context = ($context == null) ? Config::getInstance()->getDefaultContextAlias() : $this->labeller->uri_to_alias($context); $graph = new MongoGraph(); @@ -170,11 +167,8 @@ public function suggestPrefix($ns): string /** * @param string $subject - * @param string $context - * - * @return array */ - public function getTArrayAbout($subject, array $triples, $context) + public function getTArrayAbout($subject, array $triples, ?string $context): ?array { $graph = new MongoGraph(); foreach ($triples as $triple) { @@ -197,11 +191,10 @@ public function getTArrayAbout($subject, array $triples, $context) /** * @param string $cbdSubject - * @param string $context * * @throws \Exception */ - protected function saveCBD($cbdSubject, MongoGraph $cbdGraph, Collection $collection, $context) + protected function saveCBD($cbdSubject, MongoGraph $cbdGraph, Collection $collection, ?string $context) { $cbdSubject = $this->labeller->uri_to_alias($cbdSubject); if ($cbdGraph == null || $cbdGraph->is_empty()) { diff --git a/test/performance/mongo/MongoTripodPerformanceTestBase.php b/test/performance/mongo/MongoTripodPerformanceTestBase.php index 32c800ab..fa9d6a86 100644 --- a/test/performance/mongo/MongoTripodPerformanceTestBase.php +++ b/test/performance/mongo/MongoTripodPerformanceTestBase.php @@ -56,7 +56,7 @@ private function getProfiler(): Profiler 'save.handler.file' => [ 'filename' => $profilerDir . '/xhgui.data.jsonl', ], - 'profiler.replace_url' => function () { + 'profiler.replace_url' => function (): string { return $this->getName(true) . ($this->hasFailed() ? ' FAIL' : ''); }, ]); diff --git a/test/stubs.php b/test/stubs.php index 6e5bc4a3..1921eecf 100644 --- a/test/stubs.php +++ b/test/stubs.php @@ -1,11 +1,13 @@ assertFalse($addResult, 'The triple should not have been added for this value'); $hasPropertyResult = $graph->subject_has_property('http://some/subject/1', 'http://some/predicate'); @@ -227,9 +228,9 @@ public function testGetFirstResource(): void $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', 'value 1'); $graph->add_resource_triple('http://some/subject/1', 'http://some/predicate', 'http://value/2'); - $this->assertEquals('http://value/2', $graph->get_first_resource('http://some/subject/1', 'http://some/predicate'), 'should have returned first resource'); + $this->assertSame('http://value/2', $graph->get_first_resource('http://some/subject/1', 'http://some/predicate'), 'should have returned first resource'); $this->assertEquals(null, $graph->get_first_resource('http://some/subject/2', 'http://other/predicate'), 'should have returned default value'); - $this->assertEquals('my default', $graph->get_first_resource('http://some/subject/3', 'http://other/predicate', 'my default'), 'should have returned default value'); + $this->assertSame('my default', $graph->get_first_resource('http://some/subject/3', 'http://other/predicate', 'my default'), 'should have returned default value'); } public function testRemoveResourceTriple(): void @@ -239,22 +240,22 @@ public function testRemoveResourceTriple(): void // Add some triples $graph->add_resource_triple('http://some/subject/1', 'http://some/predicate', 'http://value/1'); $graph->add_resource_triple('http://some/subject/2', 'http://some/predicate', 'http://value/2'); - $this->assertEquals(2, $graph->get_triple_count(), 'should have 2 triples'); + $this->assertSame(2, $graph->get_triple_count(), 'should have 2 triples'); // Try to remove triples that don't exist $graph->remove_resource_triple('http://some/subject/3', 'http://some/predicate', 'http://value/3'); $graph->remove_literal_triple('http://some/subject/3', 'http://some/predicate', 'value 3'); - $this->assertEquals(2, $graph->get_triple_count(), 'should have 2 triples'); + $this->assertSame(2, $graph->get_triple_count(), 'should have 2 triples'); // Remove a triple that does exist $graph->remove_resource_triple('http://some/subject/1', 'http://some/predicate', 'http://value/1'); - $this->assertEquals(1, $graph->get_triple_count(), 'should have 1 triple'); + $this->assertSame(1, $graph->get_triple_count(), 'should have 1 triple'); // Remove the last triple $graph->remove_resource_triple('http://some/subject/2', 'http://some/predicate', 'http://value/2'); - $this->assertEquals(0, $graph->get_triple_count(), 'should have 0 triples'); + $this->assertSame(0, $graph->get_triple_count(), 'should have 0 triples'); $this->assertTrue($graph->is_empty(), 'should be empty'); - $this->assertEquals([], $graph->get_index(), 'should have empty index'); + $this->assertSame([], $graph->get_index(), 'should have empty index'); } public function testRemoveLiteralTriple(): void @@ -264,22 +265,22 @@ public function testRemoveLiteralTriple(): void // Add some triples $graph->add_literal_triple('http://some/subject/1', 'http://some/predicate', 'value 1'); $graph->add_literal_triple('http://some/subject/2', 'http://some/predicate', 'value 2'); - $this->assertEquals(2, $graph->get_triple_count(), 'should have 2 triples'); + $this->assertSame(2, $graph->get_triple_count(), 'should have 2 triples'); // Try to remove triples that don't exist $graph->remove_literal_triple('http://some/subject/3', 'http://some/predicate', 'value 3'); $graph->remove_resource_triple('http://some/subject/3', 'http://some/predicate', 'http://value/3'); - $this->assertEquals(2, $graph->get_triple_count(), 'should have 2 triples'); + $this->assertSame(2, $graph->get_triple_count(), 'should have 2 triples'); // Remove a triple that does exist $graph->remove_literal_triple('http://some/subject/1', 'http://some/predicate', 'value 1'); - $this->assertEquals(1, $graph->get_triple_count(), 'should have 1 triple'); + $this->assertSame(1, $graph->get_triple_count(), 'should have 1 triple'); // Remove the last triple $graph->remove_literal_triple('http://some/subject/2', 'http://some/predicate', 'value 2'); - $this->assertEquals(0, $graph->get_triple_count(), 'should have 0 triples'); + $this->assertSame(0, $graph->get_triple_count(), 'should have 0 triples'); $this->assertTrue($graph->is_empty(), 'should be empty'); - $this->assertEquals([], $graph->get_index(), 'should have empty index'); + $this->assertSame([], $graph->get_index(), 'should have empty index'); } public function testGetResourceProperties(): void @@ -320,7 +321,7 @@ public function testGetSequenceValues(): void $graph->add_resource_triple('http://some/subject/1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_1', 'http://value/1'); $expectedArray = ['http://value/1', 'http://value/2', 'http://value/3', 'http://value/4', 'http://value/5']; - $this->assertEquals($expectedArray, $graph->get_sequence_values('http://some/subject/1')); + $this->assertSame($expectedArray, $graph->get_sequence_values('http://some/subject/1')); } public function testAddResourceToSequence(): void @@ -333,20 +334,20 @@ public function testAddResourceToSequence(): void $graph->add_resource_to_sequence($testSubject, $testObject1); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject1], $objects); + $this->assertSame([$testObject1], $objects); $graph->add_resource_to_sequence($testSubject, $testObject2); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject1, $testObject2], $objects); + $this->assertSame([$testObject1, $testObject2], $objects); $graph->add_resource_to_sequence('http://some/other/subject', 'http://some/other/object'); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject1, $testObject2], $objects); + $this->assertSame([$testObject1, $testObject2], $objects); $objects = $graph->get_sequence_values('http://some/other/subject'); - $this->assertEquals(['http://some/other/object'], $objects); + $this->assertSame(['http://some/other/object'], $objects); } public function testAddResourceToSequenceInPosition(): void @@ -362,27 +363,27 @@ public function testAddResourceToSequenceInPosition(): void $graph->add_resource_to_sequence_in_position($testSubject, $testObject1, 1); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject1], $objects); + $this->assertSame([$testObject1], $objects); $graph->add_resource_to_sequence_in_position($testSubject, $testObject2, 1); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject2, $testObject1], $objects); + $this->assertSame([$testObject2, $testObject1], $objects); $graph->add_resource_to_sequence_in_position($testSubject, $testObject3, 1); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject3, $testObject2, $testObject1], $objects); + $this->assertSame([$testObject3, $testObject2, $testObject1], $objects); $graph->add_resource_to_sequence_in_position($testSubject, $testObject4, 3); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject3, $testObject2, $testObject4, $testObject1], $objects); + $this->assertSame([$testObject3, $testObject2, $testObject4, $testObject1], $objects); $graph->add_resource_to_sequence_in_position($testSubject, $testObject5, count($objects) + 1); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject3, $testObject2, $testObject4, $testObject1, $testObject5], $objects); + $this->assertSame([$testObject3, $testObject2, $testObject4, $testObject1, $testObject5], $objects); } public function testAddToSequenceInPositionAgain(): void @@ -412,20 +413,20 @@ public function testAddLiteralToSequence(): void $graph->add_literal_to_sequence($testSubject, $testObject1); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject1], $objects); + $this->assertSame([$testObject1], $objects); $graph->add_literal_to_sequence($testSubject, $testObject2); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject1, $testObject2], $objects); + $this->assertSame([$testObject1, $testObject2], $objects); $graph->add_literal_to_sequence('http://some/other/subject', 'bar'); $objects = $graph->get_sequence_values('http://some/subject/s1'); - $this->assertEquals([$testObject1, $testObject2], $objects); + $this->assertSame([$testObject1, $testObject2], $objects); $objects = $graph->get_sequence_values('http://some/other/subject'); - $this->assertEquals(['bar'], $objects); + $this->assertSame(['bar'], $objects); } public function testGetTripleCountWithNoParams(): void @@ -438,7 +439,7 @@ public function testGetTripleCountWithNoParams(): void $expected = 3; $actual = $graph->get_triple_count(); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } public function testGetTripleCountWithSubject(): void @@ -451,7 +452,7 @@ public function testGetTripleCountWithSubject(): void $expected = 1; $actual = $graph->get_triple_count('http://some/subject/1'); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } public function testGetTripleCountWithPredicate(): void @@ -464,7 +465,7 @@ public function testGetTripleCountWithPredicate(): void $expected = 3; $actual = $graph->get_triple_count(null, 'http://some/predicate'); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } public function testGetTripleCountWithObject(): void @@ -477,7 +478,7 @@ public function testGetTripleCountWithObject(): void $expected = 3; $actual = $graph->get_triple_count(null, null, 'some object'); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } public function testGetTripleCountWithSubjectandPredicate(): void @@ -491,7 +492,7 @@ public function testGetTripleCountWithSubjectandPredicate(): void $expected = 2; $actual = $graph->get_triple_count('http://some/subject/1', 'http://some/predicate'); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } public function testGetTripleCountWithSubjectPredicateAndObject(): void @@ -505,7 +506,7 @@ public function testGetTripleCountWithSubjectPredicateAndObject(): void $expected = 1; $actual = $graph->get_triple_count('http://some/subject/1', 'http://some/predicate', 'some object'); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } public function testGetTripleCountWithEmptyGraph(): void @@ -513,7 +514,7 @@ public function testGetTripleCountWithEmptyGraph(): void $graph = new ExtendedGraph(); $expected = 0; $actual = $graph->get_triple_count(); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } public function testGetTripleCountWithNonExistentSubject(): void @@ -521,7 +522,7 @@ public function testGetTripleCountWithNonExistentSubject(): void $graph = new ExtendedGraph(); $expected = 0; $actual = $graph->get_triple_count('http://example.com/subject'); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } public function testReplaceUris(): void @@ -604,7 +605,7 @@ public function testGetLabelForUri(): void ExtendedGraph::initProperties(['labelProperties' => ['http://www.w3.org/2000/01/rdf-schema#label']]); - $this->assertEquals($graph->get_label_for_uri($s1), $label, 'get_label_for_uri(uri) should return the value of a label property'); + $this->assertSame($graph->get_label_for_uri($s1), $label, 'get_label_for_uri(uri) should return the value of a label property'); } public function testGetLabelForUriLabelPropsNotInitialised(): void @@ -637,7 +638,7 @@ public function testGetLabelForUriReturnsEmptyStringIfSubjectNotFound(): void ExtendedGraph::initProperties(['labelProperties' => ['http://www.w3.org/2000/01/rdf-schema#label']]); - $this->assertEquals('', $graph->get_label_for_uri('http://example.com/1')); + $this->assertSame('', $graph->get_label_for_uri('http://example.com/1')); } public function testGetLabelForUriReturnsEmptyStringLabelNotFound(): void @@ -653,7 +654,7 @@ public function testGetLabelForUriReturnsEmptyStringLabelNotFound(): void ExtendedGraph::initProperties(['labelProperties' => ['http://www.w3.org/2000/01/rdf-schema#label2']]); - $this->assertEquals('', $graph->get_label_for_uri($s1)); + $this->assertSame('', $graph->get_label_for_uri($s1)); } public function testIsEqualToReturnsTrueForIdenticalGraphs(): void @@ -749,7 +750,7 @@ public function testRemoveResourceFromSequence(): void $graph->remove_resource_from_sequence($s, $sub2); $sequenceValues = $graph->get_sequence_values($s); - $this->assertEquals([$sub1, $sub3], $sequenceValues, 'There should be two sequence values, in the correct order'); + $this->assertSame([$sub1, $sub3], $sequenceValues, 'There should be two sequence values, in the correct order'); $this->assertTrue($graph->has_resource_triple($s, ExtendedGraph::rdf . '_1', $sub1)); $this->assertTrue($graph->has_resource_triple($s, ExtendedGraph::rdf . '_2', $sub3)); } @@ -818,8 +819,8 @@ public function testFromJson(): void }'); $this->assertCount(3, $graph->get_subjects()); - $this->assertEquals(['http://subject/1', 'http://subject/2', 'http://subject/3'], $graph->get_subjects()); - $this->assertEquals(['http://value/1', 'http://value/2', 'http://value/3'], $graph->get_resource_properties('http://predicate')); + $this->assertSame(['http://subject/1', 'http://subject/2', 'http://subject/3'], $graph->get_subjects()); + $this->assertSame(['http://value/1', 'http://value/2', 'http://value/3'], $graph->get_resource_properties('http://predicate')); } public function testFromInvalidJson(): void @@ -845,8 +846,8 @@ public function testAddJson(): void }'); $this->assertCount(1, $graph->get_subjects()); - $this->assertEquals(['http://subject/1'], $graph->get_subjects()); - $this->assertEquals(['http://value/1'], $graph->get_resource_properties('http://predicate')); + $this->assertSame(['http://subject/1'], $graph->get_subjects()); + $this->assertSame(['http://value/1'], $graph->get_resource_properties('http://predicate')); $graph->add_json('{ "http://subject/2": { @@ -857,8 +858,8 @@ public function testAddJson(): void }'); $this->assertCount(2, $graph->get_subjects()); - $this->assertEquals(['http://subject/1', 'http://subject/2'], $graph->get_subjects()); - $this->assertEquals(['http://value/1', 'http://value/2'], $graph->get_resource_properties('http://predicate')); + $this->assertSame(['http://subject/1', 'http://subject/2'], $graph->get_subjects()); + $this->assertSame(['http://value/1', 'http://value/2'], $graph->get_resource_properties('http://predicate')); } public function testAddInvalidJson(): void @@ -872,16 +873,16 @@ public function testAddInvalidJson(): void } }'); - $this->assertEquals(1, $graph->get_triple_count()); + $this->assertSame(1, $graph->get_triple_count()); $this->assertCount(1, $graph->get_subjects()); - $this->assertEquals(['http://subject/1'], $graph->get_subjects()); - $this->assertEquals(['http://value/1'], $graph->get_resource_properties('http://predicate')); + $this->assertSame(['http://subject/1'], $graph->get_subjects()); + $this->assertSame(['http://value/1'], $graph->get_resource_properties('http://predicate')); $index = $graph->get_index(); $graph->add_json('not a valid json'); // Should not have changed $this->assertEquals($index, $graph->get_index()); - $this->assertEquals(1, $graph->get_triple_count()); + $this->assertSame(1, $graph->get_triple_count()); } } diff --git a/test/unit/mongo/ConfigGeneratorTest.php b/test/unit/mongo/ConfigGeneratorTest.php index 2c50cbcd..14fd80dc 100644 --- a/test/unit/mongo/ConfigGeneratorTest.php +++ b/test/unit/mongo/ConfigGeneratorTest.php @@ -33,7 +33,7 @@ public function testCreateFromConfig(): void $this->assertInstanceOf(TestConfigGenerator::class, $instance); $this->assertInstanceOf(Tripod\Mongo\Config::class, $instance); $this->assertInstanceOf(ITripodConfigSerializer::class, $instance); - $this->assertEquals( + $this->assertSame( ['CBD_testing', 'CBD_test_related_content', 'CBD_testing_2'], $instance->getPods('tripod_php_testing') ); diff --git a/test/unit/mongo/MongoGraphTest.php b/test/unit/mongo/MongoGraphTest.php index d57318d2..154611e7 100644 --- a/test/unit/mongo/MongoGraphTest.php +++ b/test/unit/mongo/MongoGraphTest.php @@ -16,7 +16,7 @@ protected function setUp(): void public function testUriToQNameOnRegisteredNS(): void { $g = new MongoGraph(); - $this->assertEquals('dct:title', $g->uri_to_qname('http://purl.org/dc/terms/title')); + $this->assertSame('dct:title', $g->uri_to_qname('http://purl.org/dc/terms/title')); } public function testUriToQNameOnUnRegisteredNS(): void @@ -51,7 +51,7 @@ public function testToNQuads(): void $expected = " \"some literal title\" . .\n"; - $this->assertEquals($expected, $g->to_nquads(Config::getInstance()->getDefaultContextAlias())); + $this->assertSame($expected, $g->to_nquads(Config::getInstance()->getDefaultContextAlias())); } public function testToNQuadsTwoGraphsWithDifferentContext(): void @@ -62,7 +62,7 @@ public function testToNQuadsTwoGraphsWithDifferentContext(): void $expected = " \"some literal title\" . .\n"; - $this->assertEquals($expected, $g->to_nquads('http://talisaspire.com/')); + $this->assertSame($expected, $g->to_nquads('http://talisaspire.com/')); $g = new MongoGraph(); $g->add_literal_triple('http://example.com/2', $g->qname_to_uri('dct:title'), 'some literal title'); @@ -70,7 +70,7 @@ public function testToNQuadsTwoGraphsWithDifferentContext(): void $expected = " \"some literal title\" . .\n"; - $this->assertEquals($expected, $g->to_nquads('http://wibble.talisaspire.com/')); + $this->assertSame($expected, $g->to_nquads('http://wibble.talisaspire.com/')); } public function testAddTripodArrayThrowsException(): void @@ -424,7 +424,7 @@ public function testToTripodViewArray(): void $g->add_resource_triple('http://example.com/things/2', $g->qname_to_uri('rdf:type'), 'http://talisaspire.com/schema#Work'); $actual = $g->to_tripod_view_array('http://example.com/things/1', 'http://example.com/'); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } public function testWriteLockedDocDoesNotExposeVersionOrLockPropertyInGraph(): void diff --git a/test/unit/mongo/MongoTransactionLogTest.php b/test/unit/mongo/MongoTransactionLogTest.php index 125323a1..32b3a747 100644 --- a/test/unit/mongo/MongoTransactionLogTest.php +++ b/test/unit/mongo/MongoTransactionLogTest.php @@ -736,7 +736,7 @@ public function testCreateNewTransactionThrowsExceptionIfInsertFails(): void protected function buildTransactionDocument($id, $subjectOfChange, $startTime, $endTime, $_version): array { return [ - '_id' => 'transaction_' . (string) $id, + '_id' => 'transaction_' . $id, 'changes' => [ [ '_id' => ['r' => '_:cs0', 'c' => 'http://talisaspire.com/'], diff --git a/test/unit/mongo/MongoTripodConfigUnitTest.php b/test/unit/mongo/MongoTripodConfigUnitTest.php index 1d54f9be..30d85f78 100644 --- a/test/unit/mongo/MongoTripodConfigUnitTest.php +++ b/test/unit/mongo/MongoTripodConfigUnitTest.php @@ -123,7 +123,7 @@ public function testCompoundIndexAllArraysThrowsException(): void public function testSearchConfig(): void { $config = Config::getInstance(); - $this->assertEquals(MongoSearchProvider::class, $config->getSearchProviderClassName('tripod_php_testing')); + $this->assertSame(MongoSearchProvider::class, $config->getSearchProviderClassName('tripod_php_testing')); $this->assertCount(3, $config->getSearchDocumentSpecifications('tripod_php_testing')); } @@ -253,7 +253,7 @@ public function testGetSearchDocumentSpecificationsWhereNoneExists(): void { $expectedSpec = []; $actualSpec = Config::getInstance()->getSearchDocumentSpecifications('something:doesntexist'); - $this->assertEquals($expectedSpec, $actualSpec); + $this->assertSame($expectedSpec, $actualSpec); } public function testViewSpecCountWithoutTTLThrowsException(): void @@ -725,7 +725,7 @@ public function testGetReplicaSetName(): void $this->assertNull($mtc->getReplicaSetName($mtc->getDefaultDataSourceForStore('testing_2'))); } - public function testGetReplicaSetNameNonExistingDatasource() + public function testGetReplicaSetNameNonExistingDatasource(): void { Config::setConfig([ 'defaultContext' => 'http://talisaspire.com/', @@ -871,7 +871,7 @@ public function testSearchConfigNotPresent(): void Config::setConfig($config); $mtc = Config::getInstance(); $this->assertNull($mtc->getSearchProviderClassName('tripod_php_testing')); - $this->assertEquals([], $mtc->getSearchDocumentSpecifications('tripod_php_testing')); + $this->assertSame([], $mtc->getSearchDocumentSpecifications('tripod_php_testing')); } public function testGetAllTypesInSpecifications(): void diff --git a/test/unit/mongo/MongoTripodNQuadSerializerTest.php b/test/unit/mongo/MongoTripodNQuadSerializerTest.php index 53ac2c37..84d04f7c 100644 --- a/test/unit/mongo/MongoTripodNQuadSerializerTest.php +++ b/test/unit/mongo/MongoTripodNQuadSerializerTest.php @@ -25,7 +25,7 @@ public function testSerializerSimple(): void $serializer = new NQuadSerializer(); $actual = $serializer->getSerializedIndex($g->_index, Config::getInstance()->getDefaultContextAlias()); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } public function testSerializerWithMultipleSubjects(): void diff --git a/test/unit/mongo/MongoTripodStatTest.php b/test/unit/mongo/MongoTripodStatTest.php index 496e8d20..84c00058 100644 --- a/test/unit/mongo/MongoTripodStatTest.php +++ b/test/unit/mongo/MongoTripodStatTest.php @@ -38,7 +38,7 @@ public function testStatsDSettersAndGetters(): void $this->assertEquals('foo.bar', $stat->getHost()); $this->assertEquals(9876, $stat->getPort()); $this->assertEquals('', $stat->getPrefix()); - $this->assertEquals(['class' => StatsD::class, 'config' => ['host' => 'foo.bar', 'port' => 9876, 'prefix' => '']], $stat->getConfig()); + $this->assertSame(['class' => StatsD::class, 'config' => ['host' => 'foo.bar', 'port' => 9876, 'prefix' => '']], $stat->getConfig()); $stat->setHost('bar.baz'); $this->assertEquals('bar.baz', $stat->getHost()); @@ -48,7 +48,7 @@ public function testStatsDSettersAndGetters(): void $stat->setPrefix('FOO_BAR'); $this->assertEquals('FOO_BAR', $stat->getPrefix()); - $this->assertEquals(['class' => StatsD::class, 'config' => ['host' => 'bar.baz', 'port' => 4567, 'prefix' => 'FOO_BAR']], $stat->getConfig()); + $this->assertSame(['class' => StatsD::class, 'config' => ['host' => 'bar.baz', 'port' => 4567, 'prefix' => 'FOO_BAR']], $stat->getConfig()); } public function testStatsDIncrementNoPrefix(): void diff --git a/test/unit/mongo/MongoTripodTablesTest.php b/test/unit/mongo/MongoTripodTablesTest.php index 31a41f6f..202b0e8f 100644 --- a/test/unit/mongo/MongoTripodTablesTest.php +++ b/test/unit/mongo/MongoTripodTablesTest.php @@ -842,7 +842,7 @@ public function testDistinctForFilterWithNoMatches(): void public function testTableRowsGenerateWhenDefinedPredicateChanges(): void { - foreach (Config::getInstance()->getTableSpecifications($this->tripod->getStoreName()) as $specId => $spec) { + foreach (array_keys(Config::getInstance()->getTableSpecifications($this->tripod->getStoreName())) as $specId) { $this->generateTableRows($specId); } @@ -950,7 +950,7 @@ public function testTableRowsGenerateWhenDefinedPredicateChanges(): void public function testTableRowsNotGeneratedWhenUndefinedPredicateChanges(): void { - foreach (Config::getInstance()->getTableSpecifications($this->tripod->getStoreName()) as $specId => $spec) { + foreach (array_keys(Config::getInstance()->getTableSpecifications($this->tripod->getStoreName())) as $specId) { $this->generateTableRows($specId); } @@ -1547,7 +1547,7 @@ public function testSavingMultipleNewEntitiesResultsInOneImpactedSubject(): void public function testRemoveTableSpecDoesNotAffectInvalidation(): void { - foreach (Config::getInstance()->getTableSpecifications($this->tripod->getStoreName()) as $specId => $spec) { + foreach (array_keys(Config::getInstance()->getTableSpecifications($this->tripod->getStoreName())) as $specId) { $this->generateTableRows($specId); } @@ -1835,12 +1835,8 @@ private function generateMongoTripodTestConfig(): array /** * Generate table rows based off an id. - * - * @param string $id - * - * @return array */ - private function generateTableRows($id) + private function generateTableRows(string $id): array { $this->tripodTables->generateTableRows($id); diff --git a/test/unit/mongo/MongoTripodTestBase.php b/test/unit/mongo/MongoTripodTestBase.php index 76a0ffe2..4ea78ab3 100644 --- a/test/unit/mongo/MongoTripodTestBase.php +++ b/test/unit/mongo/MongoTripodTestBase.php @@ -138,7 +138,7 @@ protected function getTripodCollection(Driver $tripod): Collection */ protected function getDocument($_id, $collection = null, bool $fromTransactionLog = false): ?array { - if ($fromTransactionLog == true) { + if ($fromTransactionLog) { return $this->tripodTransactionLog->getTransaction($_id); } @@ -166,9 +166,11 @@ protected function assertChangesForGivenSubject(array $changes, $subjectOfChange if (strpos($c['_id']['r'], '_:cs') === false) { continue; } + if ($c['cs:subjectOfChange']['u'] != $subjectOfChange) { continue; } + $changeSet = $c; } @@ -212,9 +214,8 @@ protected function assertTransactionDate(array $doc, string $key): void * @param int|null $expectedValue * @param bool $hasVersion * @param Driver|null $tripod - * @param bool $fromTransactionLog */ - protected function assertDocumentVersion(array $_id, $expectedValue = null, $hasVersion = true, $tripod = null, $fromTransactionLog = false): void + protected function assertDocumentVersion(array $_id, $expectedValue = null, $hasVersion = true, $tripod = null, bool $fromTransactionLog = false): void { // just make sure $_id is aliased $labeller = new Labeller(); @@ -242,7 +243,7 @@ protected function assertDocumentVersion(array $_id, $expectedValue = null, $has * @param Collection|IDriver|null $tripod where to retrieve the document from * @param bool $fromTransactionLog if you want to retrieve the document from transaction log */ - protected function assertDocumentHasProperty(array $_id, $property, $expectedValue = null, $tripod = null, $fromTransactionLog = false): void + protected function assertDocumentHasProperty(array $_id, $property, $expectedValue = null, $tripod = null, bool $fromTransactionLog = false): void { // just make sure $_id is aliased $labeller = new Labeller(); @@ -264,7 +265,7 @@ protected function assertDocumentHasProperty(array $_id, $property, $expectedVal * @param Collection|IDriver|null $tripod where to retrieve the document from * @param bool $fromTransactionLog if you want to retrieve the document from transaction log */ - protected function assertDocumentDoesNotHaveProperty(array $_id, string $property, $tripod = null, $fromTransactionLog = false): void + protected function assertDocumentDoesNotHaveProperty(array $_id, string $property, $tripod = null, bool $fromTransactionLog = false): void { // just make sure $_id is aliased $labeller = new Labeller(); @@ -278,6 +279,7 @@ protected function assertDocumentDoesNotHaveProperty(array $_id, string $propert return; // if document doesn't exist then it doesn't have the property, so assertion is successful } + $this->assertArrayNotHasKey($property, $doc, 'Document for ' . var_export($_id, true) . sprintf(' should not have property [%s], but propert was found', $property)); } @@ -311,46 +313,41 @@ protected function assertDocumentHasBeenDeleted(array $_id, $tripod = null, bool } /** - * @param string $p * @param string $o */ - protected function assertHasLiteralTriple(ExtendedGraph $graph, string $s, $p, $o): void + protected function assertHasLiteralTriple(ExtendedGraph $graph, string $s, string $p, $o): void { $this->assertTrue($graph->has_literal_triple($s, $p, $o), sprintf('Graph did not contain the literal triple: <%s> <%s> "%s"', $s, $p, $o)); } /** - * @param string $p * @param string $o */ - protected function assertHasResourceTriple(ExtendedGraph $graph, string $s, $p, $o): void + protected function assertHasResourceTriple(ExtendedGraph $graph, string $s, string $p, $o): void { $this->assertTrue($graph->has_resource_triple($s, $p, $o), sprintf('Graph did not contain the resource triple: <%s> <%s> <%s>', $s, $p, $o)); } /** - * @param string $p * @param string $o */ - protected function assertDoesNotHaveLiteralTriple(ExtendedGraph $graph, string $s, $p, $o): void + protected function assertDoesNotHaveLiteralTriple(ExtendedGraph $graph, string $s, string $p, $o): void { $this->assertFalse($graph->has_literal_triple($s, $p, $o), sprintf('Graph should not contain the literal triple: <%s> <%s> "%s"', $s, $p, $o)); } /** - * @param string $p * @param string $o */ - protected function assertDoesNotHaveResourceTriple(ExtendedGraph $graph, string $s, $p, $o): void + protected function assertDoesNotHaveResourceTriple(ExtendedGraph $graph, string $s, string $p, $o): void { $this->assertFalse($graph->has_resource_triple($s, $p, $o), sprintf('Graph should not contain the resource triple: <%s> <%s> <%s>', $s, $p, $o)); } /** - * @param string $subject * @param string $transaction_id */ - protected function lockDocument($subject, $transaction_id): void + protected function lockDocument(?string $subject, $transaction_id): void { $collection = Config::getInstance()->getCollectionForLocks('tripod_php_testing'); $labeller = new Labeller(); diff --git a/test/unit/mongo/MongoTripodTransactionRollbackTest.php b/test/unit/mongo/MongoTripodTransactionRollbackTest.php index cd28a884..1b650467 100644 --- a/test/unit/mongo/MongoTripodTransactionRollbackTest.php +++ b/test/unit/mongo/MongoTripodTransactionRollbackTest.php @@ -441,7 +441,7 @@ public function lockSingleDocumentCauseFailureCallback($s, $transactionId, $cont * * @return array */ - public function lockSingleDocumentCallback($s, $transaction_id, $contextAlias) + public function lockSingleDocumentCallback(?string $s, $transaction_id, $contextAlias) { $lCollection = Config::getInstance()->getCollectionForLocks($this->tripod->getStoreName()); $countEntriesInLocksCollection = $lCollection->count(['_id' => [_ID_RESOURCE => $this->labeller->uri_to_alias($s), _ID_CONTEXT => $contextAlias]]); diff --git a/test/unit/mongo/TriplesUtilTest.php b/test/unit/mongo/TriplesUtilTest.php index 44d685fb..2be30ec1 100644 --- a/test/unit/mongo/TriplesUtilTest.php +++ b/test/unit/mongo/TriplesUtilTest.php @@ -33,7 +33,7 @@ public function testGetTArrayAbout(): void 'l' => '1548-774X', ], ]; - $this->assertEquals($expectedDoc, $tu->getTArrayAbout('http://serials.talisaspire.com/issn/0893-0465', $triples, 'http://talisaspire.com/')); + $this->assertSame($expectedDoc, $tu->getTArrayAbout('http://serials.talisaspire.com/issn/0893-0465', $triples, 'http://talisaspire.com/')); } // todo: add triples test From 1922094562045bbd7136d3b7f5899cb2c85fda10 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Thu, 12 Mar 2026 11:49:13 +0000 Subject: [PATCH 29/56] Refactor how eTag is computed --- src/mongo/Driver.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index 7662df41..54d45912 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -496,14 +496,11 @@ public function getETag(string $resource, ?string $context = null): string return ''; } - // PHP 5.3 used MongoDate::__toString() to generate the etag. - // This is incompatible with UTCDate::__toString() so we convert it into a microtime representation. - // This ensures that if it is required to dual run 2 PHP versions, there are no etag compatibility issues. - // Note that MongoDate doesn't go to 8 decimal place precision but still returns it so we go to 6 and pad - // with an extra 2 - $seconds = $lastUpdatedDate->__toString() / 1000; - - return str_pad(number_format($seconds - floor($seconds), 6), 10, '0', STR_PAD_RIGHT) . ' ' . floor($seconds); + $milliseconds = (int) $lastUpdatedDate->__toString(); + $seconds = intdiv($milliseconds, 1000); + $fraction = ($milliseconds % 1000) / 1000; + + return sprintf('%.8f %d', $fraction, $seconds); } public function getTripodViews(): Views From 78db71808d3dbcba92b3268b6b3826e3838739ed Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Thu, 12 Mar 2026 11:50:30 +0000 Subject: [PATCH 30/56] Docblock and logic fixes --- src/Config.php | 4 +- src/IDriver.php | 2 +- src/ITripodStat.php | 24 +-- src/classes/ChangeSet.php | 55 +++---- src/classes/ExtendedGraph.php | 7 +- src/classes/Timer.php | 24 +-- src/mongo/Config.php | 8 +- src/mongo/Driver.php | 2 +- src/mongo/JobGroup.php | 4 +- src/mongo/MongoGraph.php | 20 +-- src/mongo/base/DriverBase.php | 150 +++++------------- src/mongo/base/JobBase.php | 29 +--- src/mongo/delegates/SearchDocuments.php | 3 - src/mongo/delegates/SearchIndexer.php | 3 - src/mongo/delegates/Tables.php | 21 +-- src/mongo/delegates/TransactionLog.php | 21 +-- src/mongo/delegates/Updates.php | 31 +--- src/mongo/delegates/Views.php | 14 +- src/mongo/jobs/EnsureIndexes.php | 7 +- src/mongo/providers/ISearchProvider.php | 6 +- src/mongo/providers/MongoSearchProvider.php | 31 ++-- src/mongo/util/TriplesUtil.php | 6 +- test/stubs.php | 3 - test/unit/mongo/EnsureIndexesTest.php | 16 +- test/unit/mongo/IndexUtilsTest.php | 3 +- test/unit/mongo/MongoGraphTest.php | 13 +- test/unit/mongo/MongoTripodDriverTest.php | 1 - test/unit/mongo/MongoTripodTestBase.php | 23 +-- .../MongoTripodTransactionRollbackTest.php | 8 +- test/unit/mongo/MongoTripodViewsTest.php | 20 +-- 30 files changed, 159 insertions(+), 400 deletions(-) diff --git a/src/Config.php b/src/Config.php index fa608afc..bd81c555 100644 --- a/src/Config.php +++ b/src/Config.php @@ -15,9 +15,9 @@ class Config implements ITripodConfig private static $configInstance; /** - * @var array + * @var array|null */ - private static $config = []; + private static $config; /** * Config should not be instantiated directly: use Config::getInstance(). diff --git a/src/IDriver.php b/src/IDriver.php index da8ee76e..4fc222dd 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -102,7 +102,7 @@ public function saveChanges(ExtendedGraph $oldGraph, ExtendedGraph $newGraph, ?s /** * Register an event hook, which will be executed when the event fires. */ - public function registerHook(string $eventType, IEventHook $hook); + public function registerHook(string $eventType, IEventHook $hook): void; // START Deprecated methods that will be removed in 1.x.x diff --git a/src/ITripodStat.php b/src/ITripodStat.php index c778e855..007a0c8f 100644 --- a/src/ITripodStat.php +++ b/src/ITripodStat.php @@ -7,28 +7,16 @@ interface ITripodStat { /** - * @param string $operation - * @param int|number $inc Amount to increment by - * - * @return void + * @param int $inc Amount to increment by */ - public function increment($operation, $inc = 1); + public function increment(string $operation, int $inc = 1): void; /** - * @param string $operation - * @param number $duration - * - * @return void + * @param float|int $duration */ - public function timer($operation, $duration); + public function timer(string $operation, $duration): void; - /** - * @return array - */ - public function getConfig(); + public function getConfig(): array; - /** - * @return ITripodStat - */ - public static function createFromConfig(array $config); + public static function createFromConfig(array $config): ITripodStat; } diff --git a/src/classes/ChangeSet.php b/src/classes/ChangeSet.php index f5eac9b3..e672a88e 100644 --- a/src/classes/ChangeSet.php +++ b/src/classes/ChangeSet.php @@ -12,10 +12,31 @@ */ class ChangeSet extends ExtendedGraph { + /** @var array> */ public $before = []; + /** @var array> */ public $after = []; + /** + * @var array{ + * subjectOfChange?: string, + * createdDate?: string, + * creatorName?: string, + * changeReason?: string, + * after?: array, + * before?: array, + * after_rdfxml?: string, + * before_rdfxml?: string, + * properties?: array, + * 'http://purl.org/dc/terms/source'?: string|array + * } + */ + public $a; + + /** @var array> */ + public $_index = []; + /** * Create a new changeset. This will calculate the required additions and removals based on before and after versions of a bounded description. The args parameter is an associative array that may have the following fields: *
    @@ -41,30 +62,6 @@ class ChangeSet extends ExtendedGraph * * @param array $a args an associative array of parameters to use when constructing the changeset */ - public $a; - - public $subjectIndex = []; - - public $_index = []; - - protected $subjectOfChange; - - protected $before_rdfxml; - - protected $after_rdfxml; - - protected $createdDate; - - protected $creatorName; - - protected $changeReason; - - protected $has_changes = false; - - protected $cs_resource; - - protected $include_count = 0; - public function __construct(array $a) { parent::__construct(); @@ -100,7 +97,7 @@ public function __construct(array $a) $this->__init(); } - protected function __init() + protected function __init(): void { $csIndex = []; $CSNS = 'http://purl.org/vocab/changeset/schema#'; @@ -189,10 +186,10 @@ protected function __init() /** * adds a triple to the internal simpleIndex holding all the changesets and statements. * - * @param string $s Subject uri - * @param string $p Predicate URI - * @param string $o Object URI or literal value - * @param string $o_type + * @param string $s Subject uri + * @param string $p Predicate URI + * @param array|string $o Object URI or literal value + * @param string $o_type Object type (bnode, uri, literal) * * @author Keith */ diff --git a/src/classes/ExtendedGraph.php b/src/classes/ExtendedGraph.php index c7bf1616..11dddd76 100644 --- a/src/classes/ExtendedGraph.php +++ b/src/classes/ExtendedGraph.php @@ -1060,10 +1060,9 @@ public function reify(array $resources, string $nodeID_prefix = 'Statement'): ar } /** - * diff - * returns a simpleIndex consisting of all the statements in array1 that weren't found in any of the subsequent arrays. + * returns a simpleIndex consisting of all the statements from the first array that weren't found in any of the subsequent arrays. * - * @param array1, array2, [array3, ...] + * @param array ...$indices If only one array is passed then the diff is taken against the graph's own index, otherwise the diff is taken against the first array passed as a parameter * * @author Keith */ @@ -1116,7 +1115,7 @@ public function diff(array ...$indices): array * merge * merges all rdf/json-style arrays passed as parameters. * - * @param array1, array2, [array3, ...] + * @param array ...$indices If only one array is passed then the merge is done against the graph's own index, otherwise the merge is done against the first array passed as a parameter * * @author Keith */ diff --git a/src/classes/Timer.php b/src/classes/Timer.php index 3b498268..4cacfbf8 100644 --- a/src/classes/Timer.php +++ b/src/classes/Timer.php @@ -9,22 +9,22 @@ class Timer { /** - * @var string, start time of event as returned from php microtime() + * @var string start time of event as returned from php microtime() */ private $start_time; /** - * @var string, end time of event as returned from php microtime() + * @var string end time of event as returned from php microtime() */ private $end_time; /** - * @var int, difference in milliseconds of event's start time and end time + * @var int difference in milliseconds of event's start time and end time */ private $result; /** - * @var int, difference in micro-seconds of event's start time and end time + * @var int difference in micro-seconds of event's start time and end time */ private $micro_result; @@ -47,11 +47,11 @@ public function stop(): void /** * Calculate difference between start and end time of event and return in milli-seconds. * - * @return number time difference in milliseconds between start and end time of event + * @return int time difference in milliseconds between start and end time of event * - * @throws \Exception + * @throws \Exception If either of or both of start or stop method are not called before this method */ - public function result() + public function result(): int { if (is_null($this->start_time)) { throw new \Exception('Timer: start method not called !'); @@ -67,7 +67,7 @@ public function result() $differenceInMilliSeconds = ((float) $endTimeSeconds - (float) $startTimeSeconds) * 1000; - $this->result = round(($differenceInMilliSeconds + ((float) $endTimeMicroSeconds * 1000)) - (float) $startTimeMicroSeconds * 1000); + $this->result = (int) round(($differenceInMilliSeconds + ((float) $endTimeMicroSeconds * 1000)) - (float) $startTimeMicroSeconds * 1000); } return $this->result; @@ -76,11 +76,11 @@ public function result() /** * Calculate difference between start and end time of event and return in micro-seconds. * - * @return number time difference in micro seconds between start and end time of event + * @return int time difference in micro seconds between start and end time of event * - * @throws \Exception, if either of or both of start or stop method are not called before this method + * @throws \Exception If either of or both of start or stop method are not called before this method */ - public function microResult() + public function microResult(): int { if (is_null($this->start_time)) { throw new TimerException('Timer: start method not called !'); @@ -96,7 +96,7 @@ public function microResult() $differenceInMicroSeconds = ((float) $endTimeSeconds - (float) $startTimeSeconds) * 1000000; - $this->micro_result = round(($differenceInMicroSeconds + ((float) $endTimeMicroSeconds * 1000000)) - (float) $startTimeMicroSeconds * 1000000); + $this->micro_result = (int) round(($differenceInMicroSeconds + ((float) $endTimeMicroSeconds * 1000000)) - (float) $startTimeMicroSeconds * 1000000); } return $this->micro_result; diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 35ddcee9..130c5cf5 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -1256,7 +1256,7 @@ protected function validateTableSpecPart(array $spec, int $depth = 0): void throw new ConfigException('Computed field spec contains more than one function'); } - if ($validationLevel === self::VALIDATE_MAX) { + if ($validationLevel === self::VALIDATE_MAX && isset($availableFields)) { $this->validateComputedFieldSpec($functions[0], $field['value'], $availableFields); } } @@ -1708,8 +1708,8 @@ protected function getConnectionForDataSource(string $dataSource): Client } } while ($retries <= self::CONNECTION_RETRIES); - if (!isset($this->connections[$dataSource])) { - self::getLogger()->error('MongoConnectionException failed after ' . $retries . ' attempts (MAX:' . self::CONNECTION_RETRIES . '): ' . $e->getMessage()); + if (!isset($this->connections[$dataSource]) && $exception !== null) { + self::getLogger()->error('MongoConnectionException failed after ' . $retries . ' attempts (MAX:' . self::CONNECTION_RETRIES . '): ' . $exception->getMessage()); throw $exception; } @@ -1819,7 +1819,7 @@ private static function getQueueName(string $envVar, string $type): string private static function getenv(string $env, $default = false) { $var = getenv($env); - if (isset($var) && $var != '') { + if ($var) { return $var; } diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index 54d45912..250b70ca 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -226,7 +226,7 @@ public function getLockedDocuments(?string $fromDateTime = null, ?string $tillDa /** * Remove locks that are there forever, creates a audit entry to keep track who and why removed these locks. * - * @throws \Exception, if something goes wrong when unlocking documents, or creating audit entries + * @throws \Exception If something goes wrong when unlocking documents, or creating audit entries */ public function removeInertLocks(string $transaction_id, string $reason): bool { diff --git a/src/mongo/JobGroup.php b/src/mongo/JobGroup.php index 1af612a6..68726938 100644 --- a/src/mongo/JobGroup.php +++ b/src/mongo/JobGroup.php @@ -67,9 +67,7 @@ public function incrementJobCount($inc = 1) return $updateResult['count']; } - if (isset($updateResult->count)) { - return $updateResult->count; - } + return $updateResult->count; } /** diff --git a/src/mongo/MongoGraph.php b/src/mongo/MongoGraph.php index 32e7e03e..f06ffb73 100644 --- a/src/mongo/MongoGraph.php +++ b/src/mongo/MongoGraph.php @@ -48,17 +48,9 @@ public function to_nquads($context): string /** * Adds the tripod array(s) to this graph. * This method is used to add individual tripod documents, or a series of tripod array documents that are embedded in a view. - * - * @param mixed $tarray - * - * @throws Exception */ - public function add_tripod_array($tarray): void + public function add_tripod_array(array $tarray): void { - if (!is_array($tarray)) { - throw new Exception('Value passed to add_tripod_array is not of type array'); - } - // need to convert from tripod storage format to rdf/json as php array format if (isset($tarray['value'][_GRAPHS])) { // iterate add add each graph @@ -72,11 +64,8 @@ public function add_tripod_array($tarray): void /** * Returns a mongo-ready doc for a single CBD. - * - * @param mixed $docId - * @param mixed $context */ - public function to_tripod_array($docId, ?string $context): ?array + public function to_tripod_array(string $docId, ?string $context): ?array { $docId = $this->_labeller->qname_to_alias($docId); $contextAlias = $this->_labeller->uri_to_alias($context); @@ -98,12 +87,9 @@ public function to_tripod_array($docId, ?string $context): ?array /** * Returns a mongo-ready doc for views, which can have multiple graphs in the same doc. * - * @param mixed $docId - * @param mixed $context - * * @return array */ - public function to_tripod_view_array($docId, ?string $context): array + public function to_tripod_view_array(string $docId, ?string $context): array { $subjects = $this->get_subjects(); $contextAlias = $this->_labeller->uri_to_alias($context); diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index 053638a8..079c9da5 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -84,13 +84,10 @@ abstract class DriverBase */ protected $config; - /** - * @return ITripodStat - */ - public function getStat() + public function getStat(): ITripodStat { if ($this->stat == null) { - $this->setStat($this->getStatFromStatFactory($this->statsConfig)); + $this->setStat($this->getStatFromStatFactory()); } return $this->stat; @@ -108,10 +105,8 @@ public function setStat(ITripodStat $stat): void /** * Returns stat object config. - * - * @return array */ - public function getStatsConfig() + public function getStatsConfig(): array { $stat = $this->getStat(); if ($stat) { @@ -121,90 +116,65 @@ public function getStatsConfig() return $this->statsConfig; } - /** - * @return string - */ - public function getStoreName() + public function getStoreName(): string { return $this->storeName; } - /** - * @return string - */ - public function getPodName() + public function getPodName(): string { return $this->podName; } /** - * @param string $type - * @param array|null $params - * * @codeCoverageIgnore */ - public function timingLog($type, $params = null): void + public function timingLog(string $type, ?array $params = null): void { $type = '[PID ' . getmypid() . '] ' . $type; $this->log(LogLevel::DEBUG, $type, $params); } /** - * @param array|null $params - * @param mixed $message - * * @codeCoverageIgnore */ - public function infoLog($message, $params = null): void + public function infoLog(string $message, ?array $params = null): void { $message = '[PID ' . getmypid() . '] ' . $message; $this->log(LogLevel::INFO, $message, $params); } /** - * @param array|null $params - * @param mixed $message - * * @codeCoverageIgnore */ - public function debugLog($message, $params = null): void + public function debugLog(string $message, ?array $params = null): void { $message = '[PID ' . getmypid() . '] ' . $message; $this->log(LogLevel::DEBUG, $message, $params); } /** - * @param string $message - * @param array|null $params - * * @codeCoverageIgnore */ - public function errorLog($message, $params = null): void + public function errorLog(string $message, ?array $params = null): void { $message = '[PID ' . getmypid() . '] ' . $message; $this->log(LogLevel::ERROR, $message, $params); } /** - * @param string $message - * @param array|null $params - * * @codeCoverageIgnore */ - public function warningLog($message, $params = null): void + public function warningLog(string $message, ?array $params = null): void { $message = '[PID ' . getmypid() . '] ' . $message; $this->log(LogLevel::WARNING, $message, $params); } /** - * @static - * - * @return LoggerInterface - * * @codeCoverageIgnore */ - public static function getLogger() + public static function getLogger(): LoggerInterface { if (self::$logger == null) { $log = new Logger('TRIPOD'); @@ -216,46 +186,25 @@ public static function getLogger() /** * For mocking out the creation of stat objects. - * - * @return ITripodStat */ - protected function getStatFromStatFactory(array $config) + protected function getStatFromStatFactory(): ITripodStat { return TripodStatFactory::create($this->statsConfig); } - /** - * @param int $secs - * - * @return int - */ - protected function getExpirySecFromNow($secs) + protected function getExpirySecFromNow(int $secs): int { return time() + $secs; } - /** - * @param string|null $context - * - * @return mixed - */ - protected function getContextAlias($context = null) + protected function getContextAlias(?string $context = null): string { $contextAlias = $this->labeller->uri_to_alias((empty($context)) ? $this->defaultContext : $context); return (empty($contextAlias)) ? $this->getConfigInstance()->getDefaultContextAlias() : $contextAlias; } - /** - * @param array $query - * @param string $type - * @param Collection|null $collection - * @param array $includeProperties - * @param int $cursorSize - * - * @return MongoGraph - */ - protected function fetchGraph(array $query, $type, $collection = null, $includeProperties = [], $cursorSize = 101) + protected function fetchGraph(array $query, string $type, ?Collection $collection = null, ?array $includeProperties = [], int $cursorSize = 101): MongoGraph { $graph = new MongoGraph(); @@ -315,8 +264,8 @@ protected function fetchGraph(array $query, $type, $collection = null, $includeP } } while ($retries <= Config::CONNECTION_RETRIES && $cursorSuccess === false); - if ($cursorSuccess === false) { - self::getLogger()->error('CursorException failed after ' . $retries . ' attempts (MAX:' . Config::CONNECTION_RETRIES . '): ' . $e->getMessage()); + if ($cursorSuccess === false && $exception !== null) { + self::getLogger()->error('CursorException failed after ' . $retries . ' attempts (MAX:' . Config::CONNECTION_RETRIES . '): ' . $exception->getMessage()); throw $exception; } @@ -344,11 +293,8 @@ protected function fetchGraph(array $query, $type, $collection = null, $includeP /** * Expands an RDF sequence into proper tripod join clauses. - * - * @param array $joins - * @param array $source */ - protected function expandSequence(&$joins, array $source) + protected function expandSequence(array &$joins, array $source): void { if (!empty($joins) && isset($joins['followSequence'])) { // add any rdf:_x style properties in the source to the joins array, @@ -376,13 +322,9 @@ protected function expandSequence(&$joins, array $source) /** * Adds an _id object (or array of _id objects) to the target document's impact index. * - * @param array &$target - * @param mixed $buildImpactIndex - * @param array $id - * * @throws \InvalidArgumentException */ - protected function addIdToImpactIndex(array $id, array &$target, $buildImpactIndex = true) + protected function addIdToImpactIndex(array $id, array &$target, bool $buildImpactIndex = true): void { if ($buildImpactIndex) { if (isset($id[_ID_RESOURCE])) { @@ -409,18 +351,13 @@ protected function addIdToImpactIndex(array $id, array &$target, $buildImpactInd /** * For mocking. - * - * @return IConfigInstance */ - protected function getConfigInstance() + protected function getConfigInstance(): IConfigInstance { return \Tripod\Config::getInstance(); } - /** - * @return Database - */ - protected function getDatabase() + protected function getDatabase(): Database { if ($this->db === null) { $this->db = $this->config->getDatabase( @@ -433,10 +370,7 @@ protected function getDatabase() return $this->db; } - /** - * @return Collection - */ - protected function getCollection() + protected function getCollection(): Collection { if ($this->collection === null) { $this->collection = $this->getDatabase()->selectCollection($this->podName); @@ -445,7 +379,12 @@ protected function getCollection() return $this->collection; } - protected function applyHooks($fn, $hooks, $args = []) + /** + * @param IEventHook[] $hooks + * + * @throws Exception If an invalid hook function is requested + */ + protected function applyHooks(string $fn, array $hooks, array $args = []): void { switch ($fn) { case $this::HOOK_FN_PRE: @@ -459,8 +398,7 @@ protected function applyHooks($fn, $hooks, $args = []) foreach ($hooks as $hook) { try { - // @var $hook IEventHook - $hook->{$fn}($args); + call_user_func([$hook, $fn], $args); } catch (\Exception $e) { // don't let rabid hooks stop tripod static::getLogger()->error('Hook ' . get_class($hook) . sprintf(' threw exception %s, continuing', $e->getMessage())); @@ -469,13 +407,11 @@ protected function applyHooks($fn, $hooks, $args = []) } /** - * @param array|null $params - * * @codeCoverageIgnore */ - private function log(string $level, string $message, $params): void + private function log(string $level, string $message, ?array $params): void { - ($params == null) ? self::getLogger()->log($level, $message) : self::getLogger()->log($level, $message, $params); + self::getLogger()->log($level, $message, $params ?: []); } } @@ -486,36 +422,25 @@ final class NoStat implements ITripodStat */ public static $instance; - /** - * @param string $operation - * @param int|number $inc - */ - public function increment($operation, $inc = 1): void + public function increment(string $operation, int $inc = 1): void { // do nothing } /** - * @param string $operation - * @param number $duration + * @param float|int $duration */ - public function timer($operation, $duration): void + public function timer(string $operation, $duration): void { // do nothing } - /** - * @return array{} - */ public function getConfig(): array { return []; } - /** - * @return self - */ - public static function getInstance() + public static function getInstance(): self { if (self::$instance == null) { self::$instance = new NoStat(); @@ -524,10 +449,7 @@ public static function getInstance() return self::$instance; } - /** - * @return NoStat - */ - public static function createFromConfig(array $config = []) + public static function createFromConfig(array $config = []): self { return self::getInstance(); } diff --git a/src/mongo/base/JobBase.php b/src/mongo/base/JobBase.php index ff130bac..9b058eec 100644 --- a/src/mongo/base/JobBase.php +++ b/src/mongo/base/JobBase.php @@ -90,8 +90,6 @@ abstract public function perform(); /** * Called in every job prior to perform(). - * - * @param \Resque_Job The queued job */ public static function beforePerform(\Resque_Job $job): void { @@ -120,28 +118,7 @@ public static function onFailure($e, \Resque_Job $job): void $failedJob->getStat()->increment($failedJob->getStatFailureIncrementKey()); } - /** - * @param string $message Log message - * @param mixed $params Log params - */ - public function debugLog($message, $params = null): void - { - parent::debugLog($message, $params); - } - - /** - * @param string $message Log message - * @param mixed $params Log params - */ - public function errorLog($message, $params = null): void - { - parent::errorLog($message, $params); - } - - /** - * @return ITripodStat - */ - public function getStat() + public function getStat(): ITripodStat { if ($this->statsConfig === null) { $this->getStatsConfig(); @@ -152,10 +129,8 @@ public function getStat() /** * Gets the stats config for the job. - * - * @return array */ - public function getStatsConfig() + public function getStatsConfig(): array { if ($this->statsConfig === []) { $this->setStatsConfig(); diff --git a/src/mongo/delegates/SearchDocuments.php b/src/mongo/delegates/SearchDocuments.php index 22043e3c..19156648 100644 --- a/src/mongo/delegates/SearchDocuments.php +++ b/src/mongo/delegates/SearchDocuments.php @@ -274,9 +274,6 @@ protected function addFields(array $source, array $fieldsOrIndices, array &$targ } } - /** - * @param mixed $specId - */ protected function getSearchDocumentSpecification(string $specId): ?array { return $this->getConfigInstance()->getSearchDocumentSpecification($this->storeName, $specId); diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 1ef65e83..853d32f6 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -184,9 +184,6 @@ public function generateSearchDocuments( } $filter = ['$or' => $types]; - if (isset($resource)) { - $filter['_id'] = [_ID_RESOURCE => $this->labeller->uri_to_alias($resource), _ID_CONTEXT => $contextAlias]; - } $count = $this->getConfigInstance()->getCollectionForCBD($this->getStoreName(), $from)->count($filter); $docs = $this->getConfigInstance() diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index 4f0a305d..fe39f9b6 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -102,8 +102,6 @@ public function __construct( /** * Receive update from subject. - * - * @param ImpactedSubject */ public function update(ImpactedSubject $subject): void { @@ -662,15 +660,12 @@ protected function truncateFields(Collection $collection, array &$generatedRow) // Find the name of any indexed fields $indexedFields = []; $indexesGroupedByCollection = $this->config->getIndexesGroupedByCollection($this->storeName); - if (isset($indexesGroupedByCollection, $indexesGroupedByCollection[$collection->getCollectionName()])) { - $indexes = $indexesGroupedByCollection[$collection->getCollectionName()]; - if (isset($indexes)) { - foreach ($indexes as $repset) { - foreach ($repset as $index) { - foreach ($index as $indexedFieldname => $v) { - if (strpos($indexedFieldname, 'value.') === 0) { - $indexedFields[] = substr($indexedFieldname, strlen('value.')); - } + if (isset($indexesGroupedByCollection[$collection->getCollectionName()])) { + foreach ($indexesGroupedByCollection[$collection->getCollectionName()] as $repset) { + foreach ($repset as $index) { + foreach ($index as $indexedFieldname => $v) { + if (strpos($indexedFieldname, 'value.') === 0) { + $indexedFields[] = substr($indexedFieldname, strlen('value.')); } } } @@ -1239,11 +1234,9 @@ protected function doJoins(array $source, $joins, &$dest, $from, $contextAlias) /** * Add counts to $dest by counting what is in $source according to $countSpec. * - * @param mixed $source - * @param mixed $countSpec * @param int[] $dest */ - protected function doCounts(array $source, $countSpec, array &$dest) + protected function doCounts(array $source, array $countSpec, array &$dest): void { // process count aggregate function foreach ($countSpec as $c) { diff --git a/src/mongo/delegates/TransactionLog.php b/src/mongo/delegates/TransactionLog.php index 5d645815..f7236e8a 100644 --- a/src/mongo/delegates/TransactionLog.php +++ b/src/mongo/delegates/TransactionLog.php @@ -4,17 +4,22 @@ namespace Tripod\Mongo; +use MongoDB\Collection; +use MongoDB\Database; use MongoDB\Driver\Cursor; use MongoDB\InsertOneResult; -use MongoDB\UpdateOneResult; +use MongoDB\UpdateResult; use Tripod\Config; class TransactionLog { + /** @var IConfigInstance */ protected $config; + /** @var Database */ private $transaction_db; + /** @var Collection */ private $transaction_collection; /** @@ -202,13 +207,9 @@ public function getCompletedTransactionCount($storeName = null, $podName = null) /** * Proxy method to help with test mocking. * - * @param array $transaction - * - * @return InsertOneResult - * * @codeCoverageIgnore */ - protected function insertTransaction($transaction) + protected function insertTransaction(array $transaction): InsertOneResult { return $this->transaction_collection->insertOne($transaction, ['w' => 1]); } @@ -216,15 +217,9 @@ protected function insertTransaction($transaction) /** * Proxy method to help with test mocking. * - * @param array $query - * @param array $update - * @param array $options - * - * @return UpdateOneResult - * * @codeCoverageIgnore */ - protected function updateTransaction($query, $update, $options) + protected function updateTransaction(array $query, array $update, array $options): UpdateResult { return $this->transaction_collection->updateOne($query, $update, $options); } diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index fa0de4d8..2fbe172f 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -267,7 +267,7 @@ public function getLockedDocuments($fromDateTime = null, $tillDateTime = null): * * @param string $reason * - * @throws \Exception, if something goes wrong when unlocking documents, or creating audit entries + * @throws \Exception If something goes wrong when unlocking documents, or creating audit entries */ public function removeInertLocks(string $transaction_id, $reason): bool { @@ -1170,20 +1170,6 @@ protected function updateCollection($query, $update, array $options) return $this->getCollection()->replaceOne($query, $update, $options); } - /** - * Returns the context alias curie for the supplied context or default context. - * - * @param string|null $context - * - * @return string - */ - protected function getContextAlias($context = null) - { - $contextAlias = $this->labeller->uri_to_alias((empty($context)) ? $this->defaultContext : $context); - - return (empty($contextAlias)) ? $this->getConfigInstance()->getDefaultContextAlias() : $contextAlias; - } - /** * @return Database */ @@ -1210,8 +1196,6 @@ protected function getLocksCollection() /** * Helper function to group the changes for $changeUri by namespaced predicate, then by additions and removals. - * - * @param mixed $changeUri */ private function getAdditionsRemovalsGroupedByNsPredicate(ChangeSet $cs, string $changeUri): array { @@ -1241,8 +1225,7 @@ private function getAdditionsRemovalsGroupedByNsPredicate(ChangeSet $cs, string /** * Helper method to group changes for $changeUri of a given type by namespaced predicate. * - * @param mixed $changeUri - * @param mixed $changePredicate + * @param array|string $changePredicate * * @throws Exception */ @@ -1279,7 +1262,6 @@ private function getChangesGroupedByNsPredicate(ChangeSet $cs, string $changeUri * Helper method to add operator to a set of existing changes ready to be sent to Mongo. * * @param array $changes - * @param mixed $operator * @param array|array $kvp */ private function addOperatorToChange(array &$changes, string $operator, array $kvp): void @@ -1290,10 +1272,13 @@ private function addOperatorToChange(array &$changes, string $operator, array $k foreach ($kvp as $key => $value) { if (isset($changes[$operator][$key])) { - $value = array_merge($value, $changes[$operator][$key]); + if (!is_array($changes[$operator][$key])) { + $changes[$operator][$key] = [$changes[$operator][$key]]; + } + $changes[$operator][$key][] = $value; + } else { + $changes[$operator][$key] = $value; } - - $changes[$operator][$key] = $value; } } diff --git a/src/mongo/delegates/Views.php b/src/mongo/delegates/Views.php index 7a87f381..126a3232 100644 --- a/src/mongo/delegates/Views.php +++ b/src/mongo/delegates/Views.php @@ -44,8 +44,6 @@ public function getOperationType(): string /** * Receive update from subject. - * - * @param ImpactedSubject */ public function update(ImpactedSubject $subject): void { @@ -508,15 +506,8 @@ public function count(string $viewSpec, array $filters = []): int /** * Joins data to $dest from $source according to specification in $joins, or queries DB if data is not available in $source. - * - * @param bool $buildImpactIndex - * @param mixed $source - * @param mixed $joins - * @param array $dest - * @param mixed $from - * @param mixed $contextAlias */ - protected function doJoins(array $source, $joins, array &$dest, $from, $contextAlias, $buildImpactIndex = true) + protected function doJoins(array $source, array $joins, array &$dest, string $from, string $contextAlias, bool $buildImpactIndex = true) { // expand sequences before doing any joins... $this->expandSequence($joins, $source); @@ -747,9 +738,6 @@ protected function getCollectionForViewSpec(string $viewSpecId): Collection return $this->getConfigInstance()->getCollectionForView($this->storeName, $viewSpecId); } - /** - * @param array|string $resourceUriOrArray - */ private function createTripodViewIdsFromResourceUris(array $resourceUriOrArray, ?string $context, string $viewType): array { $contextAlias = $this->getContextAlias($context); diff --git a/src/mongo/jobs/EnsureIndexes.php b/src/mongo/jobs/EnsureIndexes.php index 40feb8ad..6425fd4c 100644 --- a/src/mongo/jobs/EnsureIndexes.php +++ b/src/mongo/jobs/EnsureIndexes.php @@ -36,13 +36,8 @@ public function perform(): void /** * This method is use to schedule an EnsureIndexes job. - * - * @param string $storeName - * @param booelan $reindex - * @param string $queueName - * @param mixed $background */ - public function createJob($storeName, $reindex, $background, $queueName = null): void + public function createJob(string $storeName, bool $reindex, bool $background, ?string $queueName = null): void { $configInstance = $this->getConfigInstance(); if (!$queueName) { diff --git a/src/mongo/providers/ISearchProvider.php b/src/mongo/providers/ISearchProvider.php index ff17ca77..72186ac9 100644 --- a/src/mongo/providers/ISearchProvider.php +++ b/src/mongo/providers/ISearchProvider.php @@ -58,18 +58,18 @@ public function findImpactedDocuments(array $resourcesAndPredicates, $context); * duration - the time it took to execute the query and build the result structure * results - an array of results. * - * @param string $q the query as input by a user + * @param string $query the query as input by a user * @param string $type the search document type to restrict results in other words _id.type * @param array $indices an array of indices (from spec) to match query terms against, must specify at least one * @param array $fields an array of the fields (from spec) you want included in the search results * @param int $limit the number of results to return per page * @param int $offset the offset to skip to * - * @return mixed a structure representing the search results + * @return array a structure representing the search results * * @throws SearchException if there was an error performing the search, or if the parameters are invalid */ - public function search($q, $type, $indices = [], $fields = [], $limit = 10, $offset = 0); + public function search(string $query, string $type, array $indices = [], array $fields = [], int $limit = 10, int $offset = 0): array; /** * Removes all documents from search index based on the specified type id. diff --git a/src/mongo/providers/MongoSearchProvider.php b/src/mongo/providers/MongoSearchProvider.php index c9cc896c..6ad83cc4 100644 --- a/src/mongo/providers/MongoSearchProvider.php +++ b/src/mongo/providers/MongoSearchProvider.php @@ -368,20 +368,11 @@ public function findImpactedDocuments(array $resourcesAndPredicates, $context): } /** - * @param string $q - * @param string $type - * @param array $indices - * @param array $fields - * @param int $limit - * @param int $offset - * - * @return array|mixed - * * @throws SearchException */ - public function search($q, $type, $indices = [], $fields = [], $limit = 10, $offset = 0): array + public function search(string $query, string $type, array $indices = [], array $fields = [], int $limit = 10, int $offset = 0): array { - if (empty($q)) { + if (empty($query)) { throw new SearchException('You must specify a query'); } @@ -405,7 +396,7 @@ public function search($q, $type, $indices = [], $fields = [], $limit = 10, $off throw new SearchException('Value for offset must be a positive number'); } - $original_terms = explode(' ', trim(strtolower($q))); + $original_terms = explode(' ', trim(strtolower($query))); $terms = array_values(array_diff($original_terms, $this->stopWords)); // todo: this means if all the words entered were stop words, then use the orginal terms rather than do nothing! @@ -418,16 +409,16 @@ public function search($q, $type, $indices = [], $fields = [], $limit = 10, $off $regexes[] = new Regex($t, ''); } - $query = []; - $query['_id.type'] = $type; + $filter = []; + $filter['_id.type'] = $type; if (count($indices) === 1) { $searchIndex = $indices[0]; - $query[$searchIndex] = ['$all' => $regexes]; + $filter[$searchIndex] = ['$all' => $regexes]; } else { - $query['$or'] = []; + $filter['$or'] = []; foreach ($indices as $searchIndex) { - $query['$or'][] = [$searchIndex => ['$all' => $regexes]]; + $filter['$or'][] = [$searchIndex => ['$all' => $regexes]]; } } @@ -440,7 +431,7 @@ public function search($q, $type, $indices = [], $fields = [], $limit = 10, $off $searchTimer->start(); $cursor = $this->config->getCollectionForSearchDocument($this->storeName, $type) - ->find($query, [ + ->find($filter, [ 'projection' => $fieldsToReturn, 'limit' => $limit, 'skip' => $offset, @@ -452,11 +443,11 @@ public function search($q, $type, $indices = [], $fields = [], $limit = 10, $off $searchResults['head']['limit'] = $limit; $searchResults['head']['offset'] = $offset; $searchResults['head']['duration'] = ''; - $searchResults['head']['query'] = $q; + $searchResults['head']['query'] = $query; $searchResults['head']['query_terms_used'] = $terms; $searchResults['results'] = []; - $count = $this->config->getCollectionForSearchDocument($this->storeName, $type)->count($query); + $count = $this->config->getCollectionForSearchDocument($this->storeName, $type)->count($filter); if ($count > 0) { $searchResults['head']['count'] = $count; diff --git a/src/mongo/util/TriplesUtil.php b/src/mongo/util/TriplesUtil.php index 2c717bdb..a132d706 100644 --- a/src/mongo/util/TriplesUtil.php +++ b/src/mongo/util/TriplesUtil.php @@ -234,11 +234,9 @@ private function isUri($object) } /** - * @param bool|list $parts - * - * @return string + * @param string[] $parts */ - private function extract_object(array $parts) + private function extract_object(array $parts): string { if (!$this->is_object_literal($parts[2])) { return trim($parts[2], '><'); diff --git a/test/stubs.php b/test/stubs.php index 1921eecf..fc269729 100644 --- a/test/stubs.php +++ b/test/stubs.php @@ -4,9 +4,6 @@ namespace Tripod\Mongo; -/** - * @return false|int - */ function sleep(int $seconds): int { return 0; diff --git a/test/unit/mongo/EnsureIndexesTest.php b/test/unit/mongo/EnsureIndexesTest.php index 1f67fdba..ab28c2ec 100644 --- a/test/unit/mongo/EnsureIndexesTest.php +++ b/test/unit/mongo/EnsureIndexesTest.php @@ -33,9 +33,6 @@ protected function setUp(): void * * @group ensure-indexes * - * @param mixed $argument - * @param mixed|null $argumentName - * * @throws Exception */ public function testMandatoryArgs(string $argument, ?string $argumentName = null): void @@ -215,21 +212,12 @@ public function testEnsureIndexesCreateJobSpecifyQueue(): void /** * Creates a simple mock EnsureIndexes Job. * - * @param array list of methods to stub - * @param mixed $methods - * * @return EnsureIndexes&MockObject */ - protected function createMockJob($methods = []): MockObject + protected function createMockJob(array $methods = ['getIndexUtils', 'submitJob', 'warningLog', 'enqueue', 'getJobStatus']): MockObject { - $methodsToStub = ['getIndexUtils', 'submitJob', 'warningLog', 'enqueue', 'getJobStatus']; - - if (!empty($methods)) { - $methodsToStub = $methods; - } - $mockEnsureIndexesJob = $this->getMockBuilder(EnsureIndexes::class) - ->onlyMethods($methodsToStub) + ->onlyMethods($methods) ->setMockClassName('MockEnsureIndexes') ->getMock(); $mockEnsureIndexesJob->job = new Resque_Job('queue', ['id' => uniqid()]); diff --git a/test/unit/mongo/IndexUtilsTest.php b/test/unit/mongo/IndexUtilsTest.php index 4cf8925e..c58643fa 100644 --- a/test/unit/mongo/IndexUtilsTest.php +++ b/test/unit/mongo/IndexUtilsTest.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use MongoDB\Collection; use MongoDB\Driver\Manager; use PHPUnit\Framework\MockObject\MockObject; use Tripod\Mongo\IndexUtils; @@ -314,7 +315,7 @@ protected function createMockIndexUtils($mockConfig): MockObject */ protected function createMockCollection(): MockObject { - return $this->getMockBuilder(MongoDB\Collection::class) + return $this->getMockBuilder(Collection::class) ->onlyMethods(['createIndex', 'dropIndexes']) ->setConstructorArgs([ new Manager('mongodb://fake:27017'), diff --git a/test/unit/mongo/MongoGraphTest.php b/test/unit/mongo/MongoGraphTest.php index 154611e7..5ba65eed 100644 --- a/test/unit/mongo/MongoGraphTest.php +++ b/test/unit/mongo/MongoGraphTest.php @@ -3,6 +3,7 @@ declare(strict_types=1); use Tripod\Config; +use Tripod\Exceptions\Exception; use Tripod\Exceptions\LabellerException; use Tripod\Mongo\MongoGraph; @@ -73,14 +74,6 @@ public function testToNQuadsTwoGraphsWithDifferentContext(): void $this->assertSame($expected, $g->to_nquads('http://wibble.talisaspire.com/')); } - public function testAddTripodArrayThrowsException(): void - { - $this->expectException(Exception::class); - $this->expectExceptionMessage('Value passed to add_tripod_array is not of type array'); - $g = new MongoGraph(); - $g->add_tripod_array(null); - } - public function testAddTripodArraySingleDoc(): void { $doc = [ @@ -218,7 +211,7 @@ public function addTripodArrayContainingInvalidPredicates_Provider(): iterable public function testAddTripodArrayContainingEmptyPredicate(): void { // Should not be able to label '' - $this->expectException(Tripod\Exceptions\Exception::class); + $this->expectException(Exception::class); $this->expectExceptionMessage('The predicate cannot be an empty string'); $doc = [ '_id' => ['r' => 'http://talisaspire.com/works/4d101f63c10a6-2', 'c' => 'http://talisaspire.com/works/4d101f63c10a6-2'], @@ -245,7 +238,7 @@ public function testAddTripodArrayContainingEmptyPredicate(): void */ public function testAddTripodArrayContainingInvalidSubject($value): void { - $this->expectException(Tripod\Exceptions\Exception::class); + $this->expectException(Exception::class); $doc = [ '_id' => ['r' => $value, 'c' => 'http://talisaspire.com/works/4d101f63c10a6-2'], '_version' => 0, diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index 0abad686..fdb27482 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -2250,7 +2250,6 @@ public function testPassStatConfigToTripodConstructor(): void $tripod->expects($this->once()) ->method('getStatFromStatFactory') - ->with($opts['statsConfig']) ->willReturn($mockStat); /** @var StatsD */ diff --git a/test/unit/mongo/MongoTripodTestBase.php b/test/unit/mongo/MongoTripodTestBase.php index 4ea78ab3..2d522796 100644 --- a/test/unit/mongo/MongoTripodTestBase.php +++ b/test/unit/mongo/MongoTripodTestBase.php @@ -209,13 +209,7 @@ protected function assertTransactionDate(array $doc, string $key): void $this->assertNotEmpty($doc[$key]->toDateTime()); } - /** - * @param mixed $_id - * @param int|null $expectedValue - * @param bool $hasVersion - * @param Driver|null $tripod - */ - protected function assertDocumentVersion(array $_id, $expectedValue = null, $hasVersion = true, $tripod = null, bool $fromTransactionLog = false): void + protected function assertDocumentVersion(array $_id, ?int $expectedValue = null, bool $hasVersion = true, ?Driver $tripod = null): void { // just make sure $_id is aliased $labeller = new Labeller(); @@ -223,7 +217,7 @@ protected function assertDocumentVersion(array $_id, $expectedValue = null, $has $_id[$key] = $labeller->uri_to_alias($value); } - $doc = $this->getDocument($_id, $tripod, $fromTransactionLog); + $doc = $this->getDocument($_id, $tripod); if ($hasVersion == true) { $this->assertArrayHasKey('_version', $doc, 'Document for ' . var_export($_id, true) . ' should have a version, but none found'); @@ -237,13 +231,12 @@ protected function assertDocumentVersion(array $_id, $expectedValue = null, $has } /** - * @param array $_id the id of the document to retrieve from mongo - * @param string $property the property you are checking for - * @param mixed $expectedValue if not null the property value will be matched against this expectedValue - * @param Collection|IDriver|null $tripod where to retrieve the document from - * @param bool $fromTransactionLog if you want to retrieve the document from transaction log + * @param array $_id the id of the document to retrieve from mongo + * @param string $property the property you are checking for + * @param mixed $expectedValue if not null the property value will be matched against this expectedValue + * @param Collection|IDriver|null $tripod where to retrieve the document from */ - protected function assertDocumentHasProperty(array $_id, $property, $expectedValue = null, $tripod = null, bool $fromTransactionLog = false): void + protected function assertDocumentHasProperty(array $_id, string $property, $expectedValue = null, $tripod = null): void { // just make sure $_id is aliased $labeller = new Labeller(); @@ -251,7 +244,7 @@ protected function assertDocumentHasProperty(array $_id, $property, $expectedVal $_id[$key] = $labeller->uri_to_alias($value); } - $doc = $this->getDocument($_id, $tripod, $fromTransactionLog); + $doc = $this->getDocument($_id, $tripod); $this->assertArrayHasKey($property, $doc, 'Document for ' . var_export($_id, true) . sprintf(' should have property [%s], but none found', $property)); if ($expectedValue !== null) { diff --git a/test/unit/mongo/MongoTripodTransactionRollbackTest.php b/test/unit/mongo/MongoTripodTransactionRollbackTest.php index 1b650467..a59f30c3 100644 --- a/test/unit/mongo/MongoTripodTransactionRollbackTest.php +++ b/test/unit/mongo/MongoTripodTransactionRollbackTest.php @@ -435,13 +435,9 @@ public function lockSingleDocumentCauseFailureCallback($s, $transactionId, $cont * This is a private method that performs exactly the same operation as Driver::lockSingleDocument, the reason this is duplicated here * is so that we can simulate the correct locking of documents as part of mocking a workflow that will lock a document correctly but not another. * - * @param mixed $s - * @param mixed $transaction_id - * @param mixed $contextAlias - * - * @return array + * @return array|false|null */ - public function lockSingleDocumentCallback(?string $s, $transaction_id, $contextAlias) + public function lockSingleDocumentCallback(?string $s, string $transaction_id, string $contextAlias) { $lCollection = Config::getInstance()->getCollectionForLocks($this->tripod->getStoreName()); $countEntriesInLocksCollection = $lCollection->count(['_id' => [_ID_RESOURCE => $this->labeller->uri_to_alias($s), _ID_CONTEXT => $contextAlias]]); diff --git a/test/unit/mongo/MongoTripodViewsTest.php b/test/unit/mongo/MongoTripodViewsTest.php index dcdf4cef..dfb5c6fe 100644 --- a/test/unit/mongo/MongoTripodViewsTest.php +++ b/test/unit/mongo/MongoTripodViewsTest.php @@ -839,7 +839,7 @@ public function testGetViewForResourcesDoesNotInvokeViewGenerationForMissingReso ], ]; - $returnedGraph = new ExtendedGraph(); + $returnedGraph = new MongoGraph(); $returnedGraph->add_literal_triple($uri1, 'http://somepred', 'someval'); $mockDb = $this->getMockBuilder(Database::class) @@ -1924,10 +1924,7 @@ public function testSavingToAPreviouslyEmptyJoinUpdatesView(): void $this->assertTrue($view->has_triples_about('http://schemas.talis.com/2005/user/schema#xyz')); } - /** - * @return ExtendedGraph - */ - public function fetchGraphInGetViewForResourcesCallback(...$args) + public function fetchGraphInGetViewForResourcesCallback(...$args): MongoGraph { $uri1 = 'http://uri1'; $uri2 = 'http://uri2'; @@ -1938,10 +1935,10 @@ public function fetchGraphInGetViewForResourcesCallback(...$args) $query1 = ['_id' => ['$in' => [['r' => $uri1, 'c' => $context, 'type' => $viewType], ['r' => $uri2, 'c' => $context, 'type' => $viewType]]]]; $query2 = ['_id' => ['$in' => [['r' => $uri2, 'c' => $context, 'type' => $viewType]]]]; - $returnedGraph1 = new ExtendedGraph(); + $returnedGraph1 = new MongoGraph(); $returnedGraph1->add_literal_triple($uri1, 'http://somepred', 'someval'); - $returnedGraph2 = new ExtendedGraph(); + $returnedGraph2 = new MongoGraph(); $returnedGraph2->add_literal_triple($uri2, 'http://somepred', 'someval'); if ($args[0] == $query1) { return $returnedGraph1; @@ -1961,9 +1958,6 @@ public function testCursorNoExceptions(): void $viewType = 'someView'; $context = 'http://someContext'; - $returnedGraph = new ExtendedGraph(); - $returnedGraph->add_literal_triple($uri1, 'http://somepred', 'someval'); - $mockDb = $this->getMockBuilder(Database::class) ->disableOriginalConstructor() ->onlyMethods(['selectCollection']) @@ -2023,9 +2017,6 @@ public function testCursorExceptionThrown(): void $viewType = 'someView'; $context = 'http://someContext'; - $returnedGraph = new ExtendedGraph(); - $returnedGraph->add_literal_triple($uri1, 'http://somepred', 'someval'); - $mockDb = $this->getMockBuilder(Database::class) ->disableOriginalConstructor() ->onlyMethods(['selectCollection']) @@ -2086,9 +2077,6 @@ public function testCursorNoExceptionThrownWhenCursorThrowsSomeExceptions(): voi $viewType = 'someView'; $context = 'http://someContext'; - $returnedGraph = new ExtendedGraph(); - $returnedGraph->add_literal_triple($uri1, 'http://somepred', 'someval'); - $mockDb = $this->getMockBuilder(Database::class) ->disableOriginalConstructor() ->onlyMethods(['selectCollection']) From 14c4766b00ba968424c866cd365b064e1d530e64 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Fri, 13 Mar 2026 13:46:54 +0000 Subject: [PATCH 31/56] Type improvements in graph classes --- src/classes/ChangeSet.php | 29 ++-- src/classes/ExtendedGraph.php | 311 ++++++++++++++++++++-------------- 2 files changed, 200 insertions(+), 140 deletions(-) diff --git a/src/classes/ChangeSet.php b/src/classes/ChangeSet.php index e672a88e..edc9d3dc 100644 --- a/src/classes/ChangeSet.php +++ b/src/classes/ChangeSet.php @@ -8,14 +8,20 @@ * Represents a changeset. Can be used to create a changeset based on the difference between two bounded descriptions. The descriptions must share the same subject URI. * Adapted from Moriarty's changeset. * + * @phpstan-import-type ObjectType from ExtendedGraph + * @phpstan-import-type TripleSubject from ExtendedGraph + * @phpstan-import-type TriplePredicate from ExtendedGraph + * @phpstan-import-type TripleObject from ExtendedGraph + * @phpstan-import-type TripleGraph from ExtendedGraph + * * @see https://code.google.com/p/moriarty/source/browse/trunk/changeset.class.php */ class ChangeSet extends ExtendedGraph { - /** @var array> */ + /** @var TripleGraph */ public $before = []; - /** @var array> */ + /** @var TripleGraph */ public $after = []; /** @@ -24,19 +30,16 @@ class ChangeSet extends ExtendedGraph * createdDate?: string, * creatorName?: string, * changeReason?: string, - * after?: array, - * before?: array, + * after?: TripleGraph, + * before?: TripleGraph, * after_rdfxml?: string, * before_rdfxml?: string, * properties?: array, - * 'http://purl.org/dc/terms/source'?: string|array + * 'http://purl.org/dc/terms/source'?: array|string * } */ public $a; - /** @var array> */ - public $_index = []; - /** * Create a new changeset. This will calculate the required additions and removals based on before and after versions of a bounded description. The args parameter is an associative array that may have the following fields: *
      @@ -186,14 +189,14 @@ protected function __init(): void /** * adds a triple to the internal simpleIndex holding all the changesets and statements. * - * @param string $s Subject uri - * @param string $p Predicate URI - * @param array|string $o Object URI or literal value - * @param string $o_type Object type (bnode, uri, literal) + * @param TripleSubject $s Subject URI + * @param TriplePredicate $p Predicate URI + * @param string|TripleObject|TripleObject[] $o Object URI or literal value + * @param ObjectType $o_type Object type (bnode, uri, literal) * * @author Keith */ - public function addT($s, $p, $o, $o_type = 'bnode'): void + public function addT(string $s, string $p, $o, $o_type = 'bnode'): void { if (is_array($o) && isset($o[0]['type'])) { foreach ($o as $obj) { diff --git a/src/classes/ExtendedGraph.php b/src/classes/ExtendedGraph.php index 11dddd76..9004628e 100644 --- a/src/classes/ExtendedGraph.php +++ b/src/classes/ExtendedGraph.php @@ -9,28 +9,35 @@ /** * This class is based on SimpleGraph, part of Moriaty: https://code.google.com/p/moriarty/. * + * @phpstan-type ObjectResource string + * @phpstan-type ObjectLiteral string|int|float|bool + * @phpstan-type ObjectType 'bnode'|'uri'|'literal' + * @phpstan-type ObjectValue ObjectResource|ObjectLiteral + * @phpstan-type TripleSubject string + * @phpstan-type TriplePredicate string + * @phpstan-type TripleObject array{type: ObjectType, value: ObjectValue, lang?: string, datatype?: string} + * @phpstan-type TripleGraph array> + * * @see https://code.google.com/p/moriarty/source/browse/trunk/labeller.class.php */ class ExtendedGraph { - // END SimpleGraph - - // Modifications start here - public const rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; public const rdf_type = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; public const rdf_seq = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#Seq'; - // FROM SimpleGraph + /** @var TripleGraph */ public $_index = []; + /** @var string[] */ public $_image_properties = [ 'http://xmlns.com/foaf/0.1/depiction', 'http://xmlns.com/foaf/0.1/img', ]; + /** @var string[] */ public $_property_order = [ 'http://www.w3.org/2004/02/skos/core#prefLabel', RDFS_LABEL, @@ -45,6 +52,7 @@ class ExtendedGraph RDF_TYPE, ]; + /** @var array */ public $parser_errors = []; /** @@ -52,6 +60,7 @@ class ExtendedGraph */ public $_labeller; + /** @var array */ protected $_ns = [ 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', @@ -89,12 +98,12 @@ class ExtendedGraph /** * Up to the application to decide what constitures the label properties for a given app. * - * @var array + * @var string[] */ private static $labelProperties; /** - * @param array|string $graph + * @param string|TripleGraph $graph */ public function __construct($graph = null) { @@ -175,9 +184,9 @@ public function make_resource_array(string $resource): array /** * Adds a triple with a resource object to the graph. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate URI of the triple - * @param string|null $o the object of the triple, either a URI or a blank node in the format _:name + * @param TripleSubject $s the subject of the triple, either a URI or a blank node in the format _:name + * @param TriplePredicate $p the predicate URI of the triple + * @param ObjectResource|null $o the object of the triple, either a URI or a blank node in the format _:name * * @return bool true if the triple was new, false if it already existed in the graph */ @@ -193,11 +202,11 @@ public function add_resource_triple(string $s, string $p, ?string $o): bool /** * Adds a triple with a literal object to the graph. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate of the triple as a URI - * @param bool|float|int|string $o the object of the triple as a scalar value - * @param string|null $lang the language code of the triple's object (optional) - * @param string|null $dt the datatype URI of the triple's object (optional) + * @param TripleSubject $s the subject of the triple, either a URI or a blank node in the format _:name + * @param TriplePredicate $p the predicate of the triple as a URI + * @param ObjectLiteral $o the object of the triple as a scalar value + * @param string|null $lang the language code of the triple's object (optional) + * @param string|null $dt the datatype URI of the triple's object (optional) * * @return bool true if the triple was new, false if it already existed in the graph */ @@ -230,7 +239,9 @@ public function get_triples(): array /** * Get a copy of the graph's triple index. * - * @see http://n2.talis.com/wiki/RDF_PHP_Specification + * @see https://www.easyrdf.org/docs/rdf-formats-php + * + * @return TripleGraph */ public function get_index(): array { @@ -291,7 +302,7 @@ public function to_ntriples(): string /** * Serialise the graph to JSON. * - * @see http://n2.talis.com/wiki/RDF_JSON_Specification + * @see https://www.easyrdf.org/docs/rdf-formats-json * * @return string the JSON version of the graph */ @@ -303,7 +314,7 @@ public function to_json(): string /** * Serialise the graph to HTML. * - * @param array|string|null $s + * @param TripleSubject|TripleSubject[]|null $s * * @return string a HTML version of the graph */ @@ -317,7 +328,7 @@ public function to_html($s = null, bool $guess_labels = true): string if ($subjects === []) { return ''; } - } elseif (array_key_exists($s, $this->_index)) { + } elseif (isset($this->_index[$s])) { $subjects = [$s]; } else { return ''; @@ -346,14 +357,15 @@ public function to_html($s = null, bool $guess_labels = true): string $h .= '
      '; } + $value = (string) $this->_index[$subject][$p][$i]['value']; if ($this->_index[$subject][$p][$i]['type'] === 'literal') { - $h .= htmlspecialchars($this->_index[$subject][$p][$i]['value']); + $h .= htmlspecialchars($value); } else { - $h .= ''; + $h .= ''; if ($guess_labels) { - $h .= htmlspecialchars($this->get_label($this->_index[$subject][$p][$i]['value'])); + $h .= htmlspecialchars($this->get_label($value)); } else { - $h .= htmlspecialchars($this->_index[$subject][$p][$i]['value']); + $h .= htmlspecialchars($value); } $h .= ''; @@ -411,26 +423,26 @@ public function to_html($s = null, bool $guess_labels = true): string /** * Fetch the first literal value for a given subject and predicate. If there are multiple possible values then one is selected at random. * - * @param string $s the subject to search for - * @param string|string[] $p the predicate to search for, or an array of predicates - * @param bool|float|int|string|null $default a default value to use if no literal values are found + * @param TripleSubject $s the subject to search for + * @param TriplePredicate|TriplePredicate[] $p the predicate to search for, or an array of predicates + * @param ObjectLiteral|null $default a default value to use if no literal values are found * - * @return bool|float|int|string|null the first literal value found or the supplied default if no values were found + * @return ObjectLiteral|null the first literal value found or the supplied default if no values were found */ public function get_first_literal(string $s, $p, $default = null, ?string $preferred_language = null) { $best_literal = $default; - if (array_key_exists($s, $this->_index)) { + if (isset($this->_index[$s])) { if (is_array($p)) { foreach ($p as $p_uri) { - if (array_key_exists($p_uri, $this->_index[$s])) { + if (isset($this->_index[$s][$p_uri])) { foreach ($this->_index[$s][$p_uri] as $value) { if ($value['type'] == 'literal') { if ($preferred_language == null) { return $value['value']; } - if (array_key_exists('lang', $value) && $value['lang'] == $preferred_language) { + if (isset($value['lang']) && $value['lang'] == $preferred_language) { return $value['value']; } @@ -439,14 +451,14 @@ public function get_first_literal(string $s, $p, $default = null, ?string $prefe } } } - } elseif (array_key_exists($p, $this->_index[$s])) { + } elseif (isset($this->_index[$s][$p])) { foreach ($this->_index[$s][$p] as $value) { if ($value['type'] == 'literal') { if ($preferred_language == null) { return $value['value']; } - if (array_key_exists('lang', $value) && $value['lang'] == $preferred_language) { + if (isset($value['lang']) && $value['lang'] == $preferred_language) { return $value['value']; } @@ -462,11 +474,11 @@ public function get_first_literal(string $s, $p, $default = null, ?string $prefe /** * Fetch the first resource value for a given subject and predicate. If there are multiple possible values then one is selected at random. * - * @param string $s the subject to search for - * @param string $p the predicate to search for - * @param string $default a default value to use if no literal values are found + * @param TripleSubject $s the subject to search for + * @param TriplePredicate $p the predicate to search for + * @param ObjectResource $default a default value to use if no literal values are found * - * @return string|null the first resource value found or the supplied default if no values were found + * @return ObjectResource|null the first resource value found or the supplied default if no values were found */ public function get_first_resource(string $s, string $p, ?string $default = null): ?string { @@ -484,9 +496,9 @@ public function get_first_resource(string $s, string $p, ?string $default = null /** * Remove a triple with a resource object from the graph. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate URI of the triple - * @param bool|float|int|string $o the object of the triple, either a URI or a blank node in the format _:name + * @param TripleSubject $s the subject of the triple, either a URI or a blank node in the format _:name + * @param TriplePredicate $p the predicate URI of the triple + * @param ObjectResource $o the object of the triple, either a URI or a blank node in the format _:name */ public function remove_resource_triple(string $s, string $p, $o): void { @@ -511,7 +523,7 @@ public function remove_resource_triple(string $s, string $p, $o): void } /** - * @param bool|float|int|string $o + * @param ObjectLiteral $o */ public function remove_literal_triple(string $s, string $p, $o): void { @@ -538,7 +550,7 @@ public function remove_literal_triple(string $s, string $p, $o): void /** * Remove all triples having the supplied subject. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name + * @param TripleSubject $s the subject of the triple, either a URI or a blank node in the format _:name */ public function remove_triples_about(string $s): void { @@ -562,7 +574,7 @@ public function from_rdfxml(string $rdfxml, string $base = ''): void /** * Replace the triples in the graph with those parsed from the supplied JSON. * - * @see http://n2.talis.com/wiki/RDF_JSON_Specification + * @see https://www.easyrdf.org/docs/rdf-formats-json * * @param string $json the JSON to parse */ @@ -580,7 +592,7 @@ public function from_json(string $json): void /** * Add the triples parsed from the supplied JSON to the graph. * - * @see http://n2.talis.com/wiki/RDF_JSON_Specification + * @see https://www.easyrdf.org/docs/rdf-formats-json * * @param string $json the JSON to parse */ @@ -740,15 +752,15 @@ public function add_graph(ExtendedGraph $g): bool /** * Tests whether the graph contains the given triple. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate URI of the triple - * @param bool|float|int|string $o the object of the triple, either a URI or a blank node in the format _:name + * @param TripleSubject $s the subject of the triple, either a URI or a blank node in the format _:name + * @param TriplePredicate $p the predicate URI of the triple + * @param ObjectResource $o the object of the triple, either a URI or a blank node in the format _:name * * @return bool true if the triple exists in the graph, false otherwise */ public function has_resource_triple(string $s, string $p, $o): bool { - if (array_key_exists($s, $this->_index) && array_key_exists($p, $this->_index[$s])) { + if (isset($this->_index[$s][$p])) { foreach ($this->_index[$s][$p] as $value) { if (($value['type'] == 'uri' || $value['type'] == 'bnode') && $value['value'] === $o) { return true; @@ -762,25 +774,25 @@ public function has_resource_triple(string $s, string $p, $o): bool /** * Tests whether the graph contains the given triple. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate URI of the triple - * @param bool|float|int|string $o the object of the triple as a literal value - * @param string|null $lang the language of the object - * @param string|null $dt the datatype of the object + * @param TripleSubject $s the subject of the triple, either a URI or a blank node in the format _:name + * @param TriplePredicate $p the predicate URI of the triple + * @param ObjectLiteral $o the object of the triple as a literal value + * @param string|null $lang the language of the object + * @param string|null $dt the datatype of the object * * @return bool true if the triple exists in the graph, false otherwise */ public function has_literal_triple(string $s, string $p, $o, ?string $lang = null, ?string $dt = null): bool { - if (array_key_exists($s, $this->_index) && array_key_exists($p, $this->_index[$s])) { + if (isset($this->_index[$s][$p])) { foreach ($this->_index[$s][$p] as $value) { if (($value['type'] == 'literal') && $value['value'] === $o) { if ($lang !== null) { - return array_key_exists('lang', $value) && $value['lang'] === $lang; + return isset($value['lang']) && $value['lang'] === $lang; } if ($dt !== null) { - return array_key_exists('datatype', $value) && $value['datatype'] === $dt; + return isset($value['datatype']) && $value['datatype'] === $dt; } return true; @@ -794,15 +806,15 @@ public function has_literal_triple(string $s, string $p, $o, ?string $lang = nul /** * Fetch the resource values for a given subject and predicate. * - * @param string $s the subject to search for - * @param string $p the predicate to search for + * @param TripleSubject $s the subject to search for + * @param TriplePredicate $p the predicate to search for * - * @return array list of URIs and blank nodes that are the objects of triples with the supplied subject and predicate + * @return ObjectResource[] list of URIs and blank nodes that are the objects of triples with the supplied subject and predicate */ public function get_resource_triple_values(string $s, string $p): array { $values = []; - if (array_key_exists($s, $this->_index) && array_key_exists($p, $this->_index[$s])) { + if (isset($this->_index[$s][$p])) { foreach ($this->_index[$s][$p] as $value) { if ($value['type'] == 'uri' || $value['type'] == 'bnode') { $values[] = $value['value']; @@ -816,18 +828,18 @@ public function get_resource_triple_values(string $s, string $p): array /** * Fetch the literal values for a given subject and predicate. * - * @param string $s the subject to search for - * @param array|string $p the predicate to search for or an array of predicates + * @param TripleSubject $s the subject to search for + * @param TriplePredicate|TriplePredicate[] $p the predicate to search for or an array of predicates * - * @return array list of literals that are the objects of triples with the supplied subject and predicate + * @return ObjectLiteral[] list of literals that are the objects of triples with the supplied subject and predicate */ public function get_literal_triple_values(string $s, $p): array { $values = []; - if (array_key_exists($s, $this->_index)) { + if (isset($this->_index[$s])) { if (is_array($p)) { foreach ($p as $p_uri) { - if (array_key_exists($p_uri, $this->_index[$s])) { + if (isset($this->_index[$s][$p_uri])) { foreach ($this->_index[$s][$p_uri] as $value) { if ($value['type'] == 'literal') { $values[] = $value['value']; @@ -835,7 +847,7 @@ public function get_literal_triple_values(string $s, $p): array } } } - } elseif (array_key_exists($p, $this->_index[$s])) { + } elseif (isset($this->_index[$s][$p])) { foreach ($this->_index[$s][$p] as $value) { if ($value['type'] == 'literal') { $values[] = $value['value']; @@ -850,10 +862,10 @@ public function get_literal_triple_values(string $s, $p): array /** * Fetch the values for a given subject and predicate. * - * @param string $s the subject to search for - * @param array|string $p the predicate to search for, or an array of predicates + * @param TripleSubject $s the subject to search for + * @param TriplePredicate|TriplePredicate[] $p the predicate to search for or an array of predicates * - * @return array list of values of triples with the supplied subject and predicate + * @return TripleObject[] list of values of triples with the supplied subject and predicate */ public function get_subject_property_values(string $s, $p): array { @@ -862,9 +874,9 @@ public function get_subject_property_values(string $s, $p): array $p = [$p]; } - if (array_key_exists($s, $this->_index)) { + if (isset($this->_index[$s])) { foreach ($p as $pinst) { - if (array_key_exists($pinst, $this->_index[$s])) { + if (isset($this->_index[$s][$pinst])) { foreach ($this->_index[$s][$pinst] as $value) { $values[] = $value; } @@ -878,14 +890,14 @@ public function get_subject_property_values(string $s, $p): array /** * Fetch a subgraph where all triples have given subject. * - * @param string $s the subject to search for + * @param TripleSubject $s the subject to search for * * @return ExtendedGraph triples with the supplied subject */ public function get_subject_subgraph(string $s): ExtendedGraph { $sub = new ExtendedGraph(); - if (array_key_exists($s, $this->_index)) { + if (isset($this->_index[$s])) { $sub->_index[$s] = $this->_index[$s]; } @@ -895,7 +907,7 @@ public function get_subject_subgraph(string $s): ExtendedGraph /** * Fetch an array of all the subjects. * - * @return string[] list of all the subjects in the graph + * @return TripleSubject[] list of all the subjects in the graph */ public function get_subjects(): array { @@ -905,18 +917,18 @@ public function get_subjects(): array /** * Fetch an array of all the subject that have and rdf type that matches that given. * - * @param string $t the type to match + * @param ObjectResource $o the type to match */ - public function get_subjects_of_type(string $t): array + public function get_subjects_of_type(string $o): array { - return $this->get_subjects_where_resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#type', $t); + return $this->get_subjects_where_resource('http://www.w3.org/1999/02/22-rdf-syntax-ns#type', $o); } /** * Fetch an array of all the subjects where the predicate and object match a ?s $p $o triple in the graph and the object is a resource. * - * @param string $p the predicate to match - * @param string $o the resource object to match + * @param TriplePredicate $p the predicate to match + * @param ObjectResource $o the resource object to match */ public function get_subjects_where_resource(string $p, string $o): array { @@ -926,8 +938,8 @@ public function get_subjects_where_resource(string $p, string $o): array /** * Fetch an array of all the subjects where the predicate and object match a ?s $p $o triple in the graph and the object is a literal value. * - * @param string $p the predicate to match - * @param bool|float|int|string $o the literal object to match + * @param TriplePredicate $p the predicate to match + * @param ObjectValue $o the literal object to match */ public function get_subjects_where_literal(string $p, $o): array { @@ -937,15 +949,15 @@ public function get_subjects_where_literal(string $p, $o): array /** * Fetch the properties of a given subject and predicate. * - * @param string $s the subject to search for - * @param bool $distinct if true then duplicate properties are included only once (optional, default is true) + * @param TripleSubject $s the subject to search for + * @param bool $distinct if true then duplicate properties are included only once (optional, default is true) * - * @return array list of property URIs + * @return TriplePredicate[] list of property URIs */ public function get_subject_properties(string $s, bool $distinct = true): array { $values = []; - if (array_key_exists($s, $this->_index)) { + if (isset($this->_index[$s])) { foreach ($this->_index[$s] as $prop => $prop_values) { if ($distinct) { $values[] = $prop; @@ -964,37 +976,33 @@ public function get_subject_properties(string $s, bool $distinct = true): array /** * Tests whether the graph contains a triple with the given subject and predicate. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate URI of the triple + * @param TripleSubject $s the subject of the triple, either a URI or a blank node in the format _:name + * @param TriplePredicate $p the predicate URI of the triple * * @return bool true if a matching triple exists in the graph, false otherwise */ public function subject_has_property(string $s, string $p): bool { - if (array_key_exists($s, $this->_index)) { - return array_key_exists($p, $this->_index[$s]); - } - - return false; + return isset($this->_index[$s][$p]); } /** * Tests whether the graph contains a triple with the given subject. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name + * @param TripleSubject $s the subject of the triple, either a URI or a blank node in the format _:name * * @return bool true if the graph contains any triples with the specified subject, false otherwise */ public function has_triples_about(string $s): bool { - return array_key_exists($s, $this->_index); + return isset($this->_index[$s]); } /** * Removes all triples with the given subject and predicate. * - * @param string $s the subject of the triple, either a URI or a blank node in the format _:name - * @param string $p the predicate URI of the triple + * @param TripleSubject $s the subject of the triple, either a URI or a blank node in the format _:name + * @param TriplePredicate $p the predicate URI of the triple */ public function remove_property_values(string $s, string $p): void { @@ -1030,7 +1038,7 @@ public function get_inverse_label(string $resource_uri, bool $capitalize = false } /** - * @param array $resources + * @param TripleGraph $resources */ public function reify(array $resources, string $nodeID_prefix = 'Statement'): array { @@ -1062,7 +1070,7 @@ public function reify(array $resources, string $nodeID_prefix = 'Statement'): ar /** * returns a simpleIndex consisting of all the statements from the first array that weren't found in any of the subsequent arrays. * - * @param array ...$indices If only one array is passed then the diff is taken against the graph's own index, otherwise the diff is taken against the first array passed as a parameter + * @param TripleGraph ...$indices If only one array is passed then the diff is taken against the graph's own index, otherwise the diff is taken against the first array passed as a parameter * * @author Keith */ @@ -1115,7 +1123,7 @@ public function diff(array ...$indices): array * merge * merges all rdf/json-style arrays passed as parameters. * - * @param array ...$indices If only one array is passed then the merge is done against the graph's own index, otherwise the merge is done against the first array passed as a parameter + * @param TripleGraph ...$indices If only one array is passed then the merge is done against the graph's own index, otherwise the merge is done against the first array passed as a parameter * * @author Keith */ @@ -1147,7 +1155,7 @@ public function merge(array ...$indices): array } } - if (isset($properties) && is_array($properties)) { + if (!empty($properties)) { foreach ($properties as $property => $objects) { foreach ($objects as $object) { // make sure that the new bnode is being used @@ -1324,7 +1332,9 @@ public function replace_uris(string $uri1, string $uri2): void } /** - * @param bool|float|int|string|null $o + * @param TripleSubject|null $s + * @param TriplePredicate|null $p + * @param ObjectValue|null $o */ public function get_triple_count(?string $s = null, ?string $p = null, $o = null): int { @@ -1356,7 +1366,7 @@ public function get_triple_count(?string $s = null, ?string $p = null, $o = null /** * Fetch all the resource values for all subjects. * - * @return array the resource values found + * @return ObjectResource[] the resource values found */ public function get_resources(): array { @@ -1373,14 +1383,14 @@ public function get_resources(): array /** * Fetch all the resource values for a given subject. * - * @param string $s the subject to search for + * @param TripleSubject $s the subject to search for * - * @return array the resource values found + * @return ObjectResource[] the resource values found */ public function get_resources_for_subject(string $s): array { $resources = []; - if (array_key_exists($s, $this->_index)) { + if (isset($this->_index[$s])) { foreach ($this->_index[$s] as $values) { foreach ($values as $value) { if ($value['type'] == 'uri' || $value['type'] == 'bnode') { @@ -1393,6 +1403,9 @@ public function get_resources_for_subject(string $s): array return array_unique($resources); } + /** + * @param TriplePredicate $p + */ public function remove_properties(string $p): void { foreach ($this->get_subjects() as $s) { @@ -1400,6 +1413,11 @@ public function remove_properties(string $p): void } } + /** + * @param TriplePredicate $p + * + * @return ObjectResource[] the resource values found + */ public function get_resource_properties(string $p): array { $resources = []; @@ -1412,7 +1430,10 @@ public function get_resource_properties(string $p): array } /** - * @param bool|float|int|string $o + * @param TriplePredicate $p + * @param ObjectValue $o + * + * @return TripleSubject[] */ public function get_subjects_with_property_value(string $p, $o): array { @@ -1426,6 +1447,11 @@ public function get_subjects_with_property_value(string $p, $o): array return $subjects; } + /** + * @param TripleSubject $sequenceUri + * + * @return ObjectValue[] + */ public function get_sequence_values(string $sequenceUri): array { $triples = $this->get_index(); @@ -1448,15 +1474,12 @@ public function get_sequence_values(string $sequenceUri): array ksort($properties, SORT_NUMERIC); } - $values = []; - - foreach ($properties as $value) { - $values[] = $value; - } - - return $values; + return array_values($properties); } + /** + * @param TripleSubject $sequenceUri + */ public function get_next_sequence(string $sequenceUri): int { $values = $this->get_sequence_values($sequenceUri); @@ -1465,7 +1488,8 @@ public function get_next_sequence(string $sequenceUri): int } /** - * @param bool|float|int|string $o + * @param TripleSubject $s + * @param ObjectLiteral $o */ public function add_literal_to_sequence(string $s, $o): void { @@ -1474,6 +1498,9 @@ public function add_literal_to_sequence(string $s, $o): void /** * Remove a resource from a specified sequence and reindex the sequence to remove the gap. + * + * @param TripleSubject $sequenceUri + * @param ObjectResource $resourceValue */ public function remove_resource_from_sequence(string $sequenceUri, string $resourceValue): void { @@ -1496,11 +1523,19 @@ public function remove_resource_from_sequence(string $sequenceUri, string $resou } } + /** + * @param TripleSubject $s + * @param ObjectResource $o + */ public function add_resource_to_sequence(string $s, string $o): void { $this->add_to_sequence($s, $o, 'resource'); } + /** + * @param TripleSubject $s + * @param ObjectResource $o + */ public function add_resource_to_sequence_in_position(string $s, string $o, int $position): void { $sequenceValues = $this->get_sequence_values($s); @@ -1524,8 +1559,8 @@ public function add_resource_to_sequence_in_position(string $s, string $o, int $ } /** - * @param bool|float|int|string $oOldValue - * @param bool|float|int|string $oNewValue + * @param ObjectLiteral $oOldValue + * @param ObjectLiteral $oNewValue */ public function replace_literal_triple(string $s, string $p, $oOldValue, $oNewValue): bool { @@ -1539,6 +1574,11 @@ public function replace_literal_triple(string $s, string $p, $oOldValue, $oNewVa return false; } + /** + * @param TripleSubject $s + * @param TriplePredicate $p + * @param ObjectResource|null $o + */ public function replace_resource_triples(string $s, string $p, ?string $o): void { if ($this->subject_has_property($s, $p)) { @@ -1551,7 +1591,9 @@ public function replace_resource_triples(string $s, string $p, ?string $o): void } /** - * @param bool|float|int|string|null $o + * @param TripleSubject $s + * @param TriplePredicate $p + * @param ObjectLiteral|null $o */ public function replace_literal_triples(string $s, string $p, $o): void { @@ -1565,15 +1607,17 @@ public function replace_literal_triples(string $s, string $p, $o): void } /** + * @param TripleSubject $uri + * * @throws Exception */ public function get_label_for_uri(string $uri): string { - if (!isset($this->_index[$uri])) { + if (empty($this->_index[$uri])) { return ''; } - if (!isset(self::$labelProperties)) { + if (empty(self::$labelProperties)) { throw new Exception('Please initialise ExtendedGraph::$labelProperties'); } @@ -1594,6 +1638,9 @@ public function is_equal_to(ExtendedGraph $otherGraph): bool return $diffThisAndThat === [] && $diffThatAndThis === []; } + /** + * @param ObjectResource $type + */ public function remove_subjects_of_type(string $type): void { $subjects = $this->get_subjects_of_type($type); @@ -1604,10 +1651,8 @@ public function remove_subjects_of_type(string $type): void public function from_graph(ExtendedGraph $graph): void { - if ($graph) { - $this->remove_all_triples(); - $this->add_graph($graph); - } + $this->remove_all_triples(); + $this->add_graph($graph); } /** @@ -1635,6 +1680,10 @@ protected function isValidResource($value): bool } /** + * @param TripleSubject $s + * @param TriplePredicate $p + * @param TripleObject $o_info + * * @throws Exception */ private function _add_triple(string $s, string $p, array $o_info): bool @@ -1731,8 +1780,10 @@ private function _add_arc2_triple_list(array &$triples): void } } - // until ARC2 upgrades to support RDF/PHP we need to rename all types of "uri" to "iri" - private function _to_arc_index(array &$index): array + /** + * @param TripleGraph $index + */ + private function _to_arc_index(array $index): array { $ret = []; @@ -1743,6 +1794,8 @@ private function _to_arc_index(array &$index): array foreach ($p_info as $o) { $o_new = []; foreach ($o as $key => $value) { + // until ARC2 upgrades to support RDF/PHP we + // need to rename all types of "uri" to "iri" if ($key == 'type' && $value == 'uri') { $o_new['type'] = 'iri'; } else { @@ -1759,13 +1812,15 @@ private function _to_arc_index(array &$index): array } /** - * @param bool|float|int|string $o + * @param TriplePredicate $p + * @param ObjectValue $o + * @param ObjectType $type */ private function get_subjects_where(string $p, $o, string $type): array { $subjects = []; foreach ($this->_index as $subject => $properties) { - if (array_key_exists($p, $properties)) { + if (isset($properties[$p])) { foreach ($properties[$p] as $object) { if ($object['type'] == $type && $object['value'] == $o) { $subjects[] = $subject; @@ -1780,7 +1835,9 @@ private function get_subjects_where(string $p, $o, string $type): array } /** - * @param bool|float|int|string $o + * @param TripleSubject $s + * @param ObjectValue $o + * @param 'literal'|'resource' $type */ private function add_to_sequence(string $s, $o, string $type = 'resource'): void { From 02e88aeb9191342f7098bc279a662d3ece659945 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 16 Mar 2026 09:34:23 +0000 Subject: [PATCH 32/56] Drop PHP 7.3 support --- .circleci/config.yml | 4 ---- composer.json | 7 +------ docker-compose.yml | 7 ------- docker/Dockerfile-php73 | 18 ------------------ 4 files changed, 1 insertion(+), 35 deletions(-) delete mode 100644 docker/Dockerfile-php73 diff --git a/.circleci/config.yml b/.circleci/config.yml index 09da84a3..527340c8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -151,10 +151,6 @@ workflows: build_and_test: jobs: - lint - - test: - name: test-php73 - php_version: php73 - mongo_version: 3.6.23 - test: name: test-php74 php_version: php74 diff --git a/composer.json b/composer.json index a304db33..4472bdb3 100644 --- a/composer.json +++ b/composer.json @@ -17,16 +17,11 @@ "homepage": "http://talis.com/" } ], - "config": { - "audit": { - "ignore": ["PKSA-gk21-j82g-2hhy"] - } - }, "suggest": { "resque/php-resque": "Redis backed library for background jobs" }, "require": { - "php" : ">=7.3", + "php" : ">=7.4", "mongodb/mongodb": "*", "monolog/monolog" : "~1.13", "semsol/arc2": "2.2.6" diff --git a/docker-compose.yml b/docker-compose.yml index 9567b632..81a577f0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,13 +8,6 @@ x-base-config: &base-config env_file: .env services: - php73: - build: - context: ./docker - dockerfile: Dockerfile-php73 - image: talis/tripod-php:php73-latest - <<: *base-config - php74: build: context: ./docker diff --git a/docker/Dockerfile-php73 b/docker/Dockerfile-php73 deleted file mode 100644 index 54a06d99..00000000 --- a/docker/Dockerfile-php73 +++ /dev/null @@ -1,18 +0,0 @@ -FROM php:7.3.33-cli - -RUN apt-get update && apt-get install -y --no-install-recommends \ - ca-certificates \ - curl \ - git \ - unzip \ - zip \ - && rm -rf /var/lib/apt/lists/* - -RUN curl -sLo /tmp/mongosh.deb https://downloads.mongodb.com/compass/mongodb-mongosh_2.2.15_amd64.deb \ - && dpkg -i /tmp/mongosh.deb \ - && rm /tmp/mongosh.deb - -COPY --from=mlocati/php-extension-installer:2.3.2 /usr/bin/install-php-extensions /usr/local/bin/ -COPY --from=composer:2.7.7 /usr/bin/composer /usr/local/bin/ - -RUN install-php-extensions pcntl mongodb-1.6.1 xhprof From efba683eca1a528c46277f18480e332d519778d6 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 16 Mar 2026 00:12:21 +0000 Subject: [PATCH 33/56] Apply rector #3 --- src/Config.php | 10 +---- src/classes/StatsD.php | 39 ++++++------------- src/classes/Timer.php | 8 ++-- src/mongo/Config.php | 35 ++++------------- src/mongo/Driver.php | 24 +++--------- src/mongo/IConfigInstance.php | 2 + src/mongo/ImpactedSubject.php | 31 ++++++--------- src/mongo/JobGroup.php | 13 ++----- src/mongo/base/DriverBase.php | 2 +- src/mongo/base/JobBase.php | 2 +- src/mongo/delegates/SearchIndexer.php | 19 ++++----- src/mongo/delegates/TransactionLog.php | 6 +-- src/mongo/delegates/Updates.php | 31 +++++++-------- src/mongo/delegates/Views.php | 3 +- src/mongo/jobs/ApplyOperation.php | 4 +- src/mongo/providers/MongoSearchProvider.php | 15 +++---- src/mongo/serializers/NQuadSerializer.php | 4 +- src/mongo/util/TriplesUtil.php | 11 ++---- .../mongo/MongoTripodConfigTest.php | 4 +- .../mongo/MongoTripodPerformanceTestBase.php | 9 ++--- test/unit/mongo/ConfigGeneratorTest.php | 2 +- test/unit/mongo/MongoSearchProviderTest.php | 6 +-- test/unit/mongo/MongoTripodConfigUnitTest.php | 13 +++---- test/unit/mongo/MongoTripodDriverTest.php | 2 +- test/unit/mongo/MongoTripodStatTest.php | 8 ++-- test/unit/mongo/MongoTripodTablesTest.php | 2 +- test/unit/mongo/MongoTripodTestBase.php | 2 +- 27 files changed, 106 insertions(+), 201 deletions(-) diff --git a/src/Config.php b/src/Config.php index bd81c555..73dde4a7 100644 --- a/src/Config.php +++ b/src/Config.php @@ -9,15 +9,9 @@ class Config implements ITripodConfig { - /** - * @var IConfigInstance|null - */ - private static $configInstance; + private static ?IConfigInstance $configInstance = null; - /** - * @var array|null - */ - private static $config; + private static ?array $config = null; /** * Config should not be instantiated directly: use Config::getInstance(). diff --git a/src/classes/StatsD.php b/src/classes/StatsD.php index a0a286eb..92f7f883 100644 --- a/src/classes/StatsD.php +++ b/src/classes/StatsD.php @@ -12,20 +12,18 @@ class StatsD implements ITripodStat /** @var int|string */ private $port; - /** @var string|null */ - private $prefix; + private ?string $prefix = null; - /** @var string|null */ - private $pivotValue; + private ?string $pivotValue = null; /** * @param string $host * @param int|string $port */ - public function __construct($host, $port, ?string $prefix = '') + public function __construct(string $host, $port, ?string $prefix = '') { - $this->host = $host; - $this->port = $port; + $this->setHost($host); + $this->setPort($port); $this->setPrefix($prefix); } @@ -89,10 +87,7 @@ public static function createFromConfig(array $config): self return new self($host, $port, $prefix); } - /** - * @return string - */ - public function getPrefix() + public function getPrefix(): ?string { return $this->prefix; } @@ -109,10 +104,7 @@ public function setPrefix(?string $prefix): void } } - /** - * @return int|string - */ - public function getPort() + public function getPort(): int { return $this->port; } @@ -122,29 +114,20 @@ public function getPort() */ public function setPort($port): void { - $this->port = $port; + $this->port = (int) $port; } - /** - * @return string - */ - public function getHost() + public function getHost(): string { return $this->host; } - /** - * @param string $host - */ - public function setHost($host): void + public function setHost(string $host): void { $this->host = $host; } - /** - * @return string - */ - public function getPivotValue() + public function getPivotValue(): ?string { return $this->pivotValue; } diff --git a/src/classes/Timer.php b/src/classes/Timer.php index 4cacfbf8..9a715c1e 100644 --- a/src/classes/Timer.php +++ b/src/classes/Timer.php @@ -11,22 +11,22 @@ class Timer /** * @var string start time of event as returned from php microtime() */ - private $start_time; + private ?string $start_time = null; /** * @var string end time of event as returned from php microtime() */ - private $end_time; + private ?string $end_time = null; /** * @var int difference in milliseconds of event's start time and end time */ - private $result; + private ?int $result = null; /** * @var int difference in micro-seconds of event's start time and end time */ - private $micro_result; + private ?int $micro_result = null; /** * Captures current microtime as time of start. Call this before start of event. diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 130c5cf5..cbe04b26 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -118,15 +118,9 @@ class Config implements IConfigInstance */ protected static $logger; - /** - * @var array - */ - private $config; + private ?array $config = null; - /** - * @var Labeller - */ - private $labeller; + private ?Labeller $labeller = null; /** * @var string @@ -135,36 +129,25 @@ class Config implements IConfigInstance /** * The defined database indexes, keyed by database name. - * - * @var array */ - private $indexes = []; + private array $indexes = []; - /** - * @var array - */ - private $cardinality = []; + private array $cardinality = []; /** * The connection strings for each defined database. - * - * @var array */ - private $dbConfig = []; + private array $dbConfig = []; /** * All of the defined viewSpecs. - * - * @var array */ - private $viewSpecs = []; + private array $viewSpecs = []; /** * All of the defined tableSpecs. - * - * @var array */ - private $tableSpecs = []; + private array $tableSpecs = []; /** * Defined database configuration: dbname, collections, etc. @@ -1228,9 +1211,7 @@ protected function validateTableSpecPart(array $spec, int $depth = 0): void $validComputingFieldFunctions = Tables::$computedFieldFunctions; if ($validationLevel === self::VALIDATE_MAX) { $availableFields = $this->getFieldNamesInSpec($spec); - $availableFields = array_map(function (string $field): string { - return '$' . $field; - }, $availableFields); + $availableFields = array_map(fn (string $field): string => '$' . $field, $availableFields); } foreach ($spec['computed_fields'] as $field) { diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index 250b70ca..e7d43a72 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -19,35 +19,23 @@ class Driver extends DriverBase implements IDriver { - /** - * @var Views - */ - private $tripod_views; + private ?Views $tripod_views = null; - /** - * @var Tables - */ - private $tripod_tables; + private ?Tables $tripod_tables = null; - /** - * @var SearchIndexer - */ - private $searchIndexer; + private ?SearchIndexer $searchIndexer = null; /** - * @var array + * @var mixed[] */ - private $async; + private array $async; /** * @var int */ private $retriesToGetLock; - /** - * @var Updates - */ - private $updates; + private ?Updates $updates = null; /** * Constructor for Driver. diff --git a/src/mongo/IConfigInstance.php b/src/mongo/IConfigInstance.php index bb706e04..5dee8cea 100644 --- a/src/mongo/IConfigInstance.php +++ b/src/mongo/IConfigInstance.php @@ -9,6 +9,7 @@ use MongoDB\Driver\ReadPreference; use Psr\Log\LoggerInterface; use Tripod\Exceptions\ConfigException; +use Tripod\ISearchProvider; use Tripod\ITripodConfigSerializer; interface IConfigInstance extends ITripodConfigSerializer @@ -164,6 +165,7 @@ public function getTransactionLogConfig(): array; /** * @param string $storeName Store name + * @return class-string|null */ public function getSearchProviderClassName(string $storeName): ?string; diff --git a/src/mongo/ImpactedSubject.php b/src/mongo/ImpactedSubject.php index 6741c50d..3feea429 100644 --- a/src/mongo/ImpactedSubject.php +++ b/src/mongo/ImpactedSubject.php @@ -14,20 +14,17 @@ */ class ImpactedSubject { - /** - * @var string - */ - private $operation; + private ?string $operation = null; /** - * @var array + * @var mixed[] */ - private $resourceId; + private array $resourceId; /** - * @var array + * @var mixed[] */ - private $specTypes; + private array $specTypes; /** * @var string @@ -39,10 +36,7 @@ class ImpactedSubject */ private $podName; - /** - * @var ITripodStat|null - */ - private $tripodStat; + private ?ITripodStat $tripodStat; /** * @param string $operation @@ -74,10 +68,7 @@ public function __construct(array $resourceId, $operation, $storeName, $podName, } } - /** - * @return string - */ - public function getOperation() + public function getOperation(): ?string { return $this->operation; } @@ -91,17 +82,17 @@ public function getPodName() } /** - * @return array + * @return mixed[] */ - public function getResourceId() + public function getResourceId(): array { return $this->resourceId; } /** - * @return array + * @return mixed[] */ - public function getSpecTypes() + public function getSpecTypes(): array { return $this->specTypes; } diff --git a/src/mongo/JobGroup.php b/src/mongo/JobGroup.php index 68726938..c4bd8b8a 100644 --- a/src/mongo/JobGroup.php +++ b/src/mongo/JobGroup.php @@ -11,9 +11,9 @@ class JobGroup { - private $id; + private ObjectId $id; - private $collection; + private ?Collection $collection = null; private $storeName; @@ -70,20 +70,15 @@ public function incrementJobCount($inc = 1) return $updateResult->count; } - /** - * @return ObjectId - */ - public function getId() + public function getId(): ObjectId { return $this->id; } /** * For mocking. - * - * @return Collection */ - protected function getMongoCollection() + protected function getMongoCollection(): Collection { if ($this->collection === null) { $config = Config::getInstance(); diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index 079c9da5..575378a3 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -70,7 +70,7 @@ abstract class DriverBase protected $db; /** - * @var string + * @var int|string */ protected $readPreference = ReadPreference::RP_PRIMARY_PREFERRED; diff --git a/src/mongo/base/JobBase.php b/src/mongo/base/JobBase.php index 9b058eec..5d3a9ce2 100644 --- a/src/mongo/base/JobBase.php +++ b/src/mongo/base/JobBase.php @@ -54,7 +54,7 @@ abstract class JobBase extends DriverBase /** @var Timer */ protected $timer; - private $tripod; + private ?Driver $tripod = null; public function setUp(): void { diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 853d32f6..b9f8196b 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -8,6 +8,7 @@ use MongoDB\Driver\ReadPreference; use Tripod\Exceptions\SearchException; use Tripod\ISearchProvider; +use Tripod\ITripodStat; use Tripod\Mongo\Driver; use Tripod\Mongo\IConfigInstance; use Tripod\Mongo\ImpactedSubject; @@ -18,19 +19,16 @@ class SearchIndexer extends CompositeBase { - protected $labeller; + protected Labeller $labeller; - protected $stat; + protected ITripodStat $stat; - private $tripod; + private Driver $tripod; - /** - * @var ISearchProvider - */ - private $searchProvider; + private ?ISearchProvider $searchProvider = null; /** - * @param string $readPreference + * @param int|string $readPreference * * @throws SearchException */ @@ -267,10 +265,7 @@ public function deleteSearchDocumentsByTypeId($typeId) return $this->getSearchProvider()->deleteSearchDocumentsByTypeId($typeId); } - /** - * @return ISearchProvider - */ - protected function getSearchProvider() + protected function getSearchProvider(): ?ISearchProvider { return $this->searchProvider; } diff --git a/src/mongo/delegates/TransactionLog.php b/src/mongo/delegates/TransactionLog.php index f7236e8a..36d97d8f 100644 --- a/src/mongo/delegates/TransactionLog.php +++ b/src/mongo/delegates/TransactionLog.php @@ -4,6 +4,7 @@ namespace Tripod\Mongo; +use MongoDB\BSON\UTCDateTime; use MongoDB\Collection; use MongoDB\Database; use MongoDB\Driver\Cursor; @@ -14,10 +15,9 @@ class TransactionLog { /** @var IConfigInstance */ - protected $config; + protected array $config; - /** @var Database */ - private $transaction_db; + private Database $transaction_db; /** @var Collection */ private $transaction_collection; diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 2fbe172f..9f1443b4 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -27,10 +27,7 @@ class Updates extends DriverBase */ protected $labeller; - /** - * @var Driver - */ - protected $tripod; + protected Driver $tripod; /** * @var Database @@ -47,10 +44,7 @@ class Updates extends DriverBase */ protected $discoverImpactedSubjects; - /** - * @var TransactionLog - */ - private $transactionLog; + private ?TransactionLog $transactionLog = null; /** * @var string the original read preference gets stored here @@ -70,9 +64,9 @@ class Updates extends DriverBase private $retriesToGetLock; /** - * @var array + * @var mixed[] */ - private $async; + private array $async; /** * @var string @@ -80,9 +74,9 @@ class Updates extends DriverBase private $queueName; /** - * @var array + * @var IEventHook[] */ - private $saveChangesHooks = []; + private array $saveChangesHooks = []; /** * @param array $opts @@ -369,11 +363,7 @@ public function replayTransactionLog($fromDate = null, $toDate = null): bool } // getters and setters for the delegates - - /** - * @return TransactionLog - */ - public function getTransactionLog() + public function getTransactionLog(): TransactionLog { if ($this->transactionLog == null) { $this->transactionLog = new TransactionLog(); @@ -1275,6 +1265,7 @@ private function addOperatorToChange(array &$changes, string $operator, array $k if (!is_array($changes[$operator][$key])) { $changes[$operator][$key] = [$changes[$operator][$key]]; } + $changes[$operator][$key][] = $value; } else { $changes[$operator][$key] = $value; @@ -1282,6 +1273,9 @@ private function addOperatorToChange(array &$changes, string $operator, array $k } } + /** + * @return int[]|string[] + */ private function getAsyncOperations(): array { $types = []; @@ -1294,6 +1288,9 @@ private function getAsyncOperations(): array return $types; } + /** + * @return int[]|string[] + */ private function getSyncOperations(): array { $types = []; diff --git a/src/mongo/delegates/Views.php b/src/mongo/delegates/Views.php index 126a3232..73f36e64 100644 --- a/src/mongo/delegates/Views.php +++ b/src/mongo/delegates/Views.php @@ -8,7 +8,6 @@ use MongoDB\Collection; use MongoDB\Driver\ReadPreference; use Tripod\Exceptions\ViewException; -use Tripod\ExtendedGraph; use Tripod\ITripodStat; use Tripod\Mongo\DateUtil; use Tripod\Mongo\ImpactedSubject; @@ -754,7 +753,7 @@ private function createTripodViewIdsFromResourceUris(array $resourceUriOrArray, * * @return string */ - private function getFromCollectionForViewSpec($viewSpec) + private function getFromCollectionForViewSpec(?array $viewSpec) { return $viewSpec['from'] ?? $this->podName; } diff --git a/src/mongo/jobs/ApplyOperation.php b/src/mongo/jobs/ApplyOperation.php index d9db5bf4..94689072 100644 --- a/src/mongo/jobs/ApplyOperation.php +++ b/src/mongo/jobs/ApplyOperation.php @@ -103,9 +103,7 @@ public function createJob(array $subjects, $queueName = null, $otherData = []): $data = [ self::SUBJECTS_KEY => array_map( - function (ImpactedSubject $subject): array { - return $subject->toArray(); - }, + fn (ImpactedSubject $subject): array => $subject->toArray(), $subjects ), ]; diff --git a/src/mongo/providers/MongoSearchProvider.php b/src/mongo/providers/MongoSearchProvider.php index 6ad83cc4..f00af63b 100644 --- a/src/mongo/providers/MongoSearchProvider.php +++ b/src/mongo/providers/MongoSearchProvider.php @@ -15,22 +15,19 @@ class MongoSearchProvider implements ISearchProvider { - /** - * @var string - */ - protected $storeName; + protected string $storeName; /** * @var Config */ - protected $config; + protected IConfigInstance $config; + + private Labeller $labeller; /** - * @var Labeller + * @var string[] */ - private $labeller; - - private $stopWords = [ + private array $stopWords = [ 'a', 'about', 'above', diff --git a/src/mongo/serializers/NQuadSerializer.php b/src/mongo/serializers/NQuadSerializer.php index 3e97264e..56031a8b 100644 --- a/src/mongo/serializers/NQuadSerializer.php +++ b/src/mongo/serializers/NQuadSerializer.php @@ -10,9 +10,9 @@ */ class NQuadSerializer { - private $raw; + private ?int $raw = null; - private $esc_chars; + private ?array $esc_chars = null; public function ___construct(): void { diff --git a/src/mongo/util/TriplesUtil.php b/src/mongo/util/TriplesUtil.php index a132d706..cbcb6513 100644 --- a/src/mongo/util/TriplesUtil.php +++ b/src/mongo/util/TriplesUtil.php @@ -10,12 +10,9 @@ class TriplesUtil { - private $collections = []; + private array $collections = []; - /** - * @var Labeller - */ - private $labeller; + private Labeller $labeller; /** * Constructor. @@ -224,11 +221,9 @@ protected function saveCBD($cbdSubject, MongoGraph $cbdGraph, Collection $collec } /** - * @param string $object - * * @return mixed */ - private function isUri($object) + private function isUri(string $object) { return filter_var($object, FILTER_VALIDATE_URL); } diff --git a/test/performance/mongo/MongoTripodConfigTest.php b/test/performance/mongo/MongoTripodConfigTest.php index a20d2c0c..37f14518 100644 --- a/test/performance/mongo/MongoTripodConfigTest.php +++ b/test/performance/mongo/MongoTripodConfigTest.php @@ -21,10 +21,8 @@ class MongoTripodConfigTest extends MongoTripodPerformanceTestBase /** * Holds tripod config. - * - * @var array */ - private $config = []; + private array $config = []; /** * Do some setup before each test start. diff --git a/test/performance/mongo/MongoTripodPerformanceTestBase.php b/test/performance/mongo/MongoTripodPerformanceTestBase.php index fa9d6a86..ae149b36 100644 --- a/test/performance/mongo/MongoTripodPerformanceTestBase.php +++ b/test/performance/mongo/MongoTripodPerformanceTestBase.php @@ -6,8 +6,7 @@ abstract class MongoTripodPerformanceTestBase extends MongoTripodTestBase { - /** @var Profiler|null */ - private $profiler; + private ?Profiler $profiler = null; /** * Helper function to calculate difference between two microtime values. @@ -38,7 +37,7 @@ protected function startProfiler(): void */ protected function stopProfiler(): void { - if ($this->profiler) { + if ($this->profiler instanceof Profiler) { $this->profiler->stop(); $this->profiler = null; } @@ -56,9 +55,7 @@ private function getProfiler(): Profiler 'save.handler.file' => [ 'filename' => $profilerDir . '/xhgui.data.jsonl', ], - 'profiler.replace_url' => function (): string { - return $this->getName(true) . ($this->hasFailed() ? ' FAIL' : ''); - }, + 'profiler.replace_url' => fn (): string => $this->getName(true) . ($this->hasFailed() ? ' FAIL' : ''), ]); } } diff --git a/test/unit/mongo/ConfigGeneratorTest.php b/test/unit/mongo/ConfigGeneratorTest.php index 14fd80dc..c3b1dbc7 100644 --- a/test/unit/mongo/ConfigGeneratorTest.php +++ b/test/unit/mongo/ConfigGeneratorTest.php @@ -15,7 +15,7 @@ class ConfigGeneratorTest extends MongoTripodTestBase { - private $config = []; + private array $config = []; protected function setUp(): void { diff --git a/test/unit/mongo/MongoSearchProviderTest.php b/test/unit/mongo/MongoSearchProviderTest.php index 7377fcf0..f0560e62 100644 --- a/test/unit/mongo/MongoSearchProviderTest.php +++ b/test/unit/mongo/MongoSearchProviderTest.php @@ -16,11 +16,9 @@ class MongoSearchProviderTest extends MongoTripodTestBase { - /** @var SearchIndexer */ - private $searchIndexer; + private SearchIndexer $searchIndexer; - /** @var MongoSearchProvider */ - private $mongoSearchProvider; + private MongoSearchProvider $mongoSearchProvider; protected function setUp(): void { diff --git a/test/unit/mongo/MongoTripodConfigUnitTest.php b/test/unit/mongo/MongoTripodConfigUnitTest.php index 30d85f78..cea5fcb9 100644 --- a/test/unit/mongo/MongoTripodConfigUnitTest.php +++ b/test/unit/mongo/MongoTripodConfigUnitTest.php @@ -9,6 +9,7 @@ use Tripod\Exceptions\ConfigException; use Tripod\ExtendedGraph; use Tripod\Mongo\Driver; +use Tripod\Mongo\IConfigInstance; use Tripod\Mongo\Labeller; use Tripod\Mongo\MongoGraph; use Tripod\Mongo\MongoSearchProvider; @@ -18,7 +19,7 @@ class MongoTripodConfigUnitTest extends MongoTripodTestBase /** * @var Tripod\Mongo\Config */ - private $tripodConfig; + private IConfigInstance $tripodConfig; protected function setUp(): void { @@ -62,7 +63,7 @@ public function testNamespaces(): void $expectedNs['bibo'] = 'http://purl.org/ontology/bibo/'; $expectedNs['foaf'] = 'http://xmlns.com/foaf/0.1/'; $expectedNs['baseData'] = 'http://basedata.com/b/'; - $this->assertEquals($expectedNs, $ns, 'Incorrect namespaces'); + $this->assertSame($expectedNs, $ns, 'Incorrect namespaces'); } public function testTConfig(): void @@ -1646,9 +1647,7 @@ public function testMongoConnectionNoExceptions(): void $mockConfig->expects($this->exactly(1)) ->method('getMongoClient') ->with('mongodb://mongodb:27017/', ['connectTimeoutMS' => 20000]) - ->willReturnCallback(function (): Client { - return new Client(); - }); + ->willReturnCallback(fn (): Client => new Client()); $mockConfig->getDatabase('tripod_php_testing', 'rs1', ReadPreference::RP_SECONDARY_PREFERRED); $mockConfig->getCollectionForCBD('tripod_php_testing', 'CBD_testing', ReadPreference::RP_SECONDARY_PREFERRED); $mockConfig->getCollectionForCBD('tripod_php_testing', 'CBD_testing', ReadPreference::RP_NEAREST); @@ -1684,9 +1683,7 @@ public function testMongoConnectionNoExceptionThrownWhenConnectionThrowsSomeExce $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->throwException(new ConnectionTimeoutException('Exception thrown when connecting to Mongo')), $this->returnCallback( - function (): Client { - return new Client(); - } + fn (): Client => new Client() ) ); diff --git a/test/unit/mongo/MongoTripodDriverTest.php b/test/unit/mongo/MongoTripodDriverTest.php index fdb27482..d6668ce2 100755 --- a/test/unit/mongo/MongoTripodDriverTest.php +++ b/test/unit/mongo/MongoTripodDriverTest.php @@ -2259,7 +2259,7 @@ public function testPassStatConfigToTripodConstructor(): void $this->assertEquals('example.com', $stat->getHost()); $this->assertEquals(1234, $stat->getPort()); - $this->assertEquals('somePrefix', $stat->getPrefix()); + $this->assertSame('somePrefix', $stat->getPrefix()); $config = $stat->getConfig(); $this->assertEquals( diff --git a/test/unit/mongo/MongoTripodStatTest.php b/test/unit/mongo/MongoTripodStatTest.php index 84c00058..51453f97 100644 --- a/test/unit/mongo/MongoTripodStatTest.php +++ b/test/unit/mongo/MongoTripodStatTest.php @@ -17,7 +17,7 @@ public function testStatFactory(): void $this->assertInstanceOf(StatsD::class, $stat); $this->assertEquals('example.com', $stat->getHost()); $this->assertEquals(1234, $stat->getPort()); - $this->assertEquals('somePrefix', $stat->getPrefix()); + $this->assertSame('somePrefix', $stat->getPrefix()); $noStat = TripodStatFactory::create(); $this->assertInstanceOf(NoStat::class, $noStat); @@ -30,14 +30,14 @@ public function testStatsDSettersAndGetters(): void $this->assertInstanceOf(StatsD::class, $stat); $this->assertEquals('example.com', $stat->getHost()); $this->assertEquals(1234, $stat->getPort()); - $this->assertEquals('somePrefix', $stat->getPrefix()); + $this->assertSame('somePrefix', $stat->getPrefix()); $this->assertEquals($this->getStatsDConfig(), $stat->getConfig()); $stat = new StatsD('foo.bar', 9876); $this->assertEquals('foo.bar', $stat->getHost()); $this->assertEquals(9876, $stat->getPort()); - $this->assertEquals('', $stat->getPrefix()); + $this->assertSame('', $stat->getPrefix()); $this->assertSame(['class' => StatsD::class, 'config' => ['host' => 'foo.bar', 'port' => 9876, 'prefix' => '']], $stat->getConfig()); $stat->setHost('bar.baz'); @@ -46,7 +46,7 @@ public function testStatsDSettersAndGetters(): void $stat->setPort(4567); $this->assertEquals(4567, $stat->getPort()); $stat->setPrefix('FOO_BAR'); - $this->assertEquals('FOO_BAR', $stat->getPrefix()); + $this->assertSame('FOO_BAR', $stat->getPrefix()); $this->assertSame(['class' => StatsD::class, 'config' => ['host' => 'bar.baz', 'port' => 4567, 'prefix' => 'FOO_BAR']], $stat->getConfig()); } diff --git a/test/unit/mongo/MongoTripodTablesTest.php b/test/unit/mongo/MongoTripodTablesTest.php index 202b0e8f..d0155938 100644 --- a/test/unit/mongo/MongoTripodTablesTest.php +++ b/test/unit/mongo/MongoTripodTablesTest.php @@ -42,7 +42,7 @@ class MongoTripodTablesTest extends MongoTripodTestBase protected $defaultPodName = 'CBD_testing'; - private $tablesConstParams; + private array $tablesConstParams; protected function setUp(): void { diff --git a/test/unit/mongo/MongoTripodTestBase.php b/test/unit/mongo/MongoTripodTestBase.php index 2d522796..ef6bb9d6 100644 --- a/test/unit/mongo/MongoTripodTestBase.php +++ b/test/unit/mongo/MongoTripodTestBase.php @@ -218,7 +218,7 @@ protected function assertDocumentVersion(array $_id, ?int $expectedValue = null, } $doc = $this->getDocument($_id, $tripod); - if ($hasVersion == true) { + if ($hasVersion) { $this->assertArrayHasKey('_version', $doc, 'Document for ' . var_export($_id, true) . ' should have a version, but none found'); if ($expectedValue !== null) { From cac83742cc21d611cb21e6edbd092c78be6ba84a Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 16 Mar 2026 00:11:09 +0000 Subject: [PATCH 34/56] Property types --- src/classes/ChangeSet.php | 6 +- src/classes/ExtendedGraph.php | 15 ++-- src/classes/Labeller.php | 15 +--- src/classes/StatsD.php | 4 +- src/exceptions/LabellerException.php | 12 +-- src/mongo/Config.php | 74 ++++--------------- src/mongo/Driver.php | 7 +- src/mongo/IConfigInstance.php | 1 + src/mongo/ImpactedSubject.php | 38 +++------- src/mongo/JobGroup.php | 8 +- src/mongo/MongoGraph.php | 2 +- src/mongo/base/CompositeBase.php | 13 +--- src/mongo/base/DriverBase.php | 48 +++--------- src/mongo/base/JobBase.php | 12 ++- src/mongo/delegates/SearchIndexer.php | 5 -- src/mongo/delegates/Tables.php | 24 ++---- src/mongo/delegates/TransactionLog.php | 4 +- src/mongo/delegates/Updates.php | 34 ++------- src/mongo/jobs/DiscoverImpactedSubjects.php | 11 +-- .../mongo/MongoTripodSearchIndexerTest.php | 1 - 20 files changed, 93 insertions(+), 241 deletions(-) diff --git a/src/classes/ChangeSet.php b/src/classes/ChangeSet.php index edc9d3dc..cac45c1c 100644 --- a/src/classes/ChangeSet.php +++ b/src/classes/ChangeSet.php @@ -19,10 +19,10 @@ class ChangeSet extends ExtendedGraph { /** @var TripleGraph */ - public $before = []; + public array $before = []; /** @var TripleGraph */ - public $after = []; + public array $after = []; /** * @var array{ @@ -38,7 +38,7 @@ class ChangeSet extends ExtendedGraph * 'http://purl.org/dc/terms/source'?: array|string * } */ - public $a; + public array $a; /** * Create a new changeset. This will calculate the required additions and removals based on before and after versions of a bounded description. The args parameter is an associative array that may have the following fields: diff --git a/src/classes/ExtendedGraph.php b/src/classes/ExtendedGraph.php index 9004628e..ff7d6689 100644 --- a/src/classes/ExtendedGraph.php +++ b/src/classes/ExtendedGraph.php @@ -29,16 +29,16 @@ class ExtendedGraph public const rdf_seq = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#Seq'; /** @var TripleGraph */ - public $_index = []; + public array $_index = []; /** @var string[] */ - public $_image_properties = [ + public array $_image_properties = [ 'http://xmlns.com/foaf/0.1/depiction', 'http://xmlns.com/foaf/0.1/img', ]; /** @var string[] */ - public $_property_order = [ + public array $_property_order = [ 'http://www.w3.org/2004/02/skos/core#prefLabel', RDFS_LABEL, 'http://purl.org/dc/terms/title', @@ -52,8 +52,7 @@ class ExtendedGraph RDF_TYPE, ]; - /** @var array */ - public $parser_errors = []; + public array $parser_errors = []; /** * @var Labeller @@ -61,7 +60,7 @@ class ExtendedGraph public $_labeller; /** @var array */ - protected $_ns = [ + protected array $_ns = [ 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', 'owl' => 'http://www.w3.org/2002/07/owl#', @@ -100,7 +99,7 @@ class ExtendedGraph * * @var string[] */ - private static $labelProperties; + private static array $labelProperties; /** * @param string|TripleGraph $graph @@ -1297,7 +1296,7 @@ public function get_list_values(string $listUri): array public static function initProperties(array $properties): void { if (array_key_exists('labelProperties', $properties)) { - self::$labelProperties = $properties['labelProperties']; + self::$labelProperties = $properties['labelProperties'] ?? []; } } diff --git a/src/classes/Labeller.php b/src/classes/Labeller.php index 56532426..af8d8ad7 100644 --- a/src/classes/Labeller.php +++ b/src/classes/Labeller.php @@ -12,10 +12,7 @@ */ class Labeller { - /** - * @var array - */ - public $_labels = [ + public array $_labels = [ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_1' => ['first', 'first', 'is first member of'], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_2' => ['second', 'second', 'is second member of'], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_3' => ['third', 'third', 'is third member of'], @@ -238,15 +235,9 @@ class Labeller 'http://purl.org/goodrelations/v1#hasGTIN-14' => ['GTIN-14'], ]; - /** - * @var array - */ - protected $_label_properties = []; + protected array $_label_properties = []; - /** - * @var array - */ - protected $_ns = [ + protected array $_ns = [ 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', 'owl' => 'http://www.w3.org/2002/07/owl#', diff --git a/src/classes/StatsD.php b/src/classes/StatsD.php index 92f7f883..d6cd3802 100644 --- a/src/classes/StatsD.php +++ b/src/classes/StatsD.php @@ -6,8 +6,7 @@ class StatsD implements ITripodStat { - /** @var string */ - private $host; + private string $host; /** @var int|string */ private $port; @@ -17,7 +16,6 @@ class StatsD implements ITripodStat private ?string $pivotValue = null; /** - * @param string $host * @param int|string $port */ public function __construct(string $host, $port, ?string $prefix = '') diff --git a/src/exceptions/LabellerException.php b/src/exceptions/LabellerException.php index 2fe266bd..b336042b 100644 --- a/src/exceptions/LabellerException.php +++ b/src/exceptions/LabellerException.php @@ -9,21 +9,15 @@ */ class LabellerException extends Exception { - private $target; + private ?string $target; - /** - * @param string $target - */ - public function __construct($target) + public function __construct(?string $target) { $this->target = $target; parent::__construct('Could not label: ' . $target); } - /** - * @return string - */ - public function getTarget() + public function getTarget(): ?string { return $this->target; } diff --git a/src/mongo/Config.php b/src/mongo/Config.php index cbe04b26..2fe49cd4 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -27,105 +27,65 @@ class Config implements IConfigInstance /** * All of the defined searchDocSpecs. - * - * @var array */ - protected $searchDocSpecs = []; + protected array $searchDocSpecs = []; /** * All defined namespaces. - * - * @var array */ - protected $ns = []; + protected array $ns = []; /** * The transaction log db config. - * - * @var array */ - protected $tConfig = []; + protected array $tConfig = []; /** * The value should be the name of a class that implement iTripodSearchProvider keyed by storename. - * - * @var array */ - protected $searchProviderClassName = []; + protected array $searchProviderClassName = []; /** * All of the predicates associated with a particular spec document. - * - * @var array */ - protected $specPredicates; + protected array $specPredicates; /** * A simple map between collection names and the database name they belong to. - * - * @var array */ - protected $collectionDatabases = []; + protected array $collectionDatabases = []; - /** - * @var array - */ - protected $activeMongoConnections = []; + protected array $activeMongoConnections = []; - /** - * @var string - */ - protected $defaultDatabase; + protected array $dataSources = []; - /** - * @var array - */ - protected $dataSources = []; + protected array $podConnections = []; - /** - * @var array - */ - protected $podConnections = []; - - /** - * @var string - */ - protected static $validationLevel = self::VALIDATE_MIN; + protected static string $validationLevel = self::VALIDATE_MIN; /** * Database connections, keyed by datasource, so we're not inadvertently opening many db connections through getDatabase(). - * - * @var array */ - protected $connections = []; + protected array $connections = []; - /** - * @var int - */ - protected $mongoCursorTimeout = 30000; + protected int $mongoCursorTimeout = 30000; /** * @var array */ - protected $batchSize = [ + protected array $batchSize = [ OP_TABLES => 100, OP_SEARCH => 100, OP_VIEWS => 25, ]; - /** - * @var LoggerInterface - */ - protected static $logger; + protected static ?LoggerInterface $logger = null; private ?array $config = null; private ?Labeller $labeller = null; - /** - * @var string - */ - private $defaultContext; + private string $defaultContext; /** * The defined database indexes, keyed by database name. @@ -151,10 +111,8 @@ class Config implements IConfigInstance /** * Defined database configuration: dbname, collections, etc. - * - * @var array */ - private $databases = []; + private array $databases = []; /** * Config should not be instantiated directly: use Config::getInstance(). diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index e7d43a72..48a6869b 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -26,14 +26,11 @@ class Driver extends DriverBase implements IDriver private ?SearchIndexer $searchIndexer = null; /** - * @var mixed[] + * @var array{OP_VIEWS: bool, OP_TABLES: bool, OP_SEARCH: bool} */ private array $async; - /** - * @var int - */ - private $retriesToGetLock; + private int $retriesToGetLock; private ?Updates $updates = null; diff --git a/src/mongo/IConfigInstance.php b/src/mongo/IConfigInstance.php index 5dee8cea..02bbad14 100644 --- a/src/mongo/IConfigInstance.php +++ b/src/mongo/IConfigInstance.php @@ -165,6 +165,7 @@ public function getTransactionLogConfig(): array; /** * @param string $storeName Store name + * * @return class-string|null */ public function getSearchProviderClassName(string $storeName): ?string; diff --git a/src/mongo/ImpactedSubject.php b/src/mongo/ImpactedSubject.php index 3feea429..a4a00044 100644 --- a/src/mongo/ImpactedSubject.php +++ b/src/mongo/ImpactedSubject.php @@ -11,43 +11,35 @@ /** * A subject that has been involved in an modification event (create/update, delete) and will therefore require * view, table and search doc generation. + * + * @phpstan-type ResourceId array{r: string, c: string} */ class ImpactedSubject { private ?string $operation = null; /** - * @var mixed[] + * @var ResourceId */ private array $resourceId; /** - * @var mixed[] + * @var string[] */ private array $specTypes; - /** - * @var string - */ - private $storeName; + private string $storeName; - /** - * @var string - */ - private $podName; + private string $podName; - private ?ITripodStat $tripodStat; + private ?ITripodStat $tripodStat = null; /** - * @param string $operation - * @param string $storeName - * @param string $podName - * * @throws Exception */ - public function __construct(array $resourceId, $operation, $storeName, $podName, array $specTypes = [], ?ITripodStat $stat = null) + public function __construct(array $resourceId, string $operation, string $storeName, string $podName, array $specTypes = [], ?ITripodStat $stat = null) { - if (!is_array($resourceId) || !array_key_exists(_ID_RESOURCE, $resourceId) || !array_key_exists(_ID_CONTEXT, $resourceId)) { + if (!array_key_exists(_ID_RESOURCE, $resourceId) || !array_key_exists(_ID_CONTEXT, $resourceId)) { throw new Exception('Parameter $resourceId needs to be of type array with ' . _ID_RESOURCE . ' and ' . _ID_CONTEXT . ' keys'); } @@ -73,10 +65,7 @@ public function getOperation(): ?string return $this->operation; } - /** - * @return string - */ - public function getPodName() + public function getPodName(): string { return $this->podName; } @@ -97,10 +86,7 @@ public function getSpecTypes(): array return $this->specTypes; } - /** - * @return string - */ - public function getStoreName() + public function getStoreName(): string { return $this->storeName; } @@ -127,7 +113,7 @@ public function toArray(): array public function update(): void { $tripod = $this->getTripod(); - if (property_exists($this, 'tripodStat') && $this->tripodStat !== null) { + if ($this->tripodStat !== null) { $tripod->setStat($this->tripodStat); } diff --git a/src/mongo/JobGroup.php b/src/mongo/JobGroup.php index c4bd8b8a..e24453ce 100644 --- a/src/mongo/JobGroup.php +++ b/src/mongo/JobGroup.php @@ -15,7 +15,7 @@ class JobGroup private ?Collection $collection = null; - private $storeName; + private string $storeName; /** * Constructor method. @@ -23,7 +23,7 @@ class JobGroup * @param string $storeName Tripod store (database) name * @param ObjectId|string $groupId Optional tracking ID, will assign a new one if omitted */ - public function __construct($storeName, $groupId = null) + public function __construct(string $storeName, $groupId = null) { $this->storeName = $storeName; if (!$groupId) { @@ -40,7 +40,7 @@ public function __construct($storeName, $groupId = null) * * @param int $count Number of jobs in group */ - public function setJobCount($count): void + public function setJobCount(int $count): void { $this->getMongoCollection()->updateOne( ['_id' => $this->getId()], @@ -56,7 +56,7 @@ public function setJobCount($count): void * * @return int Updated job count */ - public function incrementJobCount($inc = 1) + public function incrementJobCount(int $inc = 1): int { $updateResult = $this->getMongoCollection()->findOneAndUpdate( ['_id' => $this->getId()], diff --git a/src/mongo/MongoGraph.php b/src/mongo/MongoGraph.php index f06ffb73..eed7b431 100644 --- a/src/mongo/MongoGraph.php +++ b/src/mongo/MongoGraph.php @@ -34,7 +34,7 @@ public function __construct() * * @throws \InvalidArgumentException if you do not specify a context */ - public function to_nquads($context): string + public function to_nquads(?string $context): string { if (empty($context)) { throw new \InvalidArgumentException('You must specify the context when serializing to nquads'); diff --git a/src/mongo/base/CompositeBase.php b/src/mongo/base/CompositeBase.php index 44e64a4a..65e62e9d 100644 --- a/src/mongo/base/CompositeBase.php +++ b/src/mongo/base/CompositeBase.php @@ -12,10 +12,7 @@ abstract class CompositeBase extends DriverBase implements IComposite { - /** - * @var ApplyOperation - */ - protected $applyOperation; + protected ?ApplyOperation $applyOperation = null; /** * Returns an array of ImpactedSubjects based on the subjects and predicates of change. @@ -170,10 +167,8 @@ protected function checkIfTypeShouldTriggerOperation(?string $rdfType, array $va /** * For mocking. - * - * @return ApplyOperation */ - protected function getApplyOperation() + protected function getApplyOperation(): ApplyOperation { if ($this->applyOperation === null) { $this->applyOperation = new ApplyOperation(); @@ -186,10 +181,10 @@ protected function getApplyOperation() * Queues a batch of ImpactedSubjects in a single ApplyOperation job. * * @param ImpactedSubject[] $subjects Array of ImpactedSubjects - * @param string $queueName Queue name + * @param string|null $queueName Queue name * @param array $jobOptions Job options */ - protected function queueApplyJob(array $subjects, $queueName, array $jobOptions) + protected function queueApplyJob(array $subjects, ?string $queueName, array $jobOptions) { $this->getApplyOperation()->createJob($subjects, $queueName, $jobOptions); } diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index 575378a3..fedce2c6 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -31,58 +31,30 @@ abstract class DriverBase public const HOOK_FN_FAILURE = 'failure'; - /** - * @var LoggerInterface - */ - public static $logger; + public static ?LoggerInterface $logger = null; - /** - * @var Collection - */ - protected $collection; + protected string $storeName; - /** - * @var string - */ - protected $storeName; + protected string $podName; - /** - * @var string - */ - protected $podName; + protected ?string $defaultContext = null; - /** - * @var string|null - */ - protected $defaultContext; + protected ?ITripodStat $stat = null; - /** - * @var ITripodStat|null - */ - protected $stat; + protected array $statsConfig = []; - /** @var array */ - protected $statsConfig = []; + protected ?Database $db = null; - /** - * @var Database - */ - protected $db; + protected ?Collection $collection = null; /** * @var int|string */ protected $readPreference = ReadPreference::RP_PRIMARY_PREFERRED; - /** - * @var Labeller - */ - protected $labeller; + protected Labeller $labeller; - /** - * @var IConfigInstance - */ - protected $config; + protected IConfigInstance $config; public function getStat(): ITripodStat { diff --git a/src/mongo/base/JobBase.php b/src/mongo/base/JobBase.php index 5d3a9ce2..980d4908 100644 --- a/src/mongo/base/JobBase.php +++ b/src/mongo/base/JobBase.php @@ -44,15 +44,19 @@ abstract class JobBase extends DriverBase */ public $job; + /** + * @var string[] + */ protected $mandatoryArgs = []; + /** + * @var bool + */ protected $configRequired = false; - /** @var IConfigInstance */ - protected $tripodConfig; + protected ?IConfigInstance $tripodConfig = null; - /** @var Timer */ - protected $timer; + protected ?Timer $timer = null; private ?Driver $tripod = null; diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index b9f8196b..4d341ca3 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -8,7 +8,6 @@ use MongoDB\Driver\ReadPreference; use Tripod\Exceptions\SearchException; use Tripod\ISearchProvider; -use Tripod\ITripodStat; use Tripod\Mongo\Driver; use Tripod\Mongo\IConfigInstance; use Tripod\Mongo\ImpactedSubject; @@ -19,10 +18,6 @@ class SearchIndexer extends CompositeBase { - protected Labeller $labeller; - - protected ITripodStat $stat; - private Driver $tripod; private ?ISearchProvider $searchProvider = null; diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index fe39f9b6..3c253a75 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -25,11 +25,9 @@ class Tables extends CompositeBase * Note about the "true" value - this is so that the keys are defined as keys rather than values. If we move to * a json schema we could define the types of attribute and whether they are required or not. * - * @var array - * * @static */ - public static $predicateModifiers = [ + public static array $predicateModifiers = [ 'join' => [ 'glue' => true, 'predicates' => true, @@ -45,46 +43,36 @@ class Tables extends CompositeBase /** * Computed field config - A list of valid functions to write dynamic table row field values. * - * @var array - * * @static */ - public static $computedFieldFunctions = ['conditional', 'replace', 'arithmetic']; + public static array $computedFieldFunctions = ['conditional', 'replace', 'arithmetic']; /** * Computed conditional config - list of allowed conditional operators. * - * @var array - * * @static */ - public static $conditionalOperators = ['>', '<', '>=', '<=', '==', '!=', 'contains', 'not contains', '~=', '!~']; + public static array $conditionalOperators = ['>', '<', '>=', '<=', '==', '!=', 'contains', 'not contains', '~=', '!~']; /** * Computed arithmetic config - list of allowed arithmetic operators. * - * @var array - * * @static */ - public static $arithmeticOperators = ['+', '-', '*', '/', '%']; + public static array $arithmeticOperators = ['+', '-', '*', '/', '%']; - /** - * @var array - */ - protected $temporaryFields = []; + protected array $temporaryFields = []; /** * Construct accepts actual objects rather than strings as this class is a delegate of * Tripod and should inherit connections set up there. * - * @param string $storeName * @param ITripodStat|null $stat * @param string $readPreference * todo: MongoCollection -> podName */ public function __construct( - $storeName, + string $storeName, Collection $collection, ?string $defaultContext, $stat = null, diff --git a/src/mongo/delegates/TransactionLog.php b/src/mongo/delegates/TransactionLog.php index 36d97d8f..c5f87e82 100644 --- a/src/mongo/delegates/TransactionLog.php +++ b/src/mongo/delegates/TransactionLog.php @@ -4,7 +4,6 @@ namespace Tripod\Mongo; -use MongoDB\BSON\UTCDateTime; use MongoDB\Collection; use MongoDB\Database; use MongoDB\Driver\Cursor; @@ -19,8 +18,7 @@ class TransactionLog private Database $transaction_db; - /** @var Collection */ - private $transaction_collection; + private Collection $transaction_collection; /** * Constructor. diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 9f1443b4..7fa2d8e9 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -22,27 +22,13 @@ class Updates extends DriverBase { - /** - * @var Labeller - */ - protected $labeller; - protected Driver $tripod; - /** - * @var Database - */ - protected $locksDb; + protected ?Database $locksDb = null; - /** - * @var Collection - */ - protected $locksCollection; + protected ?Collection $locksCollection = null; - /** - * @var DiscoverImpactedSubjects - */ - protected $discoverImpactedSubjects; + protected ?DiscoverImpactedSubjects $discoverImpactedSubjects = null; private ?TransactionLog $transactionLog = null; @@ -61,17 +47,14 @@ class Updates extends DriverBase /** * @var int */ - private $retriesToGetLock; + private int $retriesToGetLock; /** - * @var mixed[] + * @var array{OP_VIEWS: bool, OP_TABLES: bool, OP_SEARCH: bool} */ private array $async; - /** - * @var string - */ - private $queueName; + private ?string $queueName = null; /** * @var IEventHook[] @@ -1172,10 +1155,7 @@ protected function getLocksDatabase() return $this->locksDb; } - /** - * @return Collection - */ - protected function getLocksCollection() + protected function getLocksCollection(): Collection { if ($this->locksCollection === null) { $this->locksCollection = $this->getLocksDatabase()->selectCollection(LOCKS_COLLECTION); diff --git a/src/mongo/jobs/DiscoverImpactedSubjects.php b/src/mongo/jobs/DiscoverImpactedSubjects.php index d1ba9cf8..c6eb1b3d 100644 --- a/src/mongo/jobs/DiscoverImpactedSubjects.php +++ b/src/mongo/jobs/DiscoverImpactedSubjects.php @@ -20,19 +20,16 @@ class DiscoverImpactedSubjects extends JobBase public const CONTEXT_ALIAS_KEY = 'contextAlias'; - /** - * @var ApplyOperation - */ - protected $applyOperation; + protected ?ApplyOperation $applyOperation = null; /** - * @var array + * @var array */ protected $subjectsGroupedByQueue = []; protected $configRequired = true; - protected $subjectCount; + protected int $subjectCount; protected $mandatoryArgs = [ self::STORE_NAME_KEY, @@ -207,7 +204,7 @@ protected function addSubjectToQueue(ImpactedSubject $subject, $queueName) * * @return ApplyOperation */ - protected function getApplyOperation() + protected function getApplyOperation(): ApplyOperation { if ($this->applyOperation === null) { $this->applyOperation = new ApplyOperation(); diff --git a/test/unit/mongo/MongoTripodSearchIndexerTest.php b/test/unit/mongo/MongoTripodSearchIndexerTest.php index 9220eca1..c8e444c5 100644 --- a/test/unit/mongo/MongoTripodSearchIndexerTest.php +++ b/test/unit/mongo/MongoTripodSearchIndexerTest.php @@ -533,7 +533,6 @@ public function testBatchSearchDocumentsGeneration(): void $tripod = $this->getMockBuilder(Driver::class) ->onlyMethods(['getStoreName']) ->setConstructorArgs(['CBD_testing', 'tripod_php_testing']) - ->disableOriginalConstructor() ->getMock(); $tripod->expects($this->atLeastOnce())->method('getStoreName')->willReturn('tripod_php_testing'); From 1cdb0e5f60fc48be7fcf5678fee140c1cffc4ae4 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Thu, 12 Mar 2026 11:08:43 +0000 Subject: [PATCH 35/56] Add phpstan --- .circleci/config.yml | 1 + composer.json | 4 +++- phpstan.neon | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 phpstan.neon diff --git a/.circleci/config.yml b/.circleci/config.yml index 527340c8..6519b6c8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -68,6 +68,7 @@ jobs: - checkout - run: composer install - run: composer lint + - run: composer analyse test: parameters: diff --git a/composer.json b/composer.json index 4472bdb3..c6a53d78 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "phpunit/phpunit": "^9.6.20", "resque/php-resque": "v1.3.6", "friendsofphp/php-cs-fixer": "^3.4", - "perftools/php-profiler": "^1.2" + "perftools/php-profiler": "^1.2", + "phpstan/phpstan": "^2.1" }, "autoload": { "classmap": ["src/"] @@ -40,6 +41,7 @@ }, "scripts": { "lint": "php-cs-fixer check", + "analyse": "phpstan analyse --memory-limit 1024M", "test": [ "Composer\\Config::disableProcessTimeout", "phpunit" diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..661d7431 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,17 @@ +parameters: + level: 5 + phpVersion: + min: 70400 # PHP 7.4 + max: 80419 # PHP 8.4.19 + tips: + treatPhpDocTypesAsCertain: false + ignoreErrors: + - '#Access to undefined constant MongoDB\\Driver\\ReadPreference\:\:RP_.*#' + - '#Call to an undefined method MongoDB\\Driver\\ReadPreference\:\:getMode\(\)#' + - identifier: missingType.iterableValue + reportUnmatched: false + - identifier: unset.possiblyHookedProperty + reportUnmatched: false + paths: + - src + - test From f676b4bc716e29f464c70c1c919e6a606e11c288 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 16 Mar 2026 13:31:47 +0000 Subject: [PATCH 36/56] Fixes --- src/Config.php | 2 +- src/classes/Labeller.php | 4 +- src/classes/StatsD.php | 5 +- src/mongo/Config.php | 15 +-- src/mongo/IConfigInstance.php | 7 + src/mongo/base/DriverBase.php | 7 +- src/mongo/base/JobBase.php | 101 +++++--------- src/mongo/delegates/SearchDocuments.php | 5 +- src/mongo/delegates/SearchIndexer.php | 21 +-- src/mongo/delegates/Tables.php | 74 +++++----- src/mongo/delegates/TransactionLog.php | 19 ++- src/mongo/delegates/Updates.php | 34 ++--- src/mongo/delegates/Views.php | 6 +- src/mongo/jobs/DiscoverImpactedSubjects.php | 2 - src/mongo/providers/ISearchProvider.php | 4 +- src/mongo/providers/MongoSearchProvider.php | 16 +-- src/mongo/util/IndexUtils.php | 126 ++++++++---------- src/mongo/util/TriplesUtil.php | 20 +-- test/stubs.php | 5 +- test/unit/mongo/ApplyOperationTest.php | 4 +- test/unit/mongo/ConfigGeneratorTest.php | 2 +- test/unit/mongo/EnsureIndexesTest.php | 6 +- test/unit/mongo/MongoTripodConfigUnitTest.php | 3 - test/unit/mongo/MongoTripodTestBase.php | 12 +- .../MongoTripodTransactionRollbackTest.php | 3 - test/unit/mongo/TestJobBase.php | 3 +- 26 files changed, 211 insertions(+), 295 deletions(-) diff --git a/src/Config.php b/src/Config.php index 73dde4a7..6f2c5f86 100644 --- a/src/Config.php +++ b/src/Config.php @@ -54,7 +54,7 @@ public static function setConfig(array $config): void */ public static function getConfig(): array { - return self::$config; + return self::$config ?? []; } /** diff --git a/src/classes/Labeller.php b/src/classes/Labeller.php index af8d8ad7..4d399c80 100644 --- a/src/classes/Labeller.php +++ b/src/classes/Labeller.php @@ -325,7 +325,7 @@ public function uri_to_qname(?string $uri): ?string $ns = $m[1]; $localname = $m[2]; $prefix = $this->get_prefix($ns); - if ($prefix != null && $prefix !== false) { + if ($prefix) { return $prefix . ':' . $localname; } } @@ -336,7 +336,7 @@ public function uri_to_qname(?string $uri): ?string public function get_prefix(string $ns): string { $prefix = array_search($ns, $this->_ns, true); - if ($prefix != null && $prefix !== false) { + if ($prefix) { return $prefix; } diff --git a/src/classes/StatsD.php b/src/classes/StatsD.php index d6cd3802..b41ba7d9 100644 --- a/src/classes/StatsD.php +++ b/src/classes/StatsD.php @@ -8,8 +8,7 @@ class StatsD implements ITripodStat { private string $host; - /** @var int|string */ - private $port; + private int $port; private ?string $prefix = null; @@ -217,7 +216,7 @@ protected function generateStatData(string $operation, $value): array protected function getStatsPaths(): array { - return array_values(array_filter([$this->getAggregateStatPath()])); + return array_filter([$this->getAggregateStatPath()]); } protected function getAggregateStatPath(): string diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 2fe49cd4..91fdec24 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -219,8 +219,6 @@ public function getDefaultContextAlias(): string * * @deprecated * - * @return Config - * * @throws ConfigException */ public static function getInstance(): IConfigInstance @@ -402,7 +400,7 @@ public function getDefaultDataSourceForStore(string $storeName): ?string */ public function getViewSpecification(string $storeName, string $vid): ?array { - if (isset($this->viewSpecs[$storeName], $this->viewSpecs[$storeName][$vid])) { + if (isset($this->viewSpecs[$storeName][$vid])) { return $this->viewSpecs[$storeName][$vid]; } @@ -1554,11 +1552,12 @@ protected function getPredicateAliasesFromPredicateProperty($predicate): array protected function getPredicatesFromPredicateFunctions(array $array): array { $predicates = []; - if (is_array($array)) { - if (isset($array['predicates'])) { - $predicates = $array['predicates']; - } else { - $predicates = array_merge($predicates, $this->getPredicatesFromPredicateFunctions($array[key($array)])); + if (isset($array['predicates'])) { + $predicates = $array['predicates']; + } elseif ($array !== []) { + $function = key($array); + if (is_array($array[$function])) { + $predicates = array_merge($predicates, $this->getPredicatesFromPredicateFunctions($array[$function])); } } diff --git a/src/mongo/IConfigInstance.php b/src/mongo/IConfigInstance.php index 02bbad14..04c70298 100644 --- a/src/mongo/IConfigInstance.php +++ b/src/mongo/IConfigInstance.php @@ -148,6 +148,13 @@ public function getTypesInTableSpecifications(string $storeName, ?string $pod = */ public function getTypesInSearchSpecifications(string $storeName, ?string $pod = null): array; + /** + * Returns a unique list of every rdf type configured in view, table, and search specifications. + * + * @param string $storeName Store name + */ + public function getAllTypesInSpecifications(string $storeName): array; + /** * Returns an array of database names. */ diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index fedce2c6..d5b9ea61 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -80,12 +80,7 @@ public function setStat(ITripodStat $stat): void */ public function getStatsConfig(): array { - $stat = $this->getStat(); - if ($stat) { - return $stat->getConfig(); - } - - return $this->statsConfig; + return $this->getStat()->getConfig(); } public function getStoreName(): string diff --git a/src/mongo/base/JobBase.php b/src/mongo/base/JobBase.php index 980d4908..6fee9c32 100644 --- a/src/mongo/base/JobBase.php +++ b/src/mongo/base/JobBase.php @@ -124,7 +124,7 @@ public static function onFailure($e, \Resque_Job $job): void public function getStat(): ITripodStat { - if ($this->statsConfig === null) { + if ($this->statsConfig === []) { $this->getStatsConfig(); } @@ -145,28 +145,15 @@ public function getStatsConfig(): array /** * Stat string for successful job timer. - * - * @return string */ - abstract protected function getStatTimerSuccessKey(); + abstract protected function getStatTimerSuccessKey(): string; /** * Stat string for failed job increment. - * - * @return string */ - abstract protected function getStatFailureIncrementKey(); + abstract protected function getStatFailureIncrementKey(): string; - /** - * For mocking. - * - * @param string $storeName - * @param string $podName - * @param array $opts - * - * @return Driver - */ - protected function getTripod($storeName, $podName, $opts = []) + protected function getTripod(string $storeName, string $podName, array $opts = []): Driver { $this->getTripodConfig(); @@ -190,10 +177,8 @@ protected function getTripod($storeName, $podName, $opts = []) /** * Make sure each job considers how to validate its args. - * - * @return array */ - protected function getMandatoryArgs() + protected function getMandatoryArgs(): array { return $this->mandatoryArgs; } @@ -203,7 +188,7 @@ protected function getMandatoryArgs() * * @throws \Exception */ - protected function validateArgs() + protected function validateArgs(): void { $message = null; foreach ($this->getMandatoryArgs() as $arg) { @@ -220,7 +205,7 @@ protected function validateArgs() } } - protected function ensureConfig() + protected function ensureConfig(): void { if (!isset($this->args[self::TRIPOD_CONFIG_KEY]) && !isset($this->args[self::TRIPOD_CONFIG_GENERATOR])) { $message = 'Argument ' . self::TRIPOD_CONFIG_KEY . ' or ' . self::TRIPOD_CONFIG_GENERATOR @@ -241,7 +226,7 @@ protected function ensureConfig() * * @throws JobException If there is a problem queuing the job */ - protected function submitJob($queueName, $class, array $data, $retryAttempts = 5) + protected function submitJob(string $queueName, string $class, array $data, int $retryAttempts = 5): string { // @see https://github.com/chrisboulton/php-resque/issues/228, when this PR is merged we can stop tracking the status in this way try { @@ -250,7 +235,7 @@ protected function submitJob($queueName, $class, array $data, $retryAttempts = 5 } $token = $this->enqueue($queueName, $class, $data); - if (!$this->getJobStatus($token)) { + if (!$token || !$this->hasJobStatus($token)) { $this->errorLog(sprintf('Could not retrieve status for queued %s job - job %s failed to %s', $class, $token, $queueName)); throw new \Exception(sprintf('Could not retrieve status for queued job - job %s failed to %s', $token, $queueName)); @@ -276,41 +261,31 @@ protected function submitJob($queueName, $class, array $data, $retryAttempts = 5 /** * Actually enqueues the job with Resque. Returns a tracking token. For mocking. * - * @param string $queueName - * @param string $class - * @param mixed $data - * - * @internal param bool|\Tripod\Mongo\Jobs\false $tracking + * @param array $data * - * @return string + * @return false|string */ - protected function enqueue($queueName, $class, $data) + protected function enqueue(string $queueName, string $class, array $data) { return \Resque::enqueue($queueName, $class, $data, true); } /** - * Given a token, return the job status. For mocking. - * - * @param string $token - * - * @return mixed + * Given a token, return the job status. */ - protected function getJobStatus($token) + protected function hasJobStatus(string $token): bool { $status = new \Resque_Job_Status($token); - return $status->get(); + return !empty($status->get()); } /** * Take a Tripod Config Serializer and return a config array. * - * @param array|ITripodConfigSerializer $configSerializer An object that implements ITripodConfigSerializer - * - * @return array + * @param mixed $configSerializer An object that implements ITripodConfigSerializer */ - protected function serializeConfig($configSerializer) + protected function serializeConfig($configSerializer): array { if ($configSerializer instanceof ITripodConfigSerializer) { return $configSerializer->serialize(); @@ -329,10 +304,8 @@ protected function serializeConfig($configSerializer) * Deserialize a tripodConfigGenerator argument to a Tripod Config object. * * @param array $config The serialized Tripod config - * - * @return IConfigInstance */ - protected function deserializeConfig(array $config) + protected function deserializeConfig(array $config): IConfigInstance { Config::setConfig($config); @@ -342,7 +315,7 @@ protected function deserializeConfig(array $config) /** * Sets the Tripod config for the job. */ - protected function setTripodConfig() + protected function setTripodConfig(): void { if (isset($this->args[self::TRIPOD_CONFIG_GENERATOR])) { $config = $this->args[self::TRIPOD_CONFIG_GENERATOR]; @@ -355,10 +328,8 @@ protected function setTripodConfig() /** * Returns the Tripod config required by the job. - * - * @return IConfigInstance */ - protected function getTripodConfig() + protected function getTripodConfig(): IConfigInstance { if ($this->tripodConfig === null) { $this->ensureConfig(); @@ -368,22 +339,12 @@ protected function getTripodConfig() return $this->tripodConfig; } - /** - * Sets the stats config for the job. - */ - protected function setStatsConfig() - { - if (isset($this->args['statsConfig'])) { - $this->statsConfig = $this->args['statsConfig']; - } - } - /** * Tripod options to pass between jobs. * - * @return array + * @return array */ - protected function getTripodOptions() + protected function getTripodOptions(): array { $statsConfig = $this->getStatsConfig(); $options = []; @@ -399,15 +360,11 @@ protected function getTripodOptions() * * @return array */ - protected function generateConfigJobArgs() + protected function generateConfigJobArgs(): array { $configInstance = $this->getConfigInstance(); $args = []; - if ($configInstance instanceof ITripodConfigSerializer) { - $config = $configInstance->serialize(); - } else { - $config = Config::getConfig(); - } + $config = $configInstance->serialize(); if (isset($config['class'])) { $args[self::TRIPOD_CONFIG_GENERATOR] = $config; @@ -417,4 +374,14 @@ protected function generateConfigJobArgs() return $args; } + + /** + * Sets the stats config for the job. + */ + private function setStatsConfig(): void + { + if (isset($this->args['statsConfig'])) { + $this->statsConfig = $this->args['statsConfig']; + } + } } diff --git a/src/mongo/delegates/SearchDocuments.php b/src/mongo/delegates/SearchDocuments.php index 19156648..a77754a6 100644 --- a/src/mongo/delegates/SearchDocuments.php +++ b/src/mongo/delegates/SearchDocuments.php @@ -32,12 +32,9 @@ public function __construct($storeName, Collection $collection, $defaultContext, } /** - * @param string $resource - * @param string $context - * * @throws \Exception */ - public function generateSearchDocumentBasedOnSpecId(string $specId, $resource, $context): ?array + public function generateSearchDocumentBasedOnSpecId(string $specId, ?string $resource, ?string $context): ?array { if (empty($resource)) { throw new \Exception('Resource must be specified'); diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 4d341ca3..8c8308e2 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -136,17 +136,13 @@ public function generateAndIndexSearchDocuments($resourceUri, $context, string $ } /** - * @param string|null $resourceUri - * @param string|null $context - * @param string|null $queueName - * * @return array|null Will return an array with a count and group id, if $queueName is sent and $resourceUri is null */ public function generateSearchDocuments( string $searchDocumentType, - $resourceUri = null, - $context = null, - $queueName = null + ?string $resourceUri = null, + ?string $context = null, + ?string $queueName = null ): ?array { $t = new Timer(); $t->start(); @@ -188,7 +184,7 @@ public function generateSearchDocuments( $jobOptions = []; $subjects = []; - if ($queueName && !$resourceUri) { + if ($queueName) { $jobOptions['statsConfig'] = $this->getStatsConfig(); $jobGroup = $this->getJobGroup($this->storeName); $jobOptions[ApplyOperation::TRACKING_KEY] = $jobGroup->getId()->__toString(); @@ -196,7 +192,7 @@ public function generateSearchDocuments( } foreach ($docs as $doc) { - if ($queueName && !$resourceUri) { + if ($queueName) { $subject = new ImpactedSubject( $doc['_id'], OP_SEARCH, @@ -250,12 +246,7 @@ public function findImpactedComposites(array $resourcesAndPredicates, string $co return $this->getSearchProvider()->findImpactedDocuments($resourcesAndPredicates, $contextAlias); } - /** - * @param string $typeId - * - * @return array|bool - */ - public function deleteSearchDocumentsByTypeId($typeId) + public function deleteSearchDocumentsByTypeId(string $typeId): int { return $this->getSearchProvider()->deleteSearchDocumentsByTypeId($typeId); } diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index 3c253a75..00d79e26 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -213,7 +213,7 @@ public function getOperationType(): string * @param array $options Table query options * @param array $filter * - * @return array + * @return array{head: array{count: int, offset: int, limit: int}, results: array|CursorInterface} */ public function getTableRows( string $tableSpecId, @@ -307,12 +307,12 @@ public function distinct(string $tableSpecId, string $fieldName, array $filter = /** * This method will delete all table rows where the _id.type matches the specified $tableId. * - * @param string $tableId Table spec ID - * @param UTCDateTime|null $timestamp Optional timestamp to delete all table rows that are older than + * @param string $tableId Table spec ID + * @param int|UTCDateTime|null $timestamp Optional timestamp to delete all table rows that are older than * * @return int The number of table rows deleted */ - public function deleteTableRowsByTableId(string $tableId, $timestamp = null) + public function deleteTableRowsByTableId(string $tableId, $timestamp = null): int { $t = new Timer(); $t->start(); @@ -321,7 +321,7 @@ public function deleteTableRowsByTableId(string $tableId, $timestamp = null) if ($tableSpec == null) { $this->debugLog('Could not find a table specification for ' . $tableId); - return; + return 0; } $query = ['_id.type' => $tableId]; @@ -1033,12 +1033,15 @@ protected function doConditional($left, $operator, $right) * @param array $spec * @param array $dest */ - protected function addFields(array $source, array $spec, array &$dest) + protected function addFields(array $source, array $spec, array &$dest): void { if (isset($spec['fields'])) { foreach ($spec['fields'] as $f) { - if (isset($f['temporary']) && $f['temporary'] === true && !in_array($f['fieldName'], $this->temporaryFields)) { - $this->temporaryFields[] = $f['fieldName']; + /** @var string */ + $fieldName = $f['fieldName']; + + if (isset($f['temporary']) && $f['temporary'] === true && !in_array($fieldName, $this->temporaryFields)) { + $this->temporaryFields[] = $fieldName; } if (isset($f['predicates'])) { @@ -1062,8 +1065,8 @@ protected function addFields(array $source, array $spec, array &$dest) } // Otherwise apply a modifier - } elseif (isset($dest[$f['fieldName']])) { - $dest[$f['fieldName']] = $this->applyModifier($function, $dest[$f['fieldName']], $functionOptions); + } elseif (isset($dest[$fieldName])) { + $dest[$fieldName] = $this->applyModifier($function, $dest[$fieldName], $functionOptions); } } } @@ -1077,14 +1080,14 @@ protected function addFields(array $source, array $spec, array &$dest) } // If value exists, set as array - if (isset($dest[$f['fieldName']])) { - if (!is_array($dest[$f['fieldName']])) { - $dest[$f['fieldName']] = [$dest[$f['fieldName']]]; + if (isset($dest[$fieldName])) { + if (!is_array($dest[$fieldName])) { + $dest[$fieldName] = [$dest[$fieldName]]; } - $dest[$f['fieldName']][] = $this->labeller->qname_to_alias($source['_id']['r']); + $dest[$fieldName][] = $this->labeller->qname_to_alias($source['_id']['r']); } else { - $dest[$f['fieldName']] = $this->labeller->qname_to_alias($source['_id']['r']); + $dest[$fieldName] = $this->labeller->qname_to_alias($source['_id']['r']); } } } @@ -1096,9 +1099,9 @@ protected function addFields(array $source, array $spec, array &$dest) * * @param array $source * @param array $f - * @param string $predicate + * @param array $dest */ - protected function generateValues(array $source, array $f, $predicate, array &$dest) + protected function generateValues(array $source, array $f, string $predicate, array &$dest): void { $values = []; if (isset($source[$predicate][VALUE_URI]) && !empty($source[$predicate][VALUE_URI])) { @@ -1119,20 +1122,23 @@ protected function generateValues(array $source, array $f, $predicate, array &$d } } + /** @var string */ + $fieldName = $f['fieldName']; + // now add all the values foreach ($values as $v) { - if (!isset($dest[$f['fieldName']])) { + if (!isset($dest[$fieldName])) { // single value - $dest[$f['fieldName']] = $v; - } elseif (is_array($dest[$f['fieldName']])) { + $dest[$fieldName] = $v; + } elseif (is_array($dest[$fieldName])) { // add to existing array of values - $dest[$f['fieldName']][] = $v; + $dest[$fieldName][] = $v; } else { // convert from single value to array of values - $existingVal = $dest[$f['fieldName']]; - $dest[$f['fieldName']] = []; - $dest[$f['fieldName']][] = $existingVal; - $dest[$f['fieldName']][] = $v; + $existingVal = $dest[$fieldName]; + $dest[$fieldName] = []; + $dest[$fieldName][] = $existingVal; + $dest[$fieldName][] = $v; } } } @@ -1140,7 +1146,7 @@ protected function generateValues(array $source, array $f, $predicate, array &$d /** * Recursively get functions that can modify a predicate. * - * @param array $array + * @param array|string $array */ protected function getPredicateFunctions($array): array { @@ -1148,9 +1154,12 @@ protected function getPredicateFunctions($array): array if (is_array($array)) { if (isset($array['predicates'])) { $predicateFunctions['predicates'] = $array['predicates']; - } else { - $predicateFunctions[key($array)] = $array[key($array)]; - $predicateFunctions = array_merge($predicateFunctions, $this->getPredicateFunctions($array[key($array)])); + } elseif ($array !== []) { + $function = key($array); + $predicateFunctions[$function] = $array[$function]; + if (is_array($array[$function])) { + $predicateFunctions = array_merge($predicateFunctions, $this->getPredicateFunctions($array[$function])); + } } } @@ -1318,15 +1327,14 @@ protected function getCollectionForTableSpec(string $tableSpecId): Collection * join - pass in "glue":" " to specify what to glue multiple values together with * date - no options. * - * @param string $modifier - * @param string $value - * @param array $options + * @param string|string[]|\Stringable|\Stringable[] $value + * @param array $options * * @return mixed * * @throws \Exception */ - private function applyModifier($modifier, $value, array $options = []) + private function applyModifier(string $modifier, $value, array $options = []) { switch ($modifier) { case 'predicates': diff --git a/src/mongo/delegates/TransactionLog.php b/src/mongo/delegates/TransactionLog.php index c5f87e82..a08b9d37 100644 --- a/src/mongo/delegates/TransactionLog.php +++ b/src/mongo/delegates/TransactionLog.php @@ -6,14 +6,13 @@ use MongoDB\Collection; use MongoDB\Database; -use MongoDB\Driver\Cursor; +use MongoDB\Driver\CursorInterface; use MongoDB\InsertOneResult; use MongoDB\UpdateResult; use Tripod\Config; class TransactionLog { - /** @var IConfigInstance */ protected array $config; private Database $transaction_db; @@ -142,16 +141,14 @@ public function purgeAllTransactions(): void } /** - * @param string $storeName - * @param string $podName - * @param string|null $fromDate only transactions after this specified date. This must be a datetime string i.e. '2010-01-15 00:00:00' - * @param string|null $toDate only transactions before this specified date. This must be a datetime string i.e. '2010-01-15 00:00:00' + * @param string|null $fromDate only transactions after this specified date. This must be a datetime string i.e. '2010-01-15 00:00:00' + * @param string|null $toDate only transactions before this specified date. This must be a datetime string i.e. '2010-01-15 00:00:00' * - * @return Cursor + * @return CursorInterface&\Iterator * * @throws \InvalidArgumentException */ - public function getCompletedTransactions($storeName = null, $podName = null, $fromDate = null, $toDate = null) + public function getCompletedTransactions(?string $storeName = null, ?string $podName = null, ?string $fromDate = null, ?string $toDate = null) { $query = []; $query['status'] = 'completed'; @@ -184,14 +181,14 @@ public function getTotalTransactionCount() } /** - * @param string $storeName database name to filter on (optional) - * @param string $podName collectionName to filter on (optional) + * @param string|null $storeName database name to filter on (optional) + * @param string|null $podName collectionName to filter on (optional) * * @return int Total number of completed transactions in the transaction log * * @codeCoverageIgnore */ - public function getCompletedTransactionCount($storeName = null, $podName = null) + public function getCompletedTransactionCount(?string $storeName = null, ?string $podName = null) { if (!empty($storeName) && !empty($podName)) { return $this->transaction_collection->count(['status' => 'completed', 'dbName' => $storeName, 'collectionName' => $podName]); diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 7fa2d8e9..ebb3b3e7 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -33,20 +33,15 @@ class Updates extends DriverBase private ?TransactionLog $transactionLog = null; /** - * @var string the original read preference gets stored here - * when changing for a write + * @var int|string the original read preference gets stored here when changing for a write */ private $originalCollectionReadPreference = ''; /** - * @var string the original read preference gets stored here - * when changing for a write + * @var int|string the original read preference gets stored here when changing for a write */ private $originalDbReadPreference = ''; - /** - * @var int - */ private int $retriesToGetLock; /** @@ -405,7 +400,7 @@ protected function resetOriginalReadPreference() { $dbReadPref = $this->db->getReadPreference(); if ($this->originalDbReadPreference !== $dbReadPref->getMode()) { - $pref = $this->originalDbReadPreference ?? $this->readPreference; + $pref = $this->originalDbReadPreference ?: $this->readPreference; $dbTagsets = $dbReadPref->getTagsets(); $this->db = $this->db->withOptions([ @@ -416,7 +411,7 @@ protected function resetOriginalReadPreference() // Reset collection object $collReadPref = $this->getCollection()->getReadPreference(); if ($this->originalCollectionReadPreference !== $collReadPref->getMode()) { - $pref = $this->originalCollectionReadPreference ?? $this->readPreference; + $pref = $this->originalCollectionReadPreference ?: $this->readPreference; $collTagsets = $collReadPref->getTagsets(); $this->collection = $this->collection->withOptions([ 'readPreference' => new ReadPreference($pref, $collTagsets), @@ -988,13 +983,11 @@ protected function unlockAllDocuments(string $transaction_id): bool /** * Lock and return a single document for editing. * - * @param string $s subject URI of resource to lock - * @param string $transaction_id - * @param string $contextAlias + * @param string $s subject URI of resource to lock * - * @return array + * @return array|false */ - protected function lockSingleDocument(?string $s, $transaction_id, $contextAlias) + protected function lockSingleDocument(string $s, string $transaction_id, string $contextAlias) { $countEntriesInLocksCollection = $this->getLocksCollection() ->count( @@ -1132,21 +1125,16 @@ protected function getTripod(array $data): Driver /** * This proxy method allows us to mock updates against $this->collection. * - * @param mixed $query - * @param mixed $update + * @param array|object $query + * @param array|object $update * @param array $options - * - * @return bool */ - protected function updateCollection($query, $update, array $options) + protected function updateCollection($query, $update, array $options): UpdateResult { return $this->getCollection()->replaceOne($query, $update, $options); } - /** - * @return Database - */ - protected function getLocksDatabase() + protected function getLocksDatabase(): Database { if ($this->locksDb === null) { $this->locksDb = $this->config->getDatabase($this->storeName); diff --git a/src/mongo/delegates/Views.php b/src/mongo/delegates/Views.php index 73f36e64..d1b83c3e 100644 --- a/src/mongo/delegates/Views.php +++ b/src/mongo/delegates/Views.php @@ -332,13 +332,13 @@ public function generateViewsForResourcesOfType(string $rdfType, ?string $resour * * @return int The number of views deleted */ - public function deleteViewsByViewId(string $viewId, $timestamp = null) + public function deleteViewsByViewId(string $viewId, $timestamp = null): int { $viewSpec = $this->getConfigInstance()->getViewSpecification($this->storeName, $viewId); if ($viewSpec == null) { $this->debugLog(sprintf("Could not find a view specification with viewId '%s'", $viewId)); - return; + return 0; } $query = ['_id.type' => $viewId]; @@ -749,7 +749,7 @@ private function createTripodViewIdsFromResourceUris(array $resourceUriOrArray, } /** - * @param string $viewSpec + * @param array{from: string}|null $viewSpec * * @return string */ diff --git a/src/mongo/jobs/DiscoverImpactedSubjects.php b/src/mongo/jobs/DiscoverImpactedSubjects.php index c6eb1b3d..496661f8 100644 --- a/src/mongo/jobs/DiscoverImpactedSubjects.php +++ b/src/mongo/jobs/DiscoverImpactedSubjects.php @@ -201,8 +201,6 @@ protected function addSubjectToQueue(ImpactedSubject $subject, $queueName) /** * For mocking. - * - * @return ApplyOperation */ protected function getApplyOperation(): ApplyOperation { diff --git a/src/mongo/providers/ISearchProvider.php b/src/mongo/providers/ISearchProvider.php index 72186ac9..ffa653ad 100644 --- a/src/mongo/providers/ISearchProvider.php +++ b/src/mongo/providers/ISearchProvider.php @@ -78,9 +78,9 @@ public function search(string $query, string $type, array $indices = [], array $ * * @param string $typeId search type id * - * @return array|bool response returned by mongo + * @return int The number of search documents deleted * * @throws Exception if there was an error performing the operation */ - public function deleteSearchDocumentsByTypeId($typeId); + public function deleteSearchDocumentsByTypeId(string $typeId): int; } diff --git a/src/mongo/providers/MongoSearchProvider.php b/src/mongo/providers/MongoSearchProvider.php index f00af63b..c38b6d71 100644 --- a/src/mongo/providers/MongoSearchProvider.php +++ b/src/mongo/providers/MongoSearchProvider.php @@ -9,6 +9,7 @@ use MongoDB\BSON\Regex; use MongoDB\BSON\UTCDateTime; use MongoDB\Collection; +use Tripod\Config; use Tripod\Exceptions\SearchException; use Tripod\ISearchProvider; use Tripod\Timer; @@ -17,9 +18,6 @@ class MongoSearchProvider implements ISearchProvider { protected string $storeName; - /** - * @var Config - */ protected IConfigInstance $config; private Labeller $labeller; @@ -208,7 +206,7 @@ public function __construct(Driver $tripod) { $this->storeName = $tripod->getStoreName(); $this->labeller = new Labeller(); - $this->config = \Tripod\Config::getInstance(); + $this->config = Config::getInstance(); } /** @@ -385,11 +383,11 @@ public function search(string $query, string $type, array $indices = [], array $ throw new SearchException('You must specify at least one field from the search document specification to return'); } - if (!is_numeric($limit) || $limit < 0) { + if ($limit < 0) { throw new SearchException('Value for limit must be a positive number'); } - if (!is_numeric($offset) || $offset < 0) { + if ($offset < 0) { throw new SearchException('Value for offset must be a positive number'); } @@ -483,14 +481,14 @@ public function getSearchCollectionName(): string * Here search type id represents to id from, mongo tripod config, that is converted to _id.type in SEARCH_INDEX_COLLECTION * If type id is not specified this method will throw an exception. * - * @param string $typeId Search type id - * @param UTCDateTime|null $timestamp Optional timestamp to delete all search docs that are older than + * @param string $typeId Search type id + * @param int|UTCDateTime|null $timestamp Optional timestamp to delete all search docs that are older than * * @return int The number of search documents deleted * * @throws \Tripod\Exceptions\Exception if there was an error performing the operation */ - public function deleteSearchDocumentsByTypeId($typeId, $timestamp = null) + public function deleteSearchDocumentsByTypeId(string $typeId, $timestamp = null): int { $searchSpec = $this->getSearchDocumentSpecification($typeId); if ($searchSpec == null) { diff --git a/src/mongo/util/IndexUtils.php b/src/mongo/util/IndexUtils.php index 4683f190..85ccecc5 100644 --- a/src/mongo/util/IndexUtils.php +++ b/src/mongo/util/IndexUtils.php @@ -15,7 +15,7 @@ class IndexUtils * @param string|null $storeName - database name to ensure indexes for * @param bool $background - index in the background (default) or lock DB whilst indexing */ - public function ensureIndexes($reindex = false, $storeName = null, $background = true): void + public function ensureIndexes(bool $reindex = false, ?string $storeName = null, bool $background = true): void { $config = $this->getConfig(); $dbs = ($storeName == null) ? $config->getDbs() : [$storeName]; @@ -69,87 +69,81 @@ public function ensureIndexes($reindex = false, $storeName = null, $background = // Index views foreach ($config->getViewSpecifications($storeName) as $viewId => $spec) { $collection = $config->getCollectionForView($storeName, $viewId); - if ($collection) { - $indexes = [ - [_ID_KEY . '.' . _ID_RESOURCE => 1, _ID_KEY . '.' . _ID_CONTEXT => 1, _ID_KEY . '.' . _ID_TYPE => 1], - [_ID_KEY . '.' . _ID_TYPE => 1], - ['value.' . _IMPACT_INDEX => 1], - [\_CREATED_TS => 1], - ]; - if (isset($spec['ensureIndexes'])) { - $indexes = array_merge($indexes, $spec['ensureIndexes']); - } + $indexes = [ + [_ID_KEY . '.' . _ID_RESOURCE => 1, _ID_KEY . '.' . _ID_CONTEXT => 1, _ID_KEY . '.' . _ID_TYPE => 1], + [_ID_KEY . '.' . _ID_TYPE => 1], + ['value.' . _IMPACT_INDEX => 1], + [\_CREATED_TS => 1], + ]; + if (isset($spec['ensureIndexes'])) { + $indexes = array_merge($indexes, $spec['ensureIndexes']); + } - if ($reindex && !in_array($collection->getNamespace(), $reindexedCollections)) { - $collection->dropIndexes(); - $reindexedCollections[] = $collection->getNamespace(); - } + if ($reindex && !in_array($collection->getNamespace(), $reindexedCollections)) { + $collection->dropIndexes(); + $reindexedCollections[] = $collection->getNamespace(); + } - foreach ($indexes as $index) { - $collection->createIndex( - $index, - [ - 'background' => $background, - ] - ); - } + foreach ($indexes as $index) { + $collection->createIndex( + $index, + [ + 'background' => $background, + ] + ); } } // Index table rows foreach ($config->getTableSpecifications($storeName) as $tableId => $spec) { $collection = $config->getCollectionForTable($storeName, $tableId); - if ($collection) { - $indexes = [ - [_ID_KEY . '.' . _ID_RESOURCE => 1, _ID_KEY . '.' . _ID_CONTEXT => 1, _ID_KEY . '.' . _ID_TYPE => 1], - [_ID_KEY . '.' . _ID_TYPE => 1], - ['value.' . _IMPACT_INDEX => 1], - [\_CREATED_TS => 1], - ]; - if (isset($spec['ensureIndexes'])) { - $indexes = array_merge($indexes, $spec['ensureIndexes']); - } + $indexes = [ + [_ID_KEY . '.' . _ID_RESOURCE => 1, _ID_KEY . '.' . _ID_CONTEXT => 1, _ID_KEY . '.' . _ID_TYPE => 1], + [_ID_KEY . '.' . _ID_TYPE => 1], + ['value.' . _IMPACT_INDEX => 1], + [\_CREATED_TS => 1], + ]; + if (isset($spec['ensureIndexes'])) { + $indexes = array_merge($indexes, $spec['ensureIndexes']); + } - if ($reindex && !in_array($collection->getNamespace(), $reindexedCollections)) { - $collection->dropIndexes(); - $reindexedCollections[] = $collection->getNamespace(); - } + if ($reindex && !in_array($collection->getNamespace(), $reindexedCollections)) { + $collection->dropIndexes(); + $reindexedCollections[] = $collection->getNamespace(); + } - foreach ($indexes as $index) { - $collection->createIndex( - $index, - [ - 'background' => $background, - ] - ); - } + foreach ($indexes as $index) { + $collection->createIndex( + $index, + [ + 'background' => $background, + ] + ); } } // index search documents foreach (array_keys($config->getSearchDocumentSpecifications($storeName)) as $searchId) { $collection = $config->getCollectionForSearchDocument($storeName, $searchId); - if ($collection) { - $indexes = [ - [_ID_KEY . '.' . _ID_RESOURCE => 1, _ID_KEY . '.' . _ID_CONTEXT => 1], - [_ID_KEY . '.' . _ID_TYPE => 1], - [_IMPACT_INDEX => 1], - [\_CREATED_TS => 1], - ]; - - if ($reindex && !in_array($collection->getNamespace(), $reindexedCollections)) { - $collection->dropIndexes(); - $reindexedCollections[] = $collection->getNamespace(); - } + $indexes = [ + [_ID_KEY . '.' . _ID_RESOURCE => 1, _ID_KEY . '.' . _ID_CONTEXT => 1], + [_ID_KEY . '.' . _ID_TYPE => 1], + [_IMPACT_INDEX => 1], + [\_CREATED_TS => 1], + ]; + + if ($reindex && !in_array($collection->getNamespace(), $reindexedCollections)) { + $collection->dropIndexes(); + $reindexedCollections[] = $collection->getNamespace(); + } - foreach ($indexes as $index) { - $collection->createIndex( - $index, - [ - 'background' => $background, - ] - ); - } + foreach ($indexes as $index) { + $collection->createIndex( + $index, + [ + 'background' => $background, + ] + ); } } } @@ -158,8 +152,6 @@ public function ensureIndexes($reindex = false, $storeName = null, $background = /** * returns mongo tripod config instance, this method aids helps with * testing. - * - * @return \Tripod\Mongo\Config */ protected function getConfig(): IConfigInstance { diff --git a/src/mongo/util/TriplesUtil.php b/src/mongo/util/TriplesUtil.php index cbcb6513..5122e9df 100644 --- a/src/mongo/util/TriplesUtil.php +++ b/src/mongo/util/TriplesUtil.php @@ -10,8 +10,6 @@ class TriplesUtil { - private array $collections = []; - private Labeller $labeller; /** @@ -26,19 +24,12 @@ public function __construct() * Add $triples about a given $subject to Mongo. Only $triples with subject matching $subject will be added, others will be ignored. * Make them quads with a $context. * - * @param mixed $subject - * @param string $podName - * @param string|null $context * @param string[]|null $allowableTypes */ - public function loadTriplesAbout($subject, array $triples, string $storeName, $podName, $context = null, $allowableTypes = null): void + public function loadTriplesAbout(string $subject, array $triples, string $storeName, string $podName, ?string $context = null, ?array $allowableTypes = null): void { - $context = ($context == null) ? Config::getInstance()->getDefaultContextAlias() : $this->labeller->uri_to_alias($context); - if (array_key_exists($podName, $this->collections)) { - $collection = $this->collections[$podName]; - } else { - $collection = Config::getInstance()->getCollectionForCBD($storeName, $podName); - } + $context = $context !== null ? $this->labeller->uri_to_alias($context) : Config::getInstance()->getDefaultContextAlias(); + $collection = Config::getInstance()->getCollectionForCBD($storeName, $podName); $graph = new MongoGraph(); foreach ($triples as $triple) { @@ -56,11 +47,8 @@ public function loadTriplesAbout($subject, array $triples, string $storeName, $p } } - if ($allowableTypes != null && is_array($allowableTypes)) { + if ($allowableTypes != null) { $types = $graph->get_resource_triple_values($subject, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); - if ($types == null || $types === []) { - return; - } foreach ($types as $type) { if (in_array($type, $allowableTypes)) { diff --git a/test/stubs.php b/test/stubs.php index fc269729..768a0911 100644 --- a/test/stubs.php +++ b/test/stubs.php @@ -4,7 +4,4 @@ namespace Tripod\Mongo; -function sleep(int $seconds): int -{ - return 0; -} +function sleep(int $seconds): void {} diff --git a/test/unit/mongo/ApplyOperationTest.php b/test/unit/mongo/ApplyOperationTest.php index 2ac9395e..e7624706 100644 --- a/test/unit/mongo/ApplyOperationTest.php +++ b/test/unit/mongo/ApplyOperationTest.php @@ -993,11 +993,11 @@ public function testCreateJobStatusFalse(): void ); $applyOperation = $this->getMockBuilder(ApplyOperation::class) - ->onlyMethods(['enqueue', 'getJobStatus', 'warningLog']) + ->onlyMethods(['enqueue', 'hasJobStatus', 'warningLog']) ->getMock(); $applyOperation->method('enqueue')->willReturn('sometoken'); - $applyOperation->method('getJobStatus')->willReturn(false); + $applyOperation->method('hasJobStatus')->willReturn(false); // expect 5 retries. Catch this with call to warning log $applyOperation->expects($this->exactly(5))->method('warningLog'); diff --git a/test/unit/mongo/ConfigGeneratorTest.php b/test/unit/mongo/ConfigGeneratorTest.php index c3b1dbc7..bd43f2a2 100644 --- a/test/unit/mongo/ConfigGeneratorTest.php +++ b/test/unit/mongo/ConfigGeneratorTest.php @@ -150,7 +150,7 @@ public function testSerializedConfigGeneratorsSentToApplyJobs(): void ->setMockClassName('ApplyOperation_TestConfigGenerator') ->getMock(); $discoverJob->args = $jobArgs; - $discoverJob->job = (object) ['payload' => ['id' => uniqid()]]; + $discoverJob->job = new Resque_Job('discover_queue', ['id' => uniqid()]); $discoverJob->expects($this->once())->method('getTripod')->willReturn($tripod); $discoverJob->expects($this->once())->method('getApplyOperation')->willReturn($applyJob); $configInstance = Config::getInstance(); diff --git a/test/unit/mongo/EnsureIndexesTest.php b/test/unit/mongo/EnsureIndexesTest.php index ab28c2ec..b35e0c86 100644 --- a/test/unit/mongo/EnsureIndexesTest.php +++ b/test/unit/mongo/EnsureIndexesTest.php @@ -164,13 +164,13 @@ public function testEnsureIndexesCreateJobStatusFalse(): void ]; $job = $this->getMockBuilder(EnsureIndexes::class) - ->onlyMethods(['warningLog', 'enqueue', 'getJobStatus']) + ->onlyMethods(['warningLog', 'enqueue', 'hasJobStatus']) ->getMock(); // both of these methods will be called 6 times because after the first attempt fails it will // retry 5 times. $job->expects($this->exactly(6))->method('enqueue')->willReturn('sometoken'); - $job->expects($this->exactly(6))->method('getJobStatus')->willReturn(false); + $job->expects($this->exactly(6))->method('hasJobStatus')->willReturn(false); // expect 5 retries. Catch this with call to warning log $job->expects($this->exactly(5))->method('warningLog'); @@ -214,7 +214,7 @@ public function testEnsureIndexesCreateJobSpecifyQueue(): void * * @return EnsureIndexes&MockObject */ - protected function createMockJob(array $methods = ['getIndexUtils', 'submitJob', 'warningLog', 'enqueue', 'getJobStatus']): MockObject + protected function createMockJob(array $methods = ['getIndexUtils', 'submitJob', 'warningLog', 'enqueue', 'hasJobStatus']): MockObject { $mockEnsureIndexesJob = $this->getMockBuilder(EnsureIndexes::class) ->onlyMethods($methods) diff --git a/test/unit/mongo/MongoTripodConfigUnitTest.php b/test/unit/mongo/MongoTripodConfigUnitTest.php index cea5fcb9..8f9e7f9c 100644 --- a/test/unit/mongo/MongoTripodConfigUnitTest.php +++ b/test/unit/mongo/MongoTripodConfigUnitTest.php @@ -16,9 +16,6 @@ class MongoTripodConfigUnitTest extends MongoTripodTestBase { - /** - * @var Tripod\Mongo\Config - */ private IConfigInstance $tripodConfig; protected function setUp(): void diff --git a/test/unit/mongo/MongoTripodTestBase.php b/test/unit/mongo/MongoTripodTestBase.php index ef6bb9d6..f17b8065 100644 --- a/test/unit/mongo/MongoTripodTestBase.php +++ b/test/unit/mongo/MongoTripodTestBase.php @@ -21,12 +21,12 @@ abstract class MongoTripodTestBase extends TestCase { /** - * @var Driver + * @var Driver|null */ protected $tripod; /** - * @var TransactionLog + * @var TransactionLog|null */ protected $tripodTransactionLog; @@ -206,7 +206,7 @@ protected function assertTransactionDate(array $doc, string $key): void { $this->assertArrayHasKey($key, $doc, 'the date property: {$key} was not present in document'); $this->assertInstanceOf(UTCDateTime::class, $doc[$key]); - $this->assertNotEmpty($doc[$key]->toDateTime()); + $this->assertInstanceOf(DateTimeInterface::class, $doc[$key]->toDateTime()); } protected function assertDocumentVersion(array $_id, ?int $expectedValue = null, bool $hasVersion = true, ?Driver $tripod = null): void @@ -268,7 +268,7 @@ protected function assertDocumentDoesNotHaveProperty(array $_id, string $propert $doc = $this->getDocument($_id, $tripod, $fromTransactionLog); if ($doc === null) { - $this->assertNull($doc); + $this->assertNull($doc); // @phpstan-ignore method.alreadyNarrowedType return; // if document doesn't exist then it doesn't have the property, so assertion is successful } @@ -277,7 +277,7 @@ protected function assertDocumentDoesNotHaveProperty(array $_id, string $propert } /** - * @param Driver|null $tripod + * @param Collection|IDriver|null $tripod */ protected function assertDocumentExists(array $_id, $tripod = null, bool $fromTransactionLog = false): void { @@ -293,7 +293,7 @@ protected function assertDocumentHasBeenDeleted(array $_id, $tripod = null, bool { $doc = $this->getDocument($_id, $tripod, $useTransactionTripod); if ($useTransactionTripod) { - $this->assertNull($doc, sprintf('Document with _id:[%s] exists, but it should not', $_id)); + $this->assertNull($doc, 'Document with _id:[' . print_r($_id, true) . '] exists, but it should not'); } else { $this->assertTrue(is_array($doc), 'Document should be array'); $keys = array_keys($doc); diff --git a/test/unit/mongo/MongoTripodTransactionRollbackTest.php b/test/unit/mongo/MongoTripodTransactionRollbackTest.php index a59f30c3..1e48f6e4 100644 --- a/test/unit/mongo/MongoTripodTransactionRollbackTest.php +++ b/test/unit/mongo/MongoTripodTransactionRollbackTest.php @@ -144,7 +144,6 @@ public function testTransactionRollbackDuringLockAllDocuments(): void $this->assertDocumentDoesNotHaveProperty(['r' => $subjectTwo, 'c' => 'http://talisaspire.com/'], _LOCKED_FOR_TRANS_TS, $this->tripod); $transaction = $mockTripodUpdate->getTransactionLog()->getTransaction($mockTransactionId); - $this->assertNotNull($transaction); $this->assertEquals('Did not obtain locks on documents', $transaction['error']['reason']); $this->assertEquals('failed', $transaction['status']); } @@ -204,7 +203,6 @@ public function testTransactionRollbackDuringLockAllDocumentsWithEmptyOriginalCB $this->assertDocumentDoesNotHaveProperty(['r' => $subjectTwo, 'c' => 'http://talisaspire.com/'], _LOCKED_FOR_TRANS_TS, $this->tripod); $transaction = $mockTripodUpdate->getTransactionLog()->getTransaction($mockTransactionId); - $this->assertNotNull($transaction); $this->assertEquals('Did not obtain locks on documents', $transaction['error']['reason']); $this->assertEquals('failed', $transaction['status']); } @@ -403,7 +401,6 @@ public function testTransactionRollbackDuringApplyChanges(): void $this->assertDocumentDoesNotHaveProperty(['r' => $subjectTwo, 'c' => 'http://talisaspire.com/'], _LOCKED_FOR_TRANS_TS, $this->tripod); $transaction = $mockTripodUpdate->getTransactionLog()->getTransaction($mockTransactionId); - $this->assertNotNull($transaction); $this->assertEquals('Exception throw by mock test during applychangeset', $transaction['error']['reason']); $this->assertEquals('failed', $transaction['status']); } diff --git a/test/unit/mongo/TestJobBase.php b/test/unit/mongo/TestJobBase.php index 04e07f13..66599902 100644 --- a/test/unit/mongo/TestJobBase.php +++ b/test/unit/mongo/TestJobBase.php @@ -1,5 +1,6 @@ Date: Mon, 16 Mar 2026 13:40:53 +0000 Subject: [PATCH 37/56] Remove dead code branch; refactor expiry check --- src/mongo/base/DriverBase.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index d5b9ea61..c45f7039 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -199,8 +199,6 @@ protected function fetchGraph(array $query, string $type, ?Collection $collectio ]); } - $ttlExpiredResources = false; - $retries = 1; $exception = null; $cursorSuccess = false; @@ -210,10 +208,11 @@ protected function fetchGraph(array $query, string $type, ?Collection $collectio foreach ($cursor as $result) { // handle MONGO_VIEWS that have expired due to ttl. These are expired // on read (lazily) rather than on write - if ($this instanceof Views && $type == MONGO_VIEW && array_key_exists(_EXPIRES, $result['value'])) { + if ($this instanceof Views && $type == MONGO_VIEW && isset($result['value'][_EXPIRES])) { // if expires < current date, regenerate view.. + $expires = $result['value'][_EXPIRES]; $currentDate = DateUtil::getMongoDate(); - if ($result['value'][_EXPIRES]->__toString() < $currentDate) { + if ($expires < $currentDate) { // regenerate! $this->generateView($result['_id']['type'], $result['_id']['r']); } @@ -237,12 +236,6 @@ protected function fetchGraph(array $query, string $type, ?Collection $collectio throw $exception; } - if ($ttlExpiredResources) { - // generate views and retry... - $this->debugLog('One or more view had exceeded TTL was regenerated - request again...'); - $graph = $this->fetchGraph($query, $type, $collection); - } - $t->stop(); $this->timingLog($type, ['duration' => $t->result(), 'query' => $query, 'collection' => $collectionName]); if ($type == MONGO_VIEW) { From 3ddd2d68d79a1e51abdf170aed53f56a7df32ee6 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 16 Mar 2026 15:23:33 +0000 Subject: [PATCH 38/56] More method types --- src/classes/StatsD.php | 22 ++---- src/mongo/Config.php | 30 +++++--- src/mongo/IConfigInstance.php | 4 ++ src/mongo/base/CompositeBase.php | 10 +-- src/mongo/delegates/SearchDocuments.php | 35 ++-------- src/mongo/delegates/SearchIndexer.php | 9 +-- src/mongo/delegates/Tables.php | 76 +++++++-------------- src/mongo/delegates/TransactionLog.php | 28 ++++---- src/mongo/delegates/Updates.php | 64 ++++++----------- src/mongo/jobs/ApplyOperation.php | 6 +- src/mongo/jobs/DiscoverImpactedSubjects.php | 10 +-- src/mongo/providers/ISearchProvider.php | 16 +---- src/mongo/providers/MongoSearchProvider.php | 10 +-- src/mongo/util/TriplesUtil.php | 26 ++----- test/unit/mongo/MongoTripodTablesTest.php | 9 ++- 15 files changed, 123 insertions(+), 232 deletions(-) diff --git a/src/classes/StatsD.php b/src/classes/StatsD.php index b41ba7d9..53ed1bcc 100644 --- a/src/classes/StatsD.php +++ b/src/classes/StatsD.php @@ -6,9 +6,9 @@ class StatsD implements ITripodStat { - private string $host; + private string $host = ''; - private int $port; + private int $port = 0; private ?string $prefix = null; @@ -24,11 +24,7 @@ public function __construct(string $host, $port, ?string $prefix = '') $this->setPrefix($prefix); } - /** - * @param string $operation - * @param int $inc - */ - public function increment($operation, $inc = 1): void + public function increment(string $operation, int $inc = 1): void { $this->send( $this->generateStatData($operation, $inc . '|c') @@ -36,10 +32,9 @@ public function increment($operation, $inc = 1): void } /** - * @param string $operation - * @param number $duration + * @param float|int $duration */ - public function timer($operation, $duration): void + public function timer(string $operation, $duration): void { $this->send( $this->generateStatData($operation, ['1|c', $duration . '|ms']) @@ -143,13 +138,8 @@ public function setPivotValue(?string $pivotValue): void /** * Sends the stat(s) using UDP protocol. - * - * @param array $data - * @param int $sampleRate - * - * @return void */ - protected function send($data, $sampleRate = 1) + protected function send(array $data, int $sampleRate = 1): void { if (empty($this->host)) { return; diff --git a/src/mongo/Config.php b/src/mongo/Config.php index 91fdec24..ae31b295 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -12,6 +12,7 @@ use Monolog\Logger; use Psr\Log\LoggerInterface; use Tripod\Exceptions\ConfigException; +use Tripod\ISearchProvider; use Tripod\Mongo\Composites\Tables; /** @@ -32,6 +33,8 @@ class Config implements IConfigInstance /** * All defined namespaces. + * + * @var array An associative array of namespaces, keyed by prefix */ protected array $ns = []; @@ -41,7 +44,9 @@ class Config implements IConfigInstance protected array $tConfig = []; /** - * The value should be the name of a class that implement iTripodSearchProvider keyed by storename. + * The value should be the name of a class that implement ISearchProvider keyed by storename. + * + * @var array> */ protected array $searchProviderClassName = []; @@ -490,7 +495,7 @@ public function getViewSpecifications(string $storeName): array /** * This method returns a unique list of every rdf type configured in a specifications ['type'] restriction. * - * @return array of types + * @return string[] array of types */ public function getAllTypesInSpecifications(string $storeName): array { @@ -504,30 +509,38 @@ public function getAllTypesInSpecifications(string $storeName): array /** * Returns a unique list of every rdf type configured in the view spec ['type'] restriction. + * + * @return string[] */ public function getTypesInViewSpecifications(string $storeName, ?string $pod = null): array { - return array_unique($this->getSpecificationTypes($this->getViewSpecifications($storeName), $pod)); + return array_values(array_unique($this->getSpecificationTypes($this->getViewSpecifications($storeName), $pod))); } /** * Returns a unique list of every rdf type configured in the table spec ['type'] restriction. + * + * @return string[] */ public function getTypesInTableSpecifications(string $storeName, ?string $pod = null): array { - return array_unique($this->getSpecificationTypes($this->getTableSpecifications($storeName), $pod)); + return array_values(array_unique($this->getSpecificationTypes($this->getTableSpecifications($storeName), $pod))); } /** * Returns a unique list of every rdf type configured in the search doc spec ['type'] restriction. + * + * @return string[] */ public function getTypesInSearchSpecifications(string $storeName, ?string $pod = null): array { - return array_unique($this->getSpecificationTypes($this->getSearchDocumentSpecifications($storeName), $pod)); + return array_values(array_unique($this->getSpecificationTypes($this->getSearchDocumentSpecifications($storeName), $pod))); } /** * Returns an array of database names. + * + * @return string[] */ public function getDbs(): array { @@ -536,6 +549,8 @@ public function getDbs(): array /** * Returns an array of defined namespaces. + * + * @return array An associative array of namespaces, keyed by prefix */ public function getNamespaces(): array { @@ -852,9 +867,6 @@ public static function getResqueServer(): string return $resqueServer; } - /** - * @static - */ public static function getLogger(): LoggerInterface { if (self::$logger == null) { @@ -1676,6 +1688,8 @@ protected function getMongoCollection(Database $db, string $collectionName): Col // PRIVATE FUNCTIONS /** * Returns a unique list of every rdf type configured in the supplied specs' ['type'] restriction. + * + * @return string[] */ private function getSpecificationTypes(array $specifications, ?string $podName = null): array { diff --git a/src/mongo/IConfigInstance.php b/src/mongo/IConfigInstance.php index 04c70298..ee002193 100644 --- a/src/mongo/IConfigInstance.php +++ b/src/mongo/IConfigInstance.php @@ -157,11 +157,15 @@ public function getAllTypesInSpecifications(string $storeName): array; /** * Returns an array of database names. + * + * @return string[] */ public function getDbs(): array; /** * Returns an array of defined namespaces. + * + * @return array */ public function getNamespaces(): array; diff --git a/src/mongo/base/CompositeBase.php b/src/mongo/base/CompositeBase.php index 65e62e9d..eeac4d11 100644 --- a/src/mongo/base/CompositeBase.php +++ b/src/mongo/base/CompositeBase.php @@ -139,10 +139,8 @@ abstract public function getSpecification(string $storeName, string $specId): ?a /** * Test if the a particular type appears in the array of types associated with a particular spec and that the changeset * includes rdf:type (or is empty, meaning addition or deletion vs. update). - * - * @return bool */ - protected function checkIfTypeShouldTriggerOperation(?string $rdfType, array $validTypes, array $subjectPredicates) + protected function checkIfTypeShouldTriggerOperation(string $rdfType, array $validTypes, array $subjectPredicates): bool { // We don't know if this is an alias or a fqURI, nor what is in the valid types, necessarily $types = [$rdfType]; @@ -191,12 +189,8 @@ protected function queueApplyJob(array $subjects, ?string $queueName, array $job /** * For mocking. - * - * @param string $storeName - * - * @return JobGroup */ - protected function getJobGroup($storeName) + protected function getJobGroup(string $storeName): JobGroup { return new JobGroup($storeName); } diff --git a/src/mongo/delegates/SearchDocuments.php b/src/mongo/delegates/SearchDocuments.php index a77754a6..c606bfcf 100644 --- a/src/mongo/delegates/SearchDocuments.php +++ b/src/mongo/delegates/SearchDocuments.php @@ -15,12 +15,9 @@ class SearchDocuments extends DriverBase * Construct accepts actual objects rather than strings as this class is a delegate of * Tripod and should inherit connections set up there. * - * @param string $storeName - * @param string $defaultContext - * @param ITripodStat|null $stat - * @param string $readPreference + * @param int|string $readPreference */ - public function __construct($storeName, Collection $collection, $defaultContext, $stat = null, $readPreference = ReadPreference::RP_PRIMARY) + public function __construct(string $storeName, Collection $collection, string $defaultContext, ?ITripodStat $stat = null, $readPreference = ReadPreference::RP_PRIMARY) { $this->labeller = new Labeller(); $this->storeName = $storeName; @@ -119,22 +116,8 @@ public function generateSearchDocumentBasedOnSpecId(string $specId, ?string $res return $generatedDocument; } - /** - * @param string $resource - * @param string $context - * - * @throws \Exception - */ - public function generateSearchDocumentsBasedOnRdfTypes(array $rdfTypes, $resource, $context): array + public function generateSearchDocumentsBasedOnRdfTypes(array $rdfTypes, string $resource, string $context): array { - if (empty($resource)) { - throw new \Exception('Resource must be specified'); - } - - if (empty($context)) { - throw new \Exception('Context must be specified'); - } - // this is what is returned $generatedSearchDocuments = []; @@ -164,12 +147,7 @@ public function getSearchCollectionName(): string return SEARCH_INDEX_COLLECTION; } - /** - * @param array $joins - * @param array $target - * @param string $from - */ - protected function doJoin(array $source, $joins, &$target, $from) + protected function doJoin(array $source, array $joins, array &$target, string $from) { // expand sequences before proceeding $this->expandSequence($joins, $source); @@ -223,10 +201,7 @@ protected function doJoin(array $source, $joins, &$target, $from) } } - /** - * @param bool $isIndex - */ - protected function addFields(array $source, array $fieldsOrIndices, array &$target, $isIndex = false) + protected function addFields(array $source, array $fieldsOrIndices, array &$target, bool $isIndex = false) { foreach ($fieldsOrIndices as $f) { if (isset($f['predicates'])) { diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 8c8308e2..5339a508 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -77,11 +77,9 @@ public function getSpecification(string $storeName, string $specId): ?array /** * Removes all existing documents for the supplied resource and regenerate the search documents. * - * @param string $resourceUri - * @param string $context * @param array|string|null $specType */ - public function generateAndIndexSearchDocuments($resourceUri, $context, string $podName, $specType = []): void + public function generateAndIndexSearchDocuments(string $resourceUri, string $context, string $podName, $specType = []): void { $mongoCollection = $this->config->getCollectionForCBD($this->storeName, $podName); @@ -256,10 +254,7 @@ protected function getSearchProvider(): ?ISearchProvider return $this->searchProvider; } - /** - * @param string $context - */ - protected function getSearchDocumentGenerator(Collection $collection, $context): SearchDocuments + protected function getSearchDocumentGenerator(Collection $collection, string $context): SearchDocuments { return new SearchDocuments($this->storeName, $collection, $context, $this->tripod->getStat()); } diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index 00d79e26..215ab3a7 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -67,15 +67,13 @@ class Tables extends CompositeBase * Construct accepts actual objects rather than strings as this class is a delegate of * Tripod and should inherit connections set up there. * - * @param ITripodStat|null $stat - * @param string $readPreference - * todo: MongoCollection -> podName + * @param int|string $readPreference */ public function __construct( string $storeName, Collection $collection, ?string $defaultContext, - $stat = null, + ?ITripodStat $stat = null, $readPreference = ReadPreference::RP_PRIMARY ) { $this->labeller = new Labeller(); @@ -208,8 +206,6 @@ public function getOperationType(): string /** * Query the tables collection and return the results. * - * @param int $offset - * @param int $limit * @param array $options Table query options * @param array $filter * @@ -219,8 +215,8 @@ public function getTableRows( string $tableSpecId, array $filter = [], array $sortBy = [], - $offset = 0, - $limit = 10, + int $offset = 0, + int $limit = 10, array $options = [] ): array { $t = new Timer(); @@ -245,8 +241,8 @@ public function getTableRows( $findOptions = []; if (!empty($limit)) { - $findOptions['skip'] = (int) $offset; - $findOptions['limit'] = (int) $limit; + $findOptions['skip'] = $offset; + $findOptions['limit'] = $limit; } $findOptions['sort'] = $sortBy; @@ -347,13 +343,8 @@ public function deleteTableRowsByTableId(string $tableId, $timestamp = null): in /** * This method finds all the table specs for the given $rdfType and generates the table rows for the $subject one by one. - * - * @param string $rdfType - * @param string|null $subject - * @param string|null $context - * @param array $specTypes */ - public function generateTableRowsForType($rdfType, $subject = null, $context = null, $specTypes = []): void + public function generateTableRowsForType(string $rdfType, string $subject, string $context, array $specTypes = []): void { $rdfType = $this->labeller->qname_to_alias($rdfType); $rdfTypeAlias = $this->labeller->uri_to_alias($rdfType); @@ -394,11 +385,9 @@ public function generateTableRowsForType($rdfType, $subject = null, $context = n } /** - * @param string|null $resource - * @param string|null $context * @param string|null $queueName Queue for background bulk generation */ - public function generateTableRows(string $tableType, $resource = null, $context = null, $queueName = null): ?array + public function generateTableRows(string $tableType, ?string $resource = null, ?string $context = null, ?string $queueName = null): ?array { $t = new Timer(); $t->start(); @@ -541,7 +530,7 @@ public function count(string $tableSpec, array $filters = []) * @param string|null $context Optional context * @param array|string|null $specType Optional table type or array of table types to delete from */ - protected function deleteTableRowsForResource(?string $resource, $context = null, $specType = null) + protected function deleteTableRowsForResource(string $resource, ?string $context = null, $specType = null) { $t = new Timer(); $t->start(); @@ -575,11 +564,8 @@ protected function deleteTableRowsForResource(?string $resource, $context = null /** * This method handles invalidation and regeneration of table rows based on impact index, before delegating to * generateTableRowsForType() for re-generation of any table rows for the $resource. - * - * @param string|null $context - * @param array $specTypes */ - protected function generateTableRowsForResource(?string $resource, $context = null, $specTypes = []) + protected function generateTableRowsForResource(string $resource, ?string $context = null, array $specTypes = []) { $resourceAlias = $this->labeller->uri_to_alias($resource); $contextAlias = $this->getContextAlias($context); @@ -878,7 +864,7 @@ protected function generateConditionalValue(array $conditionalSpec, array &$dest * * @return mixed */ - protected function rewriteVariableValue($value, array &$dest, $setType = null) + protected function rewriteVariableValue($value, array &$dest, ?string $setType = null) { if (is_string($value)) { if (strpos($value, '$') === 0) { @@ -920,12 +906,11 @@ protected function isFunction($value): bool } /** - * @param mixed $value - * @param string|null $type + * @param mixed $value * * @return mixed */ - protected function castValueType($value, $type = null) + protected function castValueType($value, ?string $type = null) { // If value is a UTCDateTime, turn into a DateTime object in order to perform comparison if ($value instanceof UTCDateTime) { @@ -956,24 +941,22 @@ protected function castValueType($value, $type = null) } /** - * @param mixed $left The left value of the condition - * @param string $operator The comparison operator - * @param mixed $right The right value of the condition - * - * @return bool + * @param mixed $left The left value of the condition + * @param string|null $operator The comparison operator + * @param mixed|null $right The right value of the condition * * @throws \InvalidArgumentException */ - protected function doConditional($left, $operator, $right) + protected function doConditional($left, ?string $operator, $right): bool { - if ((!empty($operator)) && !in_array($operator, self::$conditionalOperators)) { - throw new \InvalidArgumentException('Invalid conditional operator'); - } - if (!$operator) { return (bool) $left; } + if (!in_array($operator, self::$conditionalOperators)) { + throw new \InvalidArgumentException('Invalid conditional operator'); + } + $result = false; switch ($operator) { @@ -1166,13 +1149,7 @@ protected function getPredicateFunctions($array): array return $predicateFunctions; } - /** - * @param array $joins - * @param array $dest - * @param string $from - * @param string $contextAlias - */ - protected function doJoins(array $source, $joins, &$dest, $from, $contextAlias) + protected function doJoins(array $source, array $joins, array &$dest, string $from, string $contextAlias) { $this->expandSequence($joins, $source); foreach ($joins as $predicate => $ruleset) { @@ -1270,10 +1247,8 @@ protected function doCounts(array $source, array $countSpec, array &$dest): void /** * Test if the a particular type appears in the array of types associated with a particular spec and that the changeset * includes rdf:type (or is empty, meaning addition or deletion vs. update). - * - * @param string $rdfType */ - protected function checkIfTypeShouldTriggerOperation($rdfType, array $validTypes, array $subjectPredicates): bool + protected function checkIfTypeShouldTriggerOperation(string $rdfType, array $validTypes, array $subjectPredicates): bool { // We don't know if this is an alias or a fqURI, nor what is in the valid types, necessarily $types = [$rdfType]; @@ -1380,14 +1355,13 @@ private function strtolower($value): string /** * Apply a regex to the RDF property value defined in $value. * - * @param mixed $regex * @param array $value * - * @return int + * @return false|int * * @throws \Tripod\Exceptions\Exception */ - private function applyRegexToValue($regex, array $value) + private function applyRegexToValue(string $regex, array $value) { if (isset($value[VALUE_URI]) || isset($value[VALUE_LITERAL])) { $v = $value[VALUE_URI] ?: $value[VALUE_LITERAL]; diff --git a/src/mongo/delegates/TransactionLog.php b/src/mongo/delegates/TransactionLog.php index a08b9d37..da037e4d 100644 --- a/src/mongo/delegates/TransactionLog.php +++ b/src/mongo/delegates/TransactionLog.php @@ -32,15 +32,15 @@ public function __construct() } /** - * @param string $transaction_id - the id you wish to assign to the new transaction - * @param array $changes - an array serialization of the changeset to be applied - * @param array $originalCBDs - an array of the serialized CBDs - * @param string $storeName - the name of the database the changes are being applied to - * @param string $podName - the name of the collection, in the database, the changes are being applied to + * @param string $transaction_id - the id you wish to assign to the new transaction + * @param array $changes - an array serialization of the changeset to be applied + * @param array|null $originalCBDs - an array of the serialized CBDs + * @param string $storeName - the name of the database the changes are being applied to + * @param string $podName - the name of the collection, in the database, the changes are being applied to * * @throws \Tripod\Exceptions\Exception */ - public function createNewTransaction($transaction_id, $changes, $originalCBDs, $storeName, $podName): void + public function createNewTransaction(string $transaction_id, array $changes, ?array $originalCBDs, string $storeName, string $podName): void { $transaction = [ '_id' => $transaction_id, @@ -68,9 +68,9 @@ public function createNewTransaction($transaction_id, $changes, $originalCBDs, $ * If you passed in an Exception, the exception is logged in the transaction log. * * @param string $transaction_id the id of the transaction you wish to cancel - * @param \Exception $error pass in the exception you wish to log + * @param \Throwable $error pass in the exception you wish to log */ - public function cancelTransaction($transaction_id, ?\Exception $error = null): void + public function cancelTransaction(string $transaction_id, ?\Throwable $error = null): void { $params = ['status' => 'cancelling']; if ($error != null) { @@ -89,9 +89,9 @@ public function cancelTransaction($transaction_id, ?\Exception $error = null): v * If you passed in an Exception, the exception is logged in the transaction log. * * @param string $transaction_id the id of the transaction you wish to set as failed - * @param \Exception $error exception you wish to log + * @param \Throwable $error exception you wish to log */ - public function failTransaction($transaction_id, ?\Exception $error = null): void + public function failTransaction(string $transaction_id, ?\Throwable $error = null): void { $params = ['status' => 'failed', 'failedTime' => DateUtil::getMongoDate()]; if ($error != null) { @@ -111,7 +111,7 @@ public function failTransaction($transaction_id, ?\Exception $error = null): voi * @param string $transaction_id - the id of the transaction you want to mark as completed * @param array $newCBDs array of CBD's that represent the after state for each modified entity */ - public function completeTransaction($transaction_id, array $newCBDs): void + public function completeTransaction(string $transaction_id, array $newCBDs): void { $this->updateTransaction( ['_id' => $transaction_id], @@ -127,7 +127,7 @@ public function completeTransaction($transaction_id, array $newCBDs): void * * @return array representing the transaction document */ - public function getTransaction($transaction_id) + public function getTransaction(string $transaction_id): array { return $this->transaction_collection->findOne(['_id' => $transaction_id]); } @@ -175,7 +175,7 @@ public function getCompletedTransactions(?string $storeName = null, ?string $pod /** * @return int Total number of transactions in the transaction log */ - public function getTotalTransactionCount() + public function getTotalTransactionCount(): int { return $this->transaction_collection->count([]); } @@ -188,7 +188,7 @@ public function getTotalTransactionCount() * * @codeCoverageIgnore */ - public function getCompletedTransactionCount(?string $storeName = null, ?string $podName = null) + public function getCompletedTransactionCount(?string $storeName = null, ?string $podName = null): int { if (!empty($storeName) && !empty($podName)) { return $this->transaction_collection->count(['status' => 'completed', 'dbName' => $storeName, 'collectionName' => $podName]); diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index ebb3b3e7..0e1ef301 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -56,10 +56,7 @@ class Updates extends DriverBase */ private array $saveChangesHooks = []; - /** - * @param array $opts - */ - public function __construct(Driver $tripod, $opts = []) + public function __construct(Driver $tripod, array $opts = []) { $this->tripod = $tripod; $this->storeName = $tripod->getStoreName(); @@ -117,16 +114,13 @@ public function __construct(Driver $tripod, $opts = []) /** * Create and apply a changeset which is the delta between $oldGraph and $newGraph. * - * @param string|null $context - * @param string|null $description - * * @throws \Exception */ public function saveChanges( ExtendedGraph $oldGraph, ExtendedGraph $newGraph, - $context = null, - $description = null + ?string $context = null, + ?string $description = null ): bool { $this->applyHooks($this::HOOK_FN_PRE, $this->saveChangesHooks, [ 'pod' => $this->getPodName(), @@ -201,11 +195,8 @@ public function saveChanges( // ////// LOCKS \\\\\\\\ /** * Get locked documents for a date range or all documents if no date range is given. - * - * @param string $fromDateTime - * @param string $tillDateTime */ - public function getLockedDocuments($fromDateTime = null, $tillDateTime = null): array + public function getLockedDocuments(?string $fromDateTime = null, ?string $tillDateTime = null): array { $query = []; if (!empty($fromDateTime) || !empty($tillDateTime)) { @@ -237,11 +228,9 @@ public function getLockedDocuments($fromDateTime = null, $tillDateTime = null): /** * Remove locks that are there forever, creates a audit entry to keep track who and why removed these locks. * - * @param string $reason - * * @throws \Exception If something goes wrong when unlocking documents, or creating audit entries */ - public function removeInertLocks(string $transaction_id, $reason): bool + public function removeInertLocks(string $transaction_id, string $reason): bool { $query = [_LOCKED_FOR_TRANS => $transaction_id]; $docs = $this->getLocksCollection()->find($query); @@ -330,7 +319,7 @@ public function removeInertLocks(string $transaction_id, $reason): bool * @param string|null $fromDate only transactions after this specified date. This must be a datetime string i.e. '2010-01-15 00:00:00' * @param string|null $toDate only transactions before this specified date. This must be a datetime string i.e. '2010-01-15 00:00:00' */ - public function replayTransactionLog($fromDate = null, $toDate = null): bool + public function replayTransactionLog(?string $fromDate = null, ?string $toDate = null): bool { $cursor = $this->getTransactionLog()->getCompletedTransactions($this->storeName, $this->podName, $fromDate, $toDate); foreach ($cursor as $result) { @@ -367,7 +356,7 @@ public function registerSaveChangesEventHook(IEventHook $hook): void * Change the read preferences to RP_PRIMARY * Used for a write operation. */ - protected function setReadPreferenceToPrimary() + protected function setReadPreferenceToPrimary(): void { // Set db preference /** @var ReadPreference $dbReadPref */ @@ -396,7 +385,7 @@ protected function setReadPreferenceToPrimary() /** * Reset the original read preference after changing with setReadPreferenceToPrimary. */ - protected function resetOriginalReadPreference() + protected function resetOriginalReadPreference(): void { $dbReadPref = $this->db->getReadPreference(); if ($this->originalDbReadPreference !== $dbReadPref->getMode()) { @@ -424,7 +413,7 @@ protected function resetOriginalReadPreference() * * @throws CardinalityException */ - protected function validateGraphCardinality(ExtendedGraph $graph) + protected function validateGraphCardinality(ExtendedGraph $graph): void { $config = $this->getConfigInstance(); $cardinality = $config->getCardinality($this->getStoreName(), $this->getPodName()); @@ -467,7 +456,7 @@ protected function validateGraphCardinality(ExtendedGraph $graph) * * @throws Exception */ - protected function storeChanges(ChangeSet $cs, $contextAlias) + protected function storeChanges(ChangeSet $cs, $contextAlias): array { $t = new Timer(); $t->start(); @@ -536,12 +525,12 @@ protected function storeChanges(ChangeSet $cs, $contextAlias) } /** - * @param string $transaction_id id of the transaction - * @param array $originalCBDs containing the original CBDS + * @param string $transaction_id id of the transaction + * @param array|null $originalCBDs containing the original CBDS * - * @throws \Exception + * @throws \Throwable */ - protected function rollbackTransaction(string $transaction_id, $originalCBDs, \Exception $exception): bool + protected function rollbackTransaction(string $transaction_id, ?array $originalCBDs, \Throwable $exception): bool { // set transaction to cancelling $this->getTransactionLog()->cancelTransaction($transaction_id, $exception); @@ -603,14 +592,11 @@ protected function getUniqId(): string /** * Adds/updates/deletes the graph in the database. * - * @param string $contextAlias - * @param string $transaction_id - * * @return array * * @throws \Exception */ - protected function applyChangeSet(ChangeSet $cs, array $originalCBDs, $contextAlias, $transaction_id) + protected function applyChangeSet(ChangeSet $cs, array $originalCBDs, string $contextAlias, string $transaction_id): array { $subjectsAndPredicatesOfChange = []; if (in_array($this->getCollection()->getCollectionName(), $this->getConfigInstance()->getPods($this->getStoreName()))) { @@ -777,12 +763,9 @@ protected function subjectsAndPredicatesOfChangeUrisToAliases(array $subjectsAnd /** * Given a set of CBD's return the CBD that matches the Subject of Change. * - * @param string $subjectOfChange - * @param string $contextAlias - * * @return array|null the document from the collection of $cbds that matches the subject of change */ - protected function getDocumentForUpdate($subjectOfChange, $contextAlias, array $cbds) + protected function getDocumentForUpdate(string $subjectOfChange, string $contextAlias, array $cbds): ?array { foreach ($cbds as $c) { if ($c[_ID_KEY] == [_ID_RESOURCE => $this->labeller->uri_to_alias($subjectOfChange), _ID_CONTEXT => $contextAlias]) { @@ -796,7 +779,7 @@ protected function getDocumentForUpdate($subjectOfChange, $contextAlias, array $ /** * Processes each subject synchronously. */ - protected function processSyncOperations(array $subjectsAndPredicatesOfChange, string $contextAlias) + protected function processSyncOperations(array $subjectsAndPredicatesOfChange, string $contextAlias): void { foreach ($this->getSyncOperations() as $op) { /** @var IComposite $composite */ @@ -830,10 +813,8 @@ protected function processSyncOperations(array $subjectsAndPredicatesOfChange, s /** * Adds the operations to the queue to be performed asynchronously. - * - * @param string $contextAlias */ - protected function queueASyncOperations(array $subjectsAndPredicatesOfChange, $contextAlias) + protected function queueASyncOperations(array $subjectsAndPredicatesOfChange, string $contextAlias): void { $operations = $this->getAsyncOperations(); if ($operations !== []) { @@ -860,10 +841,8 @@ protected function queueASyncOperations(array $subjectsAndPredicatesOfChange, $c /** * For mocking. - * - * @return DiscoverImpactedSubjects */ - protected function getDiscoverImpactedSubjects() + protected function getDiscoverImpactedSubjects(): DiscoverImpactedSubjects { if ($this->discoverImpactedSubjects === null) { $this->discoverImpactedSubjects = new DiscoverImpactedSubjects(); @@ -877,13 +856,12 @@ protected function getDiscoverImpactedSubjects() * * @param array $subjectsOfChange array of the subjects that are part of this transaction * @param string $transaction_id id for this transaction - * @param string $contextAlias * * @return array|null returns an array of CBDs, each CBD is the version at the time at which the lock was attained * * @throws \Exception */ - protected function lockAllDocuments($subjectsOfChange, $transaction_id, $contextAlias): ?array + protected function lockAllDocuments(array $subjectsOfChange, string $transaction_id, string $contextAlias): ?array { for ($retry = 1; $retry <= $this->retriesToGetLock; $retry++) { $originalCBDs = []; @@ -1085,7 +1063,7 @@ protected function getMongoDate(): UTCDateTime * * @param array $transaction */ - protected function applyTransaction(array $transaction) + protected function applyTransaction(array $transaction): void { $changes = $transaction['changes']; $newCBDs = $transaction['newCBDs']; diff --git a/src/mongo/jobs/ApplyOperation.php b/src/mongo/jobs/ApplyOperation.php index 94689072..b367fd34 100644 --- a/src/mongo/jobs/ApplyOperation.php +++ b/src/mongo/jobs/ApplyOperation.php @@ -89,10 +89,8 @@ public function perform(): void /** * @param ImpactedSubject[] $subjects - * @param string|null $queueName - * @param array $otherData */ - public function createJob(array $subjects, $queueName = null, $otherData = []): void + public function createJob(array $subjects, ?string $queueName = null, array $otherData = []): void { $configInstance = $this->getConfigInstance(); if (!$queueName) { @@ -154,7 +152,7 @@ protected function createImpactedSubject(array $args): ImpactedSubject * @param string $storeName Tripod store (database) name * @param ObjectId|string $trackingKey JobGroup ID */ - protected function getJobGroup($storeName, $trackingKey): JobGroup + protected function getJobGroup(string $storeName, $trackingKey): JobGroup { return new JobGroup($storeName, $trackingKey); } diff --git a/src/mongo/jobs/DiscoverImpactedSubjects.php b/src/mongo/jobs/DiscoverImpactedSubjects.php index 496661f8..1bacc38b 100644 --- a/src/mongo/jobs/DiscoverImpactedSubjects.php +++ b/src/mongo/jobs/DiscoverImpactedSubjects.php @@ -156,10 +156,7 @@ public function perform(): void } } - /** - * @param string|null $queueName - */ - public function createJob(array $data, $queueName = null): void + public function createJob(array $data, ?string $queueName = null): void { $configInstance = $this->getConfigInstance(); if (!$queueName) { @@ -187,10 +184,7 @@ protected function getStatFailureIncrementKey(): string return MONGO_QUEUE_DISCOVER_FAIL; } - /** - * @param string $queueName - */ - protected function addSubjectToQueue(ImpactedSubject $subject, $queueName) + protected function addSubjectToQueue(ImpactedSubject $subject, string $queueName): void { if (!array_key_exists($queueName, $this->subjectsGroupedByQueue)) { $this->subjectsGroupedByQueue[$queueName] = []; diff --git a/src/mongo/providers/ISearchProvider.php b/src/mongo/providers/ISearchProvider.php index ffa653ad..2b063adb 100644 --- a/src/mongo/providers/ISearchProvider.php +++ b/src/mongo/providers/ISearchProvider.php @@ -14,37 +14,27 @@ interface ISearchProvider * * @param array $document the document to index * - * @return mixed - * * @throws SearchException if there was an error indexing the document */ - public function indexDocument($document); + public function indexDocument(array $document): void; /** * Removes a single document from the search index based on the specified resource and context and spec id. * If spec id is not specified this method will delete all search documents that match the resource and context. * - * @param string $resource - * @param string $context * @param array|string|null $specId * - * @return mixed - * * @throws SearchException if there was an error removing the document */ - public function deleteDocument($resource, $context, $specId = []); + public function deleteDocument(string $resource, string $context, $specId = []): void; /** * Returns the ids of all documents that contain and impact index entry * matching the resource and context specified. * - * @param string $context - * - * @internal param $resource - * * @return array the ids of search documents that had matching entries in their impact index */ - public function findImpactedDocuments(array $resourcesAndPredicates, $context); + public function findImpactedDocuments(array $resourcesAndPredicates, string $context): array; /** * Executes the query and returns a structure representing a search results. diff --git a/src/mongo/providers/MongoSearchProvider.php b/src/mongo/providers/MongoSearchProvider.php index c38b6d71..3f3567ba 100644 --- a/src/mongo/providers/MongoSearchProvider.php +++ b/src/mongo/providers/MongoSearchProvider.php @@ -216,7 +216,7 @@ public function __construct(Driver $tripod) * * @throws SearchException if there was an error indexing the document */ - public function indexDocument($document): void + public function indexDocument(array $document): void { if (isset($document['_id']['type'])) { $collection = $this->config->getCollectionForSearchDocument($this->storeName, $document['_id']['type']); @@ -238,13 +238,11 @@ public function indexDocument($document): void * Removes a single document from the search index based on the specified resource and context and spec id. * If spec id is not specified this method will delete all search documents that match the resource and context. * - * @param string $resource - * @param string $context * @param array|string|null $specId * * @throws SearchException if there was an error removing the document */ - public function deleteDocument($resource, $context, $specId = []): void + public function deleteDocument(string $resource, string $context, $specId = []): void { $query = [_ID_KEY . '.' . _ID_RESOURCE => $this->labeller->uri_to_alias($resource), _ID_KEY . '.' . _ID_CONTEXT => $context]; @@ -283,11 +281,9 @@ public function deleteDocument($resource, $context, $specId = []): void * Returns the ids of all documents that contain and impact index entry * matching the resource and context specified. * - * @param string $context - * * @return array the ids of search documents that had matching entries in their impact index */ - public function findImpactedDocuments(array $resourcesAndPredicates, $context): array + public function findImpactedDocuments(array $resourcesAndPredicates, string $context): array { $contextAlias = $this->labeller->uri_to_alias($context); diff --git a/src/mongo/util/TriplesUtil.php b/src/mongo/util/TriplesUtil.php index 5122e9df..406ee1a9 100644 --- a/src/mongo/util/TriplesUtil.php +++ b/src/mongo/util/TriplesUtil.php @@ -67,11 +67,8 @@ public function loadTriplesAbout(string $subject, array $triples, string $storeN /** * Add $triples about a given $subject to Mongo. Only $triples with subject matching $subject will be added, others will be ignored. * Make them quads with a $context. - * - * @param string $subject - * @param string|null $context */ - public function bsonizeTriplesAbout($subject, array $triples, $context = null): ?array + public function bsonizeTriplesAbout(string $subject, array $triples, ?string $context = null): ?array { $context = ($context == null) ? Config::getInstance()->getDefaultContextAlias() : $this->labeller->uri_to_alias($context); $graph = new MongoGraph(); @@ -135,10 +132,7 @@ public function extractMissingObjectNs(array $triples): array return array_unique($missingNs); } - /** - * @param string $ns - */ - public function suggestPrefix($ns): string + public function suggestPrefix(string $ns): string { $parts = preg_split('/[\/#]/', $ns); for ($i = count($parts) - 1; $i >= 0; $i--) { @@ -150,10 +144,7 @@ public function suggestPrefix($ns): string return 'unknown' . uniqid(); } - /** - * @param string $subject - */ - public function getTArrayAbout($subject, array $triples, ?string $context): ?array + public function getTArrayAbout(string $subject, array $triples, ?string $context): ?array { $graph = new MongoGraph(); foreach ($triples as $triple) { @@ -175,11 +166,9 @@ public function getTArrayAbout($subject, array $triples, ?string $context): ?arr } /** - * @param string $cbdSubject - * * @throws \Exception */ - protected function saveCBD($cbdSubject, MongoGraph $cbdGraph, Collection $collection, ?string $context) + protected function saveCBD(string $cbdSubject, MongoGraph $cbdGraph, Collection $collection, ?string $context) { $cbdSubject = $this->labeller->uri_to_alias($cbdSubject); if ($cbdGraph == null || $cbdGraph->is_empty()) { @@ -208,12 +197,9 @@ protected function saveCBD($cbdSubject, MongoGraph $cbdGraph, Collection $collec } } - /** - * @return mixed - */ - private function isUri(string $object) + private function isUri(string $object): bool { - return filter_var($object, FILTER_VALIDATE_URL); + return filter_var($object, FILTER_VALIDATE_URL) !== false; } /** diff --git a/test/unit/mongo/MongoTripodTablesTest.php b/test/unit/mongo/MongoTripodTablesTest.php index d0155938..4467da83 100644 --- a/test/unit/mongo/MongoTripodTablesTest.php +++ b/test/unit/mongo/MongoTripodTablesTest.php @@ -428,10 +428,13 @@ public function testGenerateTableRowsForResourcesOfTypeWithNamespace(): void ->onlyMethods(['generateTableRows']) ->setConstructorArgs([$this->tripod->getStoreName(), $this->getTripodCollection($this->tripod), 'http://talisaspire.com/']) ->getMock(); - $mockTripodTables->expects($this->atLeastOnce())->method('generateTableRows')->willReturn(['ok' => true]); + $mockTripodTables->expects($this->atLeastOnce()) + ->method('generateTableRows') + ->with('t_work2', 'http://example.com/1', 'http://talisaspire.com/', null) + ->willReturn(['ok' => true]); // check where referred to as acorn:Work2 in spec... - $mockTripodTables->generateTableRowsForType('http://talisaspire.com/schema#Work2'); + $mockTripodTables->generateTableRowsForType('http://talisaspire.com/schema#Work2', 'http://example.com/1', 'http://talisaspire.com/'); $mockTripodTables = $this->getMockBuilder(Tripod\Mongo\Composites\Tables::class) ->onlyMethods(['generateTableRows']) @@ -440,7 +443,7 @@ public function testGenerateTableRowsForResourcesOfTypeWithNamespace(): void $mockTripodTables->expects($this->atLeastOnce())->method('generateTableRows')->willReturn(['ok' => true]); // check where referred to as http://talisaspire.com/schema#Resource in spec... - $mockTripodTables->generateTableRowsForType('acorn:Resource'); + $mockTripodTables->generateTableRowsForType('acorn:Resource', 'http://example.com/2', 'http://talisaspire.com/'); } /** From 58cb4d1aaf2157e0e5c96c69c779009442358cbc Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 16 Mar 2026 21:56:45 +0000 Subject: [PATCH 39/56] Revert covariance --- src/ITripodStat.php | 5 ++++- src/classes/StatsD.php | 5 ++++- src/mongo/Driver.php | 30 +++++++++++++++++++++++------- src/mongo/base/DriverBase.php | 5 ++++- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/ITripodStat.php b/src/ITripodStat.php index 007a0c8f..8afa2f1d 100644 --- a/src/ITripodStat.php +++ b/src/ITripodStat.php @@ -18,5 +18,8 @@ public function timer(string $operation, $duration): void; public function getConfig(): array; - public static function createFromConfig(array $config): ITripodStat; + /** + * @return self + */ + public static function createFromConfig(array $config); } diff --git a/src/classes/StatsD.php b/src/classes/StatsD.php index 53ed1bcc..1ca10411 100644 --- a/src/classes/StatsD.php +++ b/src/classes/StatsD.php @@ -66,7 +66,10 @@ public function getConfig(): array ]; } - public static function createFromConfig(array $config): self + /** + * @return self + */ + public static function createFromConfig(array $config) { if (isset($config['config'])) { $config = $config['config']; diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index 48a6869b..2e8e5c77 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -107,8 +107,10 @@ public function __construct(string $podName, string $storeName, array $opts = [] * * @param string $resource uri resource you'd like to describe * @param string|null $context string uri of the context, or named graph, you'd like to describe from + * + * @return MongoGraph */ - public function describeResource(string $resource, ?string $context = null): MongoGraph + public function describeResource(string $resource, ?string $context = null): ExtendedGraph { $resource = $this->labeller->uri_to_alias($resource); $query = [ @@ -123,8 +125,10 @@ public function describeResource(string $resource, ?string $context = null): Mon /** * Pass subjects as to $resources and have mongo return a DESCRIBE etc. + * + * @return MongoGraph */ - public function describeResources(array $resources, ?string $context = null): MongoGraph + public function describeResources(array $resources, ?string $context = null): ExtendedGraph { $ids = []; foreach ($resources as $resource) { @@ -140,20 +144,28 @@ public function describeResources(array $resources, ?string $context = null): Mo return $this->fetchGraph($query, MONGO_MULTIDESCRIBE); } - public function getViewForResource(?string $resource, string $viewType): MongoGraph + /** + * @return MongoGraph + */ + public function getViewForResource(?string $resource, string $viewType): ExtendedGraph { return $this->getTripodViews()->getViewForResource($resource, $viewType); } /** * @param string[] $resources + * + * @return MongoGraph */ - public function getViewForResources(array $resources, string $viewType): MongoGraph + public function getViewForResources(array $resources, string $viewType): ExtendedGraph { return $this->getTripodViews()->getViewForResources($resources, $viewType); } - public function getViews(array $filter, string $viewType): MongoGraph + /** + * @return MongoGraph + */ + public function getViews(array $filter, string $viewType): ExtendedGraph { return $this->getTripodViews()->getViews($filter, $viewType); } @@ -440,8 +452,10 @@ public function select(array $query, array $fields, ?array $sortBy = null, ?int * Returns a graph as the result of $query. Useful replacement for DESCRIBE ... WHERE. * * @deprecated use getGraph + * + * @return MongoGraph */ - public function describe(array $query): MongoGraph + public function describe(array $query): ExtendedGraph { return $this->fetchGraph($query, MONGO_DESCRIBE_WITH_CONDITION); } @@ -454,8 +468,10 @@ public function describe(array $query): MongoGraph * * @param array $filter conditions to filter by * @param array $includeProperties only include these predicates, empty array means return all predicates + * + * @return MongoGraph */ - public function graph(array $filter, array $includeProperties = []): MongoGraph + public function graph(array $filter, array $includeProperties = []): ExtendedGraph { return $this->fetchGraph($filter, MONGO_GET_GRAPH, null, $includeProperties); } diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index c45f7039..2086eaf2 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -409,7 +409,10 @@ public static function getInstance(): self return self::$instance; } - public static function createFromConfig(array $config = []): self + /** + * @return self + */ + public static function createFromConfig(array $config = []) { return self::getInstance(); } From 3c0a04039366b383bd0a056df11e5f81519b84a3 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 16 Mar 2026 22:44:27 +0000 Subject: [PATCH 40/56] Labeller corrections --- src/classes/Labeller.php | 45 +++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/classes/Labeller.php b/src/classes/Labeller.php index 4d399c80..421c04ed 100644 --- a/src/classes/Labeller.php +++ b/src/classes/Labeller.php @@ -12,6 +12,9 @@ */ class Labeller { + /** + * @var array> + */ public array $_labels = [ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_1' => ['first', 'first', 'is first member of'], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_2' => ['second', 'second', 'is second member of'], @@ -235,8 +238,14 @@ class Labeller 'http://purl.org/goodrelations/v1#hasGTIN-14' => ['GTIN-14'], ]; + /** + * @var string[] + */ protected array $_label_properties = []; + /** + * @var array + */ protected array $_ns = [ 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#', @@ -340,11 +349,12 @@ public function get_prefix(string $ns): string return $prefix; } + /** @var non-empty-list $parts */ $parts = preg_split('/[\/#]/', $ns); for ($i = count($parts) - 1; $i >= 0; $i--) { if ( preg_match('~^[a-zA-Z][a-zA-Z0-9\-]+$~', $parts[$i]) - && !array_key_exists($parts[$i], $this->_ns) + && !isset($this->_ns[$parts[$i]]) && $parts[$i] != 'schema' && $parts[$i] != 'ontology' && $parts[$i] != 'vocab' @@ -361,7 +371,7 @@ public function get_prefix(string $ns): string } $index = 0; - while (array_key_exists('ns' . $index, $this->_ns)) { + while (isset($this->_ns['ns' . $index])) { $index++; } @@ -385,54 +395,54 @@ public function get_label(string $uri, ?ExtendedGraph $g = null, bool $capitaliz { if ($g instanceof ExtendedGraph) { $label = $g->get_first_literal($uri, 'http://www.w3.org/2004/02/skos/core#prefLabel', '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } $label = $g->get_first_literal($uri, RDFS_LABEL, '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } $label = $g->get_first_literal($uri, 'http://purl.org/dc/terms/title', '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } $label = $g->get_first_literal($uri, DC_TITLE, '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } $label = $g->get_first_literal($uri, FOAF_NAME, '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } $label = $g->get_first_literal($uri, 'http://www.geonames.org/ontology#name', '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } $label = $g->get_first_literal($uri, RDF_VALUE, '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } $label = $g->get_first_literal($uri, 'http://purl.org/rss/1.0/title', '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } foreach ($this->_label_properties as $p) { $label = $g->get_first_literal($uri, $p, '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } } } - if (array_key_exists($uri, $this->_labels)) { + if (isset($this->_labels[$uri])) { if ($capitalize) { return ucfirst($this->_labels[$uri][0]); } @@ -456,6 +466,7 @@ public function get_label(string $uri, ?ExtendedGraph $g = null, bool $capitaliz } elseif (preg_match('~^.*[\/\#]([^\/\#]+)$~', $uri, $m)) { $localname = $m[1]; if (preg_match('~[^A-Z][A-Z][^A-Z]~', $localname)) { + /** @var non-empty-list $parts */ $parts = preg_split('/([A-Z][^A-Z]*)/', $localname, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); $parts = array_map('strtolower', $parts); if ($parts[0] == 'has') { @@ -484,12 +495,12 @@ public function get_plural_label(string $uri, ?ExtendedGraph $g = null, bool $ca { if ($g instanceof ExtendedGraph) { $label = $g->get_first_literal($uri, 'http://purl.org/net/vocab/2004/03/label#plural', '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } } - if (array_key_exists($uri, $this->_labels)) { + if (isset($this->_labels[$uri])) { $label = count($this->_labels[$uri]) > 1 ? $this->_labels[$uri][1] : $this->_labels[$uri][0] . 's'; if ($capitalize) { @@ -515,12 +526,12 @@ public function get_inverse_label(string $uri, ?ExtendedGraph $g = null, bool $c { if ($g instanceof ExtendedGraph) { $label = $g->get_first_literal($uri, 'http://purl.org/net/vocab/2004/03/label#inverseSingular', '', 'en'); - if (strlen($label) !== 0) { + if ($label) { return $label; } } - if (array_key_exists($uri, $this->_labels)) { + if (isset($this->_labels[$uri])) { $label = count($this->_labels[$uri]) > 2 ? $this->_labels[$uri][2] : 'is ' . $this->_labels[$uri][0] . ' of'; if ($capitalize) { @@ -545,7 +556,7 @@ public function label_graph(ExtendedGraph &$graph): void foreach ($index as $p_list) { foreach ($p_list as $p => $val) { if (!array_key_exists($p, $labelled_properties)) { - if (array_key_exists($p, $this->_labels)) { + if (isset($this->_labels[$p])) { if (!$graph->subject_has_property($p, RDFS_LABEL)) { $graph->add_literal_triple($p, RDFS_LABEL, $this->_labels[$p][0]); } From 148d0db57a6f9c9e0f8f03c23bd5a34cf8dee2f9 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 16 Mar 2026 22:44:32 +0000 Subject: [PATCH 41/56] Fix typo --- src/classes/Labeller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/Labeller.php b/src/classes/Labeller.php index 421c04ed..8ee4e678 100644 --- a/src/classes/Labeller.php +++ b/src/classes/Labeller.php @@ -27,7 +27,7 @@ class Labeller 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_9' => ['ninth', 'ninth', 'is ninth member of'], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_10' => ['tenth', 'tenth', 'is tenth member of'], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_11' => ['eleventh', 'eleventh', 'is eleventh member of'], - 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_12' => ['twelth', 'twelth', 'is twelth member of'], + 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_12' => ['twelfth', 'twelfth', 'is twelfth member of'], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_13' => ['thirteenth', 'thirteenth', 'is thirteenth member of'], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_14' => ['fourteenth', 'fourteenth', 'is fourteenth member of'], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_15' => ['fifteenth', 'fifteenth', 'is fifteenth member of'], From 18afec6ea3f9b80bc2aa0995feb5c2f8223d391e Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Mon, 16 Mar 2026 22:53:07 +0000 Subject: [PATCH 42/56] Fix missing return types --- src/mongo/IConfigInstance.php | 2 +- src/mongo/base/CompositeBase.php | 2 +- src/mongo/base/JobBase.php | 2 +- src/mongo/delegates/SearchDocuments.php | 4 ++-- src/mongo/delegates/SearchIndexer.php | 2 +- src/mongo/delegates/Tables.php | 12 ++++++------ src/mongo/delegates/Views.php | 2 +- src/mongo/util/TriplesUtil.php | 2 +- test/unit/mongo/TestJobBase.php | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/mongo/IConfigInstance.php b/src/mongo/IConfigInstance.php index ee002193..05fbf287 100644 --- a/src/mongo/IConfigInstance.php +++ b/src/mongo/IConfigInstance.php @@ -19,7 +19,7 @@ public function getMongoCursorTimeout(): int; /** * @param int $mongoCursorTimeout Timeout in ms */ - public function setMongoCursorTimeout(int $mongoCursorTimeout); + public function setMongoCursorTimeout(int $mongoCursorTimeout): void; /** * Returns an array of associated predicates in a table or search document specification diff --git a/src/mongo/base/CompositeBase.php b/src/mongo/base/CompositeBase.php index eeac4d11..30c5ceb0 100644 --- a/src/mongo/base/CompositeBase.php +++ b/src/mongo/base/CompositeBase.php @@ -182,7 +182,7 @@ protected function getApplyOperation(): ApplyOperation * @param string|null $queueName Queue name * @param array $jobOptions Job options */ - protected function queueApplyJob(array $subjects, ?string $queueName, array $jobOptions) + protected function queueApplyJob(array $subjects, ?string $queueName, array $jobOptions): void { $this->getApplyOperation()->createJob($subjects, $queueName, $jobOptions); } diff --git a/src/mongo/base/JobBase.php b/src/mongo/base/JobBase.php index 6fee9c32..63af5ac1 100644 --- a/src/mongo/base/JobBase.php +++ b/src/mongo/base/JobBase.php @@ -90,7 +90,7 @@ public function tearDown(): void /** * The main method of the job. */ - abstract public function perform(); + abstract public function perform(): void; /** * Called in every job prior to perform(). diff --git a/src/mongo/delegates/SearchDocuments.php b/src/mongo/delegates/SearchDocuments.php index c606bfcf..c91784fe 100644 --- a/src/mongo/delegates/SearchDocuments.php +++ b/src/mongo/delegates/SearchDocuments.php @@ -147,7 +147,7 @@ public function getSearchCollectionName(): string return SEARCH_INDEX_COLLECTION; } - protected function doJoin(array $source, array $joins, array &$target, string $from) + protected function doJoin(array $source, array $joins, array &$target, string $from): void { // expand sequences before proceeding $this->expandSequence($joins, $source); @@ -201,7 +201,7 @@ protected function doJoin(array $source, array $joins, array &$target, string $f } } - protected function addFields(array $source, array $fieldsOrIndices, array &$target, bool $isIndex = false) + protected function addFields(array $source, array $fieldsOrIndices, array &$target, bool $isIndex = false): void { foreach ($fieldsOrIndices as $f) { if (isset($f['predicates'])) { diff --git a/src/mongo/delegates/SearchIndexer.php b/src/mongo/delegates/SearchIndexer.php index 5339a508..c1416185 100644 --- a/src/mongo/delegates/SearchIndexer.php +++ b/src/mongo/delegates/SearchIndexer.php @@ -279,7 +279,7 @@ protected function deDupe(array $input): array * * @throws SearchException If provider class cannot be found */ - protected function setSearchProvider(Driver $tripod, ?IConfigInstance $config = null) + protected function setSearchProvider(Driver $tripod, ?IConfigInstance $config = null): void { if (is_null($config)) { $config = $this->getConfigInstance(); diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index 215ab3a7..06ce96bd 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -530,7 +530,7 @@ public function count(string $tableSpec, array $filters = []) * @param string|null $context Optional context * @param array|string|null $specType Optional table type or array of table types to delete from */ - protected function deleteTableRowsForResource(string $resource, ?string $context = null, $specType = null) + protected function deleteTableRowsForResource(string $resource, ?string $context = null, $specType = null): void { $t = new Timer(); $t->start(); @@ -565,7 +565,7 @@ protected function deleteTableRowsForResource(string $resource, ?string $context * This method handles invalidation and regeneration of table rows based on impact index, before delegating to * generateTableRowsForType() for re-generation of any table rows for the $resource. */ - protected function generateTableRowsForResource(string $resource, ?string $context = null, array $specTypes = []) + protected function generateTableRowsForResource(string $resource, ?string $context = null, array $specTypes = []): void { $resourceAlias = $this->labeller->uri_to_alias($resource); $contextAlias = $this->getContextAlias($context); @@ -609,7 +609,7 @@ protected function generateTableRowsForResource(string $resource, ?string $conte * * @throws \Exception */ - protected function truncatingSave(Collection $collection, array $generatedRow) + protected function truncatingSave(Collection $collection, array $generatedRow): void { try { $collection->updateOne(['_id' => $generatedRow['_id']], ['$set' => $generatedRow], ['upsert' => true]); @@ -629,7 +629,7 @@ protected function truncatingSave(Collection $collection, array $generatedRow) * * @param array $generatedRow - Pass by reference so that the contents is truncated */ - protected function truncateFields(Collection $collection, array &$generatedRow) + protected function truncateFields(Collection $collection, array &$generatedRow): void { // Find the name of any indexed fields $indexedFields = []; @@ -676,7 +676,7 @@ protected function truncateFields(Collection $collection, array &$generatedRow) * @param array $spec The table spec * @param mixed[] $dest The table row document to save */ - protected function doComputedFields(array $spec, array &$dest) + protected function doComputedFields(array $spec, array &$dest): void { if (isset($spec['computed_fields'])) { foreach ($spec['computed_fields'] as $f) { @@ -1149,7 +1149,7 @@ protected function getPredicateFunctions($array): array return $predicateFunctions; } - protected function doJoins(array $source, array $joins, array &$dest, string $from, string $contextAlias) + protected function doJoins(array $source, array $joins, array &$dest, string $from, string $contextAlias): void { $this->expandSequence($joins, $source); foreach ($joins as $predicate => $ruleset) { diff --git a/src/mongo/delegates/Views.php b/src/mongo/delegates/Views.php index d1b83c3e..4997ff46 100644 --- a/src/mongo/delegates/Views.php +++ b/src/mongo/delegates/Views.php @@ -506,7 +506,7 @@ public function count(string $viewSpec, array $filters = []): int /** * Joins data to $dest from $source according to specification in $joins, or queries DB if data is not available in $source. */ - protected function doJoins(array $source, array $joins, array &$dest, string $from, string $contextAlias, bool $buildImpactIndex = true) + protected function doJoins(array $source, array $joins, array &$dest, string $from, string $contextAlias, bool $buildImpactIndex = true): void { // expand sequences before doing any joins... $this->expandSequence($joins, $source); diff --git a/src/mongo/util/TriplesUtil.php b/src/mongo/util/TriplesUtil.php index 406ee1a9..4e5c98f7 100644 --- a/src/mongo/util/TriplesUtil.php +++ b/src/mongo/util/TriplesUtil.php @@ -168,7 +168,7 @@ public function getTArrayAbout(string $subject, array $triples, ?string $context /** * @throws \Exception */ - protected function saveCBD(string $cbdSubject, MongoGraph $cbdGraph, Collection $collection, ?string $context) + protected function saveCBD(string $cbdSubject, MongoGraph $cbdGraph, Collection $collection, ?string $context): void { $cbdSubject = $this->labeller->uri_to_alias($cbdSubject); if ($cbdGraph == null || $cbdGraph->is_empty()) { diff --git a/test/unit/mongo/TestJobBase.php b/test/unit/mongo/TestJobBase.php index 66599902..5734d923 100644 --- a/test/unit/mongo/TestJobBase.php +++ b/test/unit/mongo/TestJobBase.php @@ -14,7 +14,7 @@ public function getTripodConfig(): IConfigInstance return parent::getTripodConfig(); } - public function perform() {} + public function perform(): void {} protected function getStatTimerSuccessKey(): string { From b25f9adc2bc4c4ca040354622f26d2c62b86ce83 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 17 Mar 2026 12:43:59 +0000 Subject: [PATCH 43/56] Allow null offset in Driver::select() --- src/IDriver.php | 9 ++++++++- src/mongo/Driver.php | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/IDriver.php b/src/IDriver.php index 4fc222dd..a123d2a5 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -67,7 +67,14 @@ public function getETag(string $resource, ?string $context = null): string; * * @param array $fields array of fields, in the same format as prescribed by MongoPHP */ - public function select(array $query, array $fields, ?array $sortBy = null, ?int $limit = null, int $offset = 0, ?string $context = null): array; + public function select( + array $query, + array $fields, + ?array $sortBy = null, + ?int $limit = null, + ?int $offset = 0, + ?string $context = null + ): array; /** * Select data from a table. diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index 2e8e5c77..356b3507 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -360,7 +360,7 @@ public function getCount(array $query, ?string $groupBy = null, ?int $ttl = null * * @return array> */ - public function select(array $query, array $fields, ?array $sortBy = null, ?int $limit = null, int $offset = 0, ?string $context = null): array + public function select(array $query, array $fields, ?array $sortBy = null, ?int $limit = null, ?int $offset = 0, ?string $context = null): array { $t = new Timer(); $t->start(); @@ -394,7 +394,7 @@ public function select(array $query, array $fields, ?array $sortBy = null, ?int 'projection' => $fields, ]; if (!empty($limit)) { - $findOptions['skip'] = $offset; + $findOptions['skip'] = $offset ?? 0; $findOptions['limit'] = (int) $limit; } From af47f6ec62026deda8c44e1439546722c35a791c Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 17 Mar 2026 12:49:59 +0000 Subject: [PATCH 44/56] Make Driver::getTableRows() more consistent with select() --- src/IDriver.php | 6 +++--- src/mongo/Driver.php | 8 ++++---- src/mongo/delegates/Tables.php | 12 +++++++----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/IDriver.php b/src/IDriver.php index a123d2a5..7c6b74cc 100644 --- a/src/IDriver.php +++ b/src/IDriver.php @@ -82,9 +82,9 @@ public function select( public function getTableRows( string $tableType, array $filter = [], - array $sortBy = [], - int $offset = 0, - int $limit = 10, + ?array $sortBy = [], + ?int $offset = 0, + ?int $limit = 10, array $options = [] ): array; diff --git a/src/mongo/Driver.php b/src/mongo/Driver.php index 356b3507..061ce07f 100755 --- a/src/mongo/Driver.php +++ b/src/mongo/Driver.php @@ -173,9 +173,9 @@ public function getViews(array $filter, string $viewType): ExtendedGraph public function getTableRows( string $tableType, array $filter = [], - array $sortBy = [], - int $offset = 0, - int $limit = 10, + ?array $sortBy = [], + ?int $offset = 0, + ?int $limit = 10, array $options = [] ): array { return $this->getTripodTables()->getTableRows( @@ -395,7 +395,7 @@ public function select(array $query, array $fields, ?array $sortBy = null, ?int ]; if (!empty($limit)) { $findOptions['skip'] = $offset ?? 0; - $findOptions['limit'] = (int) $limit; + $findOptions['limit'] = $limit; } if (isset($sortBy)) { diff --git a/src/mongo/delegates/Tables.php b/src/mongo/delegates/Tables.php index 06ce96bd..3efa6d14 100644 --- a/src/mongo/delegates/Tables.php +++ b/src/mongo/delegates/Tables.php @@ -214,9 +214,9 @@ public function getOperationType(): string public function getTableRows( string $tableSpecId, array $filter = [], - array $sortBy = [], - int $offset = 0, - int $limit = 10, + ?array $sortBy = [], + ?int $offset = 0, + ?int $limit = 10, array $options = [] ): array { $t = new Timer(); @@ -241,11 +241,13 @@ public function getTableRows( $findOptions = []; if (!empty($limit)) { - $findOptions['skip'] = $offset; + $findOptions['skip'] = $offset ?? 0; $findOptions['limit'] = $limit; } - $findOptions['sort'] = $sortBy; + if (isset($sortBy)) { + $findOptions['sort'] = $sortBy; + } $results = $collection->find($filter, $findOptions); From 747e6d3d76d6299c73fa0c749262edb8ce424bab Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 17 Mar 2026 13:03:48 +0000 Subject: [PATCH 45/56] Correct types --- src/mongo/delegates/TransactionLog.php | 4 ++-- src/mongo/delegates/Updates.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mongo/delegates/TransactionLog.php b/src/mongo/delegates/TransactionLog.php index da037e4d..e66d8753 100644 --- a/src/mongo/delegates/TransactionLog.php +++ b/src/mongo/delegates/TransactionLog.php @@ -125,9 +125,9 @@ public function completeTransaction(string $transaction_id, array $newCBDs): voi * * @param string $transaction_id - the id of the transaction you wish to retrieve from the transaction log * - * @return array representing the transaction document + * @return array|null representing the transaction document */ - public function getTransaction(string $transaction_id): array + public function getTransaction(string $transaction_id): ?array { return $this->transaction_collection->findOne(['_id' => $transaction_id]); } diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 0e1ef301..25ceb88a 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -963,7 +963,7 @@ protected function unlockAllDocuments(string $transaction_id): bool * * @param string $s subject URI of resource to lock * - * @return array|false + * @return array|null|false */ protected function lockSingleDocument(string $s, string $transaction_id, string $contextAlias) { From 86ed2a3df2859fcc8788bc7e62d7ee1f39f151ab Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 17 Mar 2026 13:06:06 +0000 Subject: [PATCH 46/56] Ensure no empty values in newCBDs --- src/mongo/delegates/Updates.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 25ceb88a..1454320f 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -717,7 +717,9 @@ protected function applyChangeSet(ChangeSet $cs, array $originalCBDs, string $co 'upsert' => $update['upsert'], 'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER, ]); - $newCBDs[] = $newDoc; + if ($newDoc) { + $newCBDs[] = $newDoc; + } } catch (\Exception $e) { $this->errorLog( MONGO_WRITE, From 7ff25bc0f4dd68284b991f4596af9938155e274b Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 17 Mar 2026 13:09:42 +0000 Subject: [PATCH 47/56] Remove unneeded require --- src/mongo/base/DriverBase.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index 2086eaf2..1ab663ac 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -4,8 +4,6 @@ namespace Tripod\Mongo; -require_once TRIPOD_DIR . 'ITripodStat.php'; - use MongoDB\Collection; use MongoDB\Database; use MongoDB\Driver\ReadPreference; From d1c6901507f46e37b8635ea980174c526f646d54 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 17 Mar 2026 14:26:24 +0000 Subject: [PATCH 48/56] Check storeName is set before accessing --- src/mongo/base/DriverBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mongo/base/DriverBase.php b/src/mongo/base/DriverBase.php index 1ab663ac..57d8c8d4 100644 --- a/src/mongo/base/DriverBase.php +++ b/src/mongo/base/DriverBase.php @@ -66,7 +66,7 @@ public function getStat(): ITripodStat public function setStat(ITripodStat $stat): void { // TODO: how do we decouple this and still allow StatsD to know which db we're using? - if ($stat instanceof StatsD) { + if ($stat instanceof StatsD && isset($this->storeName)) { $stat->setPivotValue($this->getStoreName()); } From 143e27bf267db8d6d0538639f9cbf151d18536c1 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 17 Mar 2026 14:57:59 +0000 Subject: [PATCH 49/56] Segregate methods from DriverBase --- src/TripodStatFactory.php | 2 - src/classes/NoStat.php | 48 ++++++++++++++ src/mongo/base/DriverBase.php | 86 ------------------------- src/mongo/delegates/Updates.php | 36 ++++++++++- src/mongo/delegates/Views.php | 5 ++ test/unit/mongo/MongoTripodStatTest.php | 2 +- 6 files changed, 89 insertions(+), 90 deletions(-) create mode 100644 src/classes/NoStat.php diff --git a/src/TripodStatFactory.php b/src/TripodStatFactory.php index eddd448c..808818e6 100644 --- a/src/TripodStatFactory.php +++ b/src/TripodStatFactory.php @@ -4,8 +4,6 @@ namespace Tripod; -use Tripod\Mongo\NoStat; - class TripodStatFactory { /** diff --git a/src/classes/NoStat.php b/src/classes/NoStat.php new file mode 100644 index 00000000..435bde20 --- /dev/null +++ b/src/classes/NoStat.php @@ -0,0 +1,48 @@ +statsConfig); } - protected function getExpirySecFromNow(int $secs): int - { - return time() + $secs; - } - protected function getContextAlias(?string $context = null): string { $contextAlias = $this->labeller->uri_to_alias((empty($context)) ? $this->defaultContext : $context); @@ -337,33 +321,6 @@ protected function getCollection(): Collection return $this->collection; } - /** - * @param IEventHook[] $hooks - * - * @throws Exception If an invalid hook function is requested - */ - protected function applyHooks(string $fn, array $hooks, array $args = []): void - { - switch ($fn) { - case $this::HOOK_FN_PRE: - case $this::HOOK_FN_SUCCESS: - case $this::HOOK_FN_FAILURE: - break; - - default: - throw new Exception(sprintf('Invalid hook function %s requested', $fn)); - } - - foreach ($hooks as $hook) { - try { - call_user_func([$hook, $fn], $args); - } catch (\Exception $e) { - // don't let rabid hooks stop tripod - static::getLogger()->error('Hook ' . get_class($hook) . sprintf(' threw exception %s, continuing', $e->getMessage())); - } - } - } - /** * @codeCoverageIgnore */ @@ -372,46 +329,3 @@ private function log(string $level, string $message, ?array $params): void self::getLogger()->log($level, $message, $params ?: []); } } - -final class NoStat implements ITripodStat -{ - /** - * @var self - */ - public static $instance; - - public function increment(string $operation, int $inc = 1): void - { - // do nothing - } - - /** - * @param float|int $duration - */ - public function timer(string $operation, $duration): void - { - // do nothing - } - - public function getConfig(): array - { - return []; - } - - public static function getInstance(): self - { - if (self::$instance == null) { - self::$instance = new NoStat(); - } - - return self::$instance; - } - - /** - * @return self - */ - public static function createFromConfig(array $config = []) - { - return self::getInstance(); - } -} diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 1454320f..840f7746 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -22,6 +22,13 @@ class Updates extends DriverBase { + /** + * constants for the supported hook functions that can be applied. + */ + public const HOOK_FN_PRE = 'pre'; + public const HOOK_FN_SUCCESS = 'success'; + public const HOOK_FN_FAILURE = 'failure'; + protected Driver $tripod; protected ?Database $locksDb = null; @@ -352,6 +359,33 @@ public function registerSaveChangesEventHook(IEventHook $hook): void $this->saveChangesHooks[] = $hook; } + /** + * @param IEventHook[] $hooks + * + * @throws Exception If an invalid hook function is requested + */ + protected function applyHooks(string $fn, array $hooks, array $args = []): void + { + switch ($fn) { + case $this::HOOK_FN_PRE: + case $this::HOOK_FN_SUCCESS: + case $this::HOOK_FN_FAILURE: + break; + + default: + throw new Exception(sprintf('Invalid hook function %s requested', $fn)); + } + + foreach ($hooks as $hook) { + try { + call_user_func([$hook, $fn], $args); + } catch (\Exception $e) { + // don't let rabid hooks stop tripod + static::getLogger()->error('Hook ' . get_class($hook) . sprintf(' threw exception %s, continuing', $e->getMessage())); + } + } + } + /** * Change the read preferences to RP_PRIMARY * Used for a write operation. @@ -965,7 +999,7 @@ protected function unlockAllDocuments(string $transaction_id): bool * * @param string $s subject URI of resource to lock * - * @return array|null|false + * @return array|false|null */ protected function lockSingleDocument(string $s, string $transaction_id, string $contextAlias) { diff --git a/src/mongo/delegates/Views.php b/src/mongo/delegates/Views.php index 4997ff46..9a2634f9 100644 --- a/src/mongo/delegates/Views.php +++ b/src/mongo/delegates/Views.php @@ -503,6 +503,11 @@ public function count(string $viewSpec, array $filters = []): int return $this->getCollectionForViewSpec($viewSpec)->count($filters); } + protected function getExpirySecFromNow(int $secs): int + { + return time() + $secs; + } + /** * Joins data to $dest from $source according to specification in $joins, or queries DB if data is not available in $source. */ diff --git a/test/unit/mongo/MongoTripodStatTest.php b/test/unit/mongo/MongoTripodStatTest.php index 51453f97..3c703ac4 100644 --- a/test/unit/mongo/MongoTripodStatTest.php +++ b/test/unit/mongo/MongoTripodStatTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use Tripod\Mongo\NoStat; +use Tripod\NoStat; use Tripod\StatsD; use Tripod\TripodStatFactory; From 2adc87526ae2a47d9fa538bd430c693ac7ad4e6f Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Thu, 19 Mar 2026 11:54:31 +0000 Subject: [PATCH 50/56] Fix predicate (key) validation in MongoGraph::add_tarray_to_index --- src/mongo/MongoGraph.php | 10 +++++----- test/unit/mongo/MongoGraphTest.php | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mongo/MongoGraph.php b/src/mongo/MongoGraph.php index eed7b431..0b9b843b 100644 --- a/src/mongo/MongoGraph.php +++ b/src/mongo/MongoGraph.php @@ -118,8 +118,8 @@ private function add_tarray_to_index(array $tarray): void $_i = []; $predObjects = []; foreach ($tarray as $key => $value) { - if (empty($key)) { - throw new Exception('The predicate cannot be an empty string'); + if (!$this->isValidResource($key)) { + throw new Exception('The predicate must be a non-empty string, ' . var_export($key, true) . ' given'); } if ($key[0] != '_') { @@ -131,14 +131,14 @@ private function add_tarray_to_index(array $tarray): void } } elseif ($key == '_id') { // If the subject is invalid then throw an exception - if (!isset($value['r']) || !$this->isValidResource($value['r'])) { - throw new Exception('The subject cannot be an empty string'); + if (!isset($value[_ID_RESOURCE]) || !$this->isValidResource($value[_ID_RESOURCE])) { + throw new Exception('The subject must be a non-empty string, ' . var_export($value[_ID_RESOURCE], true) . ' given'); } } } $_i[$this->_labeller->qname_to_alias($tarray['_id'][_ID_RESOURCE])] = $predObjects; - $this->add_json(json_encode($_i)); + $this->_index = $this->merge($this->_index, $_i); } /** diff --git a/test/unit/mongo/MongoGraphTest.php b/test/unit/mongo/MongoGraphTest.php index 5ba65eed..16921b4a 100644 --- a/test/unit/mongo/MongoGraphTest.php +++ b/test/unit/mongo/MongoGraphTest.php @@ -179,7 +179,7 @@ public function addTripodArrayContainingInvalidLiteralValues_Provider(): iterabl */ public function testAddTripodArrayContainingInvalidPredicates($value): void { - $this->expectExceptionMessageMatches('/Argument 1 .* must be of the type string or null/'); + $this->expectExceptionMessage('The predicate must be a non-empty string'); $doc = [ '_id' => ['r' => 'http://talisaspire.com/works/4d101f63c10a6-2', 'c' => 'http://talisaspire.com/works/4d101f63c10a6-2'], '_version' => 0, @@ -212,7 +212,7 @@ public function testAddTripodArrayContainingEmptyPredicate(): void { // Should not be able to label '' $this->expectException(Exception::class); - $this->expectExceptionMessage('The predicate cannot be an empty string'); + $this->expectExceptionMessage('The predicate must be a non-empty string'); $doc = [ '_id' => ['r' => 'http://talisaspire.com/works/4d101f63c10a6-2', 'c' => 'http://talisaspire.com/works/4d101f63c10a6-2'], '_version' => 0, From 351eb384e99ce030cb53210df69f421ebbfcf9db Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 24 Mar 2026 13:03:38 +0000 Subject: [PATCH 51/56] Don't export phpstan files --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index ddcf46cb..cb2cfb7c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,3 +8,4 @@ docker-compose*.yml export-ignore logo.png export-ignore phpunit.xml export-ignore +phpstan*.neon export-ignore From bfc8602eabd1affc675c3ce31780a984ea5898b9 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 24 Mar 2026 22:03:28 +0000 Subject: [PATCH 52/56] Simplify option checks in scripts --- scripts/mongo/createSearchDocuments.php | 18 ++++-------------- scripts/mongo/createTables.php | 14 ++++---------- scripts/mongo/createViews.php | 14 ++++---------- 3 files changed, 12 insertions(+), 34 deletions(-) diff --git a/scripts/mongo/createSearchDocuments.php b/scripts/mongo/createSearchDocuments.php index f2c8d475..b8ddbed0 100644 --- a/scripts/mongo/createSearchDocuments.php +++ b/scripts/mongo/createSearchDocuments.php @@ -80,23 +80,13 @@ function generateSearchDocuments(?string $id, string $specId, string $storeName, Config::setConfig(json_decode(file_get_contents($configLocation), true)); -$storeName = isset($options['s']) || isset($options['storename']) ? $options['s'] ?? $options['storename'] : null; - -if (isset($options['d']) || isset($options['spec'])) { - $specId = isset($options['d']) ? $options['t'] : $options['spec']; -} else { - $specId = null; -} - -$id = isset($options['i']) || isset($options['id']) ? $options['i'] ?? $options['id'] : null; +$storeName = $options['s'] ?? $options['storename'] ?? null; +$specId = $options['d'] ?? $options['spec'] ?? null; +$id = $options['i'] ?? $options['id'] ?? null; $queue = null; if (isset($options['a']) || isset($options['async'])) { - if (isset($options['q']) || isset($options['queue'])) { - $queue = $options['queue']; - } else { - $queue = Config::getInstance()->getApplyQueueName(); - } + $queue = $options['q'] ?? $options['queue'] ?? Config::getInstance()->getApplyQueueName(); } $stat = null; diff --git a/scripts/mongo/createTables.php b/scripts/mongo/createTables.php index 8ad3894f..1d4921cb 100644 --- a/scripts/mongo/createTables.php +++ b/scripts/mongo/createTables.php @@ -86,19 +86,13 @@ function generateTables(?string $id, string $tableId, string $storeName, ?ITripo Config::setConfig(json_decode(file_get_contents($configLocation), true)); -$storeName = isset($options['s']) || isset($options['storename']) ? $options['s'] ?? $options['storename'] : null; - -$tableId = isset($options['t']) || isset($options['spec']) ? $options['t'] ?? $options['spec'] : null; - -$id = isset($options['i']) || isset($options['id']) ? $options['i'] ?? $options['id'] : null; +$storeName = $options['s'] ?? $options['storename'] ?? null; +$tableId = $options['t'] ?? $options['spec'] ?? null; +$id = $options['i'] ?? $options['id'] ?? null; $queue = null; if (isset($options['a']) || isset($options['async'])) { - if (isset($options['q']) || isset($options['queue'])) { - $queue = $options['queue']; - } else { - $queue = Config::getInstance()->getApplyQueueName(); - } + $queue = $options['q'] ?? $options['queue'] ?? Config::getInstance()->getApplyQueueName(); } $stat = null; diff --git a/scripts/mongo/createViews.php b/scripts/mongo/createViews.php index e3d78c36..d483231b 100644 --- a/scripts/mongo/createViews.php +++ b/scripts/mongo/createViews.php @@ -85,19 +85,13 @@ function generateViews(?string $id, string $viewId, string $storeName, ?ITripodS Config::setConfig(json_decode(file_get_contents($configLocation), true)); -$storeName = isset($options['s']) || isset($options['storename']) ? $options['s'] ?? $options['storename'] : null; - -$viewId = isset($options['v']) || isset($options['spec']) ? $options['v'] ?? $options['spec'] : null; - -$id = isset($options['i']) || isset($options['id']) ? $options['i'] ?? $options['id'] : null; +$storeName = $options['s'] ?? $options['storename'] ?? null; +$viewId = $options['v'] ?? $options['spec'] ?? null; +$id = $options['i'] ?? $options['id'] ?? null; $queue = null; if (isset($options['a']) || isset($options['async'])) { - if (isset($options['q']) || isset($options['queue'])) { - $queue = $options['queue']; - } else { - $queue = Config::getInstance()->getApplyQueueName(); - } + $queue = $options['q'] ?? $options['queue'] ?? Config::getInstance()->getApplyQueueName(); } $stat = null; From 3ddf74bf13fe855d2d9dd135fc9bfc379f4d98dd Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Tue, 24 Mar 2026 22:03:03 +0000 Subject: [PATCH 53/56] Correct usage text in scripts --- scripts/mongo/createSearchDocuments.php | 9 ++++++--- scripts/mongo/createTables.php | 7 ++++--- scripts/mongo/createViews.php | 9 +++++---- scripts/mongo/validateConfig.php | 13 +++++++++---- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/scripts/mongo/createSearchDocuments.php b/scripts/mongo/createSearchDocuments.php index b8ddbed0..f6b72b41 100644 --- a/scripts/mongo/createSearchDocuments.php +++ b/scripts/mongo/createSearchDocuments.php @@ -20,9 +20,12 @@ ] ); -function showUsage($scriptName): void +function showUsage(): void { + $scriptName = basename(__FILE__); $help = << Date: Tue, 24 Mar 2026 22:07:57 +0000 Subject: [PATCH 54/56] Fix check for initial $currentSubject --- scripts/mongo/loadTriples.php | 2 +- scripts/mongo/triplesToBSON.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mongo/loadTriples.php b/scripts/mongo/loadTriples.php index a7077460..4349def3 100644 --- a/scripts/mongo/loadTriples.php +++ b/scripts/mongo/loadTriples.php @@ -52,7 +52,7 @@ function load(TriplesUtil $loader, string $subject, array $triples, array &$erro $parts = preg_split('/\s/', $line); $subject = trim($parts[0], '><'); - if ($currentSubject === '' || $currentSubject === '0') { // set for first iteration + if ($currentSubject === '') { // set for first iteration $currentSubject = $subject; } elseif ($currentSubject !== $subject) { // once subject changes, we have all triples for that subject, flush to Mongo load($loader, $currentSubject, $triples, $errors, $podName, $storeName); diff --git a/scripts/mongo/triplesToBSON.php b/scripts/mongo/triplesToBSON.php index b9220daa..330aa3ff 100644 --- a/scripts/mongo/triplesToBSON.php +++ b/scripts/mongo/triplesToBSON.php @@ -29,7 +29,7 @@ $parts = preg_split('/\s/', $line); $subject = trim($parts[0], '><'); - if ($currentSubject === '' || $currentSubject === '0') { // set for first iteration + if ($currentSubject === '') { // set for first iteration $currentSubject = $subject; } From 4a8479e4c18704985dcff7fc0f00c372c0a6b816 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Wed, 25 Mar 2026 11:19:45 +0000 Subject: [PATCH 55/56] Stronger types in NQuadSerializer --- src/mongo/serializers/NQuadSerializer.php | 29 ++++------------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/src/mongo/serializers/NQuadSerializer.php b/src/mongo/serializers/NQuadSerializer.php index 56031a8b..4126de59 100644 --- a/src/mongo/serializers/NQuadSerializer.php +++ b/src/mongo/serializers/NQuadSerializer.php @@ -22,10 +22,8 @@ public function ___construct(): void /** * @param array|string $v - * - * @return string */ - public function getTerm($v) + public function getTerm($v): string { if (!is_array($v)) { if (preg_match('/^\_\:/', $v)) { @@ -70,10 +68,7 @@ public function getTerm($v) return $quot . $escaped . $quot . $suffix; } - /** - * @param array $index - */ - public function getSerializedIndex($index, ?string $context): string + public function getSerializedIndex(array $index, ?string $context): string { $r = ''; $nl = "\n"; @@ -108,12 +103,7 @@ public function getSerializedIndex($index, ?string $context): string return $r . $nl; } - /** - * @param string $v - * - * @return string - */ - public function escape($v) + public function escape(string $v): string { $r = ''; $v = (strpos(mb_convert_encoding(str_replace('?', '', $v), 'ISO-8859-1', 'UTF-8'), '?') === false) @@ -135,10 +125,7 @@ public function escape($v) return $r; } - /** - * @param string $c - */ - public function getCharNo($c): int + public function getCharNo(string $c): int { $c_utf = mb_convert_encoding($c, 'UTF-8', 'ISO-8859-1'); $bl = strlen($c_utf); // binary length @@ -169,13 +156,7 @@ public function getCharNo($c): int return $r; } - /** - * @param string $c - * @param int $no - * - * @return string - */ - public function getEscapedChar($c, $no) + public function getEscapedChar(string $c, int $no): string { // see http://www.w3.org/TR/rdf-testcases/#ntrip_strings if ($no < 9) { return '\u' . sprintf('%04X', $no); From 0f196742d0ded5c93134971d0b507a764193fa53 Mon Sep 17 00:00:00 2001 From: Grzegorz Rajchman Date: Wed, 25 Mar 2026 11:39:22 +0000 Subject: [PATCH 56/56] Add missing types --- src/mongo/Config.php | 2 +- src/mongo/MongoGraph.php | 6 +----- src/mongo/delegates/Updates.php | 5 ++--- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/mongo/Config.php b/src/mongo/Config.php index ae31b295..fa14ac4d 100644 --- a/src/mongo/Config.php +++ b/src/mongo/Config.php @@ -905,7 +905,7 @@ public function serialize(): array * * @param string $operation Async operation, e.g. OP_TABLES, OP_VIEWS */ - public function getBatchSize($operation): int + public function getBatchSize(string $operation): int { return $this->batchSize[$operation] ?? 1; } diff --git a/src/mongo/MongoGraph.php b/src/mongo/MongoGraph.php index 0b9b843b..736f63f8 100644 --- a/src/mongo/MongoGraph.php +++ b/src/mongo/MongoGraph.php @@ -213,11 +213,7 @@ private function toMongoTripodValueObject(array $simpleGraphValueObject): array ]; } - /** - * @param ExtendedGraph|null $graph - * @param string $contextAlias - */ - private function index_to_tarray($graph = null, $contextAlias = null): ?array + private function index_to_tarray(?ExtendedGraph $graph = null, ?string $contextAlias = null): ?array { if ($graph == null) { $graph = $this; diff --git a/src/mongo/delegates/Updates.php b/src/mongo/delegates/Updates.php index 840f7746..79ba7bfb 100644 --- a/src/mongo/delegates/Updates.php +++ b/src/mongo/delegates/Updates.php @@ -483,14 +483,13 @@ protected function validateGraphCardinality(ExtendedGraph $graph): void } /** - * @param ChangeSet $cs Change-set to apply - * @param string $contextAlias + * @param ChangeSet $cs Change-set to apply * * @return array An array of subjects and predicates that have been changed * * @throws Exception */ - protected function storeChanges(ChangeSet $cs, $contextAlias): array + protected function storeChanges(ChangeSet $cs, string $contextAlias): array { $t = new Timer(); $t->start();