From 6fbb25abb1f2d9f39065d16bf62ff3d6a67eff36 Mon Sep 17 00:00:00 2001 From: Elliot Sawyer Date: Fri, 17 Feb 2017 12:03:51 +1300 Subject: [PATCH 01/63] Bump framework/cms to ^4.0@dev --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 1a4a12e..e051477 100644 --- a/composer.json +++ b/composer.json @@ -20,11 +20,11 @@ } ], "require": { - "silverstripe/framework": "~3.1", + "silverstripe/framework": "^4.0@dev", "monolog/monolog": "~1.15" }, "require-dev": { - "silverstripe/cms": "~3.1", + "silverstripe/cms": "^4.0@dev", "hafriedlander/silverstripe-phockito": "*" }, "extra": { From bbdf79ea2b94d563faf7158d93bf94ff9baf8a61 Mon Sep 17 00:00:00 2001 From: elliot sawyer Date: Fri, 17 Feb 2017 16:27:38 +1300 Subject: [PATCH 02/63] WIP Silverstripe 4 compatibility fixes --- _config.php | 2 -- code/search/FullTextSearch.php | 2 ++ code/search/SearchIndex.php | 11 ++++++++--- code/search/SearchIntrospection.php | 18 ++++++++++-------- code/search/SearchVariant.php | 1 + code/solr/Solr.php | 27 +++++++++++++++++---------- code/solr/SolrIndex.php | 2 ++ 7 files changed, 40 insertions(+), 23 deletions(-) diff --git a/_config.php b/_config.php index c9e422a..3a5121a 100644 --- a/_config.php +++ b/_config.php @@ -2,5 +2,3 @@ global $databaseConfig; if (isset($databaseConfig['type'])) SearchUpdater::bind_manipulation_capture(); - -Deprecation::notification_version('1.0.0', 'fulltextsearch'); diff --git a/code/search/FullTextSearch.php b/code/search/FullTextSearch.php index 905a03c..636bbaa 100644 --- a/code/search/FullTextSearch.php +++ b/code/search/FullTextSearch.php @@ -1,5 +1,7 @@ databaseFields($class); if (isset($fields[$field])) { $type = $fields[$field]; @@ -209,7 +214,7 @@ abstract class SearchIndex extends ViewableData throw new Exception('Can\'t add class to Index after fields have already been added'); } - if (!DataObject::has_own_table($class)) { + if (!DataObject::getSchema()->classHasTable($class)) { throw new InvalidArgumentException('Can\'t add classes which don\'t have data tables (no $db or $has_one set on the class)'); } @@ -286,7 +291,7 @@ abstract class SearchIndex extends ViewableData { foreach ($this->getClasses() as $class => $options) { foreach (SearchIntrospection::hierarchy($class, $includeSubclasses, true) as $dataclass) { - $fields = DataObject::database_fields($dataclass); + $fields = DataObject::getSchema()->databaseFields($class); foreach ($fields as $field => $type) { if (preg_match('/^(\w+)\(/', $type, $match)) { diff --git a/code/search/SearchIntrospection.php b/code/search/SearchIntrospection.php index e88aeac..389ed05 100644 --- a/code/search/SearchIntrospection.php +++ b/code/search/SearchIntrospection.php @@ -1,5 +1,7 @@ $class) { - if (!DataObject::has_own_table($class)) { - unset($classes[$i]); - } - } - } +//@todo find another way to determine if a dataobject does not have a table +// if ($dataOnly) { +// foreach ($classes as $i => $class) { +// if (!DataObject::has_own_table($class)) { +// unset($classes[$i]); +// } +// } +// } self::$hierarchy[$key] = $classes; } diff --git a/code/search/SearchVariant.php b/code/search/SearchVariant.php index df6e187..978e867 100644 --- a/code/search/SearchVariant.php +++ b/code/search/SearchVariant.php @@ -1,5 +1,6 @@ logger; + return Injector::inst()->get('Logger'); } /** @@ -197,7 +202,7 @@ class Solr_BuildTask extends BuildTask */ protected function getLoggerFactory() { - return Injector::inst()->get('SearchLogFactory'); +// return Injector::inst()->get('SearchLogFactory'); } /** @@ -212,8 +217,9 @@ class Solr_BuildTask extends BuildTask // Set new logger $logger = $this - ->getLoggerFactory() - ->getOutputLogger($name, $verbose); + ->getLoggerFactory(); +//@todo: Cannot instantiate interface SearchLogFactory +// ->getOutputLogger($name, $verbose); $this->setLogger($logger); } } @@ -229,6 +235,7 @@ class Solr_Configure extends Solr_BuildTask // Find the IndexStore handler, which will handle uploading config files to Solr $store = $this->getSolrConfigStore(); + $indexes = Solr::get_indexes(); foreach ($indexes as $instance) { try { @@ -251,23 +258,23 @@ class Solr_Configure extends Solr_BuildTask protected function updateIndex($instance, $store) { $index = $instance->getIndexName(); - $this->getLogger()->info("Configuring $index."); + $this->getLogger()->addInfo("Configuring $index."); // Upload the config files for this index - $this->getLogger()->info("Uploading configuration ..."); + $this->getLogger()->addInfo("Uploading configuration ..."); $instance->uploadConfig($store); // Then tell Solr to use those config files $service = Solr::service(); if ($service->coreIsActive($index)) { - $this->getLogger()->info("Reloading core ..."); + $this->getLogger()->addInfo("Reloading core ..."); $service->coreReload($index); } else { - $this->getLogger()->info("Creating core ..."); + $this->getLogger()->addInfo("Creating core ..."); $service->coreCreate($index, $store->instanceDir($index)); } - $this->getLogger()->info("Done"); + $this->getLogger()->addInfo("Done"); } /** @@ -280,7 +287,7 @@ class Solr_Configure extends Solr_BuildTask $options = Solr::solr_options(); if (!isset($options['indexstore']) || !($indexstore = $options['indexstore'])) { - user_error('No index configuration for Solr provided', E_USER_ERROR); + throw new Exception('No index configuration for Solr provided', E_USER_ERROR); } // Find the IndexStore handler, which will handle uploading config files to Solr diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index 49e1dc8..f74dbf1 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -2,6 +2,8 @@ Solr::include_client_api(); +use SilverStripe\Dev\BuildTask; +use SilverStripe\Control\Director; abstract class SolrIndex extends SearchIndex { public static $fulltextTypeMap = array( From 7c27484d24b8d0431c32c7b11387975b6e6f0d09 Mon Sep 17 00:00:00 2001 From: elliot sawyer Date: Fri, 17 Feb 2017 17:37:32 +1300 Subject: [PATCH 03/63] more replacements and patches to migrate this module to 4.0 --- code/solr/Solr.php | 5 ++++- code/solr/SolrService.php | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/code/solr/Solr.php b/code/solr/Solr.php index 73ac0fb..b79a160 100644 --- a/code/solr/Solr.php +++ b/code/solr/Solr.php @@ -339,7 +339,9 @@ class Solr_Reindex extends Solr_BuildTask */ protected function getHandler() { - return Injector::inst()->get('SolrReindexHandler'); + //@todo: this needs to determine the best class from a Factory implementation + //@todo: it was 'SolrReindexHandler' but that doesn't work on 4.0 + return Injector::inst()->get('SolrReindexImmediateHandler'); } /** @@ -397,6 +399,7 @@ class Solr_Reindex extends Solr_BuildTask // If not using queuedjobs, we need to invoke Solr_Reindex as a separate process // Otherwise each group is processed via a SolrReindexGroupJob $groups = $request->getVar('groups'); + $handler = $this->getHandler(); if ($groups) { // Run grouped batches (id % groups = group) diff --git a/code/solr/SolrService.php b/code/solr/SolrService.php index 7b8c448..7a4e1c6 100644 --- a/code/solr/SolrService.php +++ b/code/solr/SolrService.php @@ -1,6 +1,7 @@ Date: Thu, 23 Feb 2017 20:04:55 +1300 Subject: [PATCH 04/63] Update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e051477..2279cfa 100644 --- a/composer.json +++ b/composer.json @@ -20,11 +20,11 @@ } ], "require": { - "silverstripe/framework": "^4.0@dev", + "silverstripe/framework": "4.0.x-dev", "monolog/monolog": "~1.15" }, "require-dev": { - "silverstripe/cms": "^4.0@dev", + "silverstripe/cms": "4.0.x-dev", "hafriedlander/silverstripe-phockito": "*" }, "extra": { From 45473db3034fd32cb2b9c573a459df87685b822c Mon Sep 17 00:00:00 2001 From: elliot sawyer Date: Thu, 23 Feb 2017 20:26:37 +1300 Subject: [PATCH 05/63] remove php <5.5 from travis.yml --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 303e94c..29a5d37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ language: php sudo: false php: - - 5.4 - 5.5 - 5.6 @@ -14,8 +13,6 @@ env: matrix: include: - - php: 5.3 - env: DB=PGSQL CORE_RELEASE=3.1 - php: 5.6 env: DB=MYSQL CORE_RELEASE=3.2 - php: 5.6 From 19b38e08111cceb928824b80b4a0fd8981b9d3b7 Mon Sep 17 00:00:00 2001 From: elliot sawyer Date: Fri, 21 Apr 2017 11:37:01 +1200 Subject: [PATCH 06/63] WIP more SS4 compatibility fixes --- code/search/SearchIndex.php | 1 + code/search/SearchQuery.php | 1 + code/search/SearchUpdater.php | 13 +++++++++++-- code/solr/Solr.php | 7 ++++--- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/code/search/SearchIndex.php b/code/search/SearchIndex.php index 6f5a865..4cb65f2 100644 --- a/code/search/SearchIndex.php +++ b/code/search/SearchIndex.php @@ -1,4 +1,5 @@ Date: Fri, 21 Apr 2017 11:45:04 +1200 Subject: [PATCH 07/63] WIP fix solr path to use DIR, avoid hardcoded module name --- code/solr/Solr.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/solr/Solr.php b/code/solr/Solr.php index 3614776..073d933 100644 --- a/code/solr/Solr.php +++ b/code/solr/Solr.php @@ -154,7 +154,7 @@ class Solr static $included = false; if (!$included) { - $solr_php_path = BASE_PATH . DIRECTORY_SEPARATOR . 'fulltextsearch/thirdparty/solr-php-client'; + $solr_php_path = __DIR__. '/../..' . '/thirdparty/solr-php-client'; set_include_path($solr_php_path); require_once($solr_php_path . DIRECTORY_SEPARATOR . 'Apache/Solr/Service.php'); require_once($solr_php_path . DIRECTORY_SEPARATOR . 'Apache/Solr/Document.php'); From 9aac0ff1aa2bc858797e2fde07c9aa9c1e48d243 Mon Sep 17 00:00:00 2001 From: elliot sawyer Date: Fri, 21 Apr 2017 11:59:27 +1200 Subject: [PATCH 08/63] WIP respect current include path WIP Namespacing and use on SearchIndex class --- code/search/SearchIndex.php | 2 +- code/solr/Solr.php | 8 ++++---- code/solr/SolrIndex.php | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/code/search/SearchIndex.php b/code/search/SearchIndex.php index 4cb65f2..1857ee3 100644 --- a/code/search/SearchIndex.php +++ b/code/search/SearchIndex.php @@ -1,5 +1,5 @@ Date: Fri, 21 Apr 2017 12:23:27 +1200 Subject: [PATCH 09/63] Namespacing for tests --- code/search/FullTextSearch.php | 2 + code/search/SearchIndex.php | 95 +------------------ code/search/SearchIndex_Null.php | 23 +++++ code/search/SearchIndex_Recording.php | 79 +++++++++++++++ code/solr/SolrIndex.php | 2 +- tests/BatchedProcessorTest.php | 37 +------- .../BatchedProcessorTest_Index.php | 15 +++ .../BatchedProcessorTest_Object.php | 13 +++ .../BatchedProcessor_QueuedJobService.php | 22 +++++ tests/SearchUpdaterTest.php | 4 + ...rchVariantSiteTreeSubsitesPolyhomeTest.php | 4 + tests/SearchVariantVersionedTest.php | 5 + tests/Solr4ServiceTest.php | 2 + tests/SolrIndexSubsitesTest.php | 2 + tests/SolrIndexTest.php | 3 + tests/SolrIndexVersionedTest.php | 4 + tests/SolrReindexQueuedTest.php | 2 + tests/SolrReindexTest.php | 6 +- 18 files changed, 191 insertions(+), 129 deletions(-) create mode 100644 code/search/SearchIndex_Null.php create mode 100644 code/search/SearchIndex_Recording.php create mode 100644 tests/BatchedProcessorTest/BatchedProcessorTest_Index.php create mode 100644 tests/BatchedProcessorTest/BatchedProcessorTest_Object.php create mode 100644 tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php diff --git a/code/search/FullTextSearch.php b/code/search/FullTextSearch.php index 636bbaa..b419d25 100644 --- a/code/search/FullTextSearch.php +++ b/code/search/FullTextSearch.php @@ -1,5 +1,7 @@ added = array(); - $this->deleted = array(); - $this->committed = false; - } - - public function add($object) - { - $res = array(); - - $res['ID'] = $object->ID; - - foreach ($this->getFieldsIterator() as $name => $field) { - $val = $this->_getFieldValue($object, $field); - $res[$name] = $val; - } - - $this->added[] = $res; - } - - public function getAdded($fields = array()) - { - $res = array(); - - foreach ($this->added as $added) { - $filtered = array(); - foreach ($fields as $field) { - if (isset($added[$field])) { - $filtered[$field] = $added[$field]; - } - } - $res[] = $filtered; - } - - return $res; - } - - public function delete($base, $id, $state) - { - $this->deleted[] = array('base' => $base, 'id' => $id, 'state' => $state); - } - - public function commit() - { - $this->committed = true; - } - - public function getIndexName() - { - return get_class($this); - } - - public function getIsCommitted() - { - return $this->committed; - } - - public function getService() - { - // Causes commits to the service to be redirected back to the same object - return $this; - } -} diff --git a/code/search/SearchIndex_Null.php b/code/search/SearchIndex_Null.php new file mode 100644 index 0000000..961bcb2 --- /dev/null +++ b/code/search/SearchIndex_Null.php @@ -0,0 +1,23 @@ +added = array(); + $this->deleted = array(); + $this->committed = false; + } + + public function add($object) + { + $res = array(); + + $res['ID'] = $object->ID; + + foreach ($this->getFieldsIterator() as $name => $field) { + $val = $this->_getFieldValue($object, $field); + $res[$name] = $val; + } + + $this->added[] = $res; + } + + public function getAdded($fields = array()) + { + $res = array(); + + foreach ($this->added as $added) { + $filtered = array(); + foreach ($fields as $field) { + if (isset($added[$field])) { + $filtered[$field] = $added[$field]; + } + } + $res[] = $filtered; + } + + return $res; + } + + public function delete($base, $id, $state) + { + $this->deleted[] = array('base' => $base, 'id' => $id, 'state' => $state); + } + + public function commit() + { + $this->committed = true; + } + + public function getIndexName() + { + return get_class($this); + } + + public function getIsCommitted() + { + return $this->committed; + } + + public function getService() + { + // Causes commits to the service to be redirected back to the same object + return $this; + } +} diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index bfe7477..8e69c77 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -4,7 +4,7 @@ Solr::include_client_api(); use SilverStripe\Dev\BuildTask; use SilverStripe\Control\Director; -use SilverStripe\FulltextSearch\SearchIndex; +use SilverStripe\FulltextSearch\Search\SearchIndex; abstract class SolrIndex extends SearchIndex { diff --git a/tests/BatchedProcessorTest.php b/tests/BatchedProcessorTest.php index 6978d3e..fcb96b3 100644 --- a/tests/BatchedProcessorTest.php +++ b/tests/BatchedProcessorTest.php @@ -1,40 +1,9 @@ 'Varchar' - ); -} - -class BatchedProcessorTest_Index extends SearchIndex_Recording implements TestOnly -{ - public function init() - { - $this->addClass('BatchedProcessorTest_Object'); - $this->addFilterField('TestText'); - } -} - -class BatchedProcessor_QueuedJobService -{ - protected $jobs = array(); - - public function queueJob(QueuedJob $job, $startAfter = null, $userId = null, $queueName = null) - { - $this->jobs[] = array( - 'job' => $job, - 'startAfter' => $startAfter - ); - return $job; - } - - public function getJobs() - { - return $this->jobs; - } -} +use SilverStripe\Dev\SapphireTest; +use SilverStripe\FullTextSearch\Search\FullTextSearch; /** * Tests {@see SearchUpdateQueuedJobProcessor} diff --git a/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php b/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php new file mode 100644 index 0000000..c62ea6b --- /dev/null +++ b/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php @@ -0,0 +1,15 @@ +addClass('BatchedProcessorTest_Object'); + $this->addFilterField('TestText'); + } +} diff --git a/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php b/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php new file mode 100644 index 0000000..b596a3a --- /dev/null +++ b/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php @@ -0,0 +1,13 @@ + 'Varchar' + ); +} diff --git a/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php b/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php new file mode 100644 index 0000000..1cf5253 --- /dev/null +++ b/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php @@ -0,0 +1,22 @@ +jobs[] = array( + 'job' => $job, + 'startAfter' => $startAfter + ); + return $job; + } + + public function getJobs() + { + return $this->jobs; + } +} diff --git a/tests/SearchUpdaterTest.php b/tests/SearchUpdaterTest.php index d2211c0..9cbb9c8 100644 --- a/tests/SearchUpdaterTest.php +++ b/tests/SearchUpdaterTest.php @@ -1,5 +1,9 @@ filtersOnID()) { From abdfe1947fd8b67884b4c6ae55a68211b32ca145 Mon Sep 17 00:00:00 2001 From: elliot sawyer Date: Fri, 21 Apr 2017 12:27:01 +1200 Subject: [PATCH 10/63] WIP add namespaces to all classes --- code/search/FullTextSearch.php | 2 +- code/search/SearchIntrospection.php | 2 +- code/search/SearchQuery.php | 2 +- code/search/SearchUpdater.php | 2 +- code/search/SearchVariant.php | 2 +- code/search/SearchVariantSiteTreeSubsitesPolyhome.php | 1 + code/search/SearchVariantSubsites.php | 2 +- code/search/SearchVariantVersioned.php | 2 +- code/search/processors/SearchUpdateBatchedProcessor.php | 2 +- code/search/processors/SearchUpdateCommitJobProcessor.php | 2 +- code/search/processors/SearchUpdateImmediateProcessor.php | 2 +- code/search/processors/SearchUpdateMessageQueueProcessor.php | 2 +- code/search/processors/SearchUpdateProcessor.php | 2 +- code/search/processors/SearchUpdateQueuedJobProcessor.php | 2 +- code/solr/Solr.php | 2 +- code/solr/Solr3Service.php | 2 +- code/solr/Solr4Service.php | 2 +- code/solr/SolrConfigStore.php | 2 +- code/solr/SolrIndex.php | 2 +- code/solr/SolrService.php | 3 ++- code/solr/reindex/handlers/SolrReindexBase.php | 2 +- code/solr/reindex/handlers/SolrReindexHandler.php | 2 +- code/solr/reindex/handlers/SolrReindexImmediateHandler.php | 2 +- code/solr/reindex/handlers/SolrReindexMessageHandler.php | 2 +- code/solr/reindex/handlers/SolrReindexQueuedHandler.php | 2 +- code/solr/reindex/jobs/SolrReindexGroupQueuedJob.php | 2 +- code/solr/reindex/jobs/SolrReindexQueuedJob.php | 2 +- code/solr/reindex/jobs/SolrReindexQueuedJobBase.php | 2 +- code/utils/CombinationsArrayIterator.php | 3 ++- code/utils/MultipleArrayIterator.php | 3 ++- code/utils/WebDAV.php | 2 +- code/utils/logging/MonologFactory.php | 2 +- code/utils/logging/QueuedJobLogHandler.php | 2 +- code/utils/logging/SearchLogFactory.php | 2 +- 34 files changed, 37 insertions(+), 33 deletions(-) diff --git a/code/search/FullTextSearch.php b/code/search/FullTextSearch.php index 636bbaa..2feb51a 100644 --- a/code/search/FullTextSearch.php +++ b/code/search/FullTextSearch.php @@ -1,5 +1,5 @@ Date: Fri, 21 Apr 2017 13:08:14 +1200 Subject: [PATCH 11/63] WIP split Solr files with multiple classes into single file / single class. Adjust namespaces --- code/solr/Solr.php | 299 +----------------- code/solr/SolrConfigStore.php | 134 -------- code/solr/SolrIndex.php | 1 - code/solr/{ => services}/Solr3Service.php | 5 +- code/solr/services/Solr3Service_Core.php | 8 + code/solr/services/Solr4Service.php | 7 + .../Solr4Service_Core.php} | 15 +- code/solr/{ => services}/SolrService.php | 14 +- code/solr/services/SolrService_Core.php | 18 ++ code/solr/stores/SolrConfigStore.php | 36 +++ code/solr/stores/SolrConfigStore_File.php | 53 ++++ code/solr/stores/SolrConfigStore_WebDAV.php | 56 ++++ code/solr/tasks/Solr_BuildTask.php | 63 ++++ code/solr/tasks/Solr_Configure.php | 81 +++++ code/solr/tasks/Solr_Reindex.php | 148 +++++++++ 15 files changed, 482 insertions(+), 456 deletions(-) delete mode 100644 code/solr/SolrConfigStore.php rename code/solr/{ => services}/Solr3Service.php (51%) create mode 100644 code/solr/services/Solr3Service_Core.php create mode 100644 code/solr/services/Solr4Service.php rename code/solr/{Solr4Service.php => services/Solr4Service_Core.php} (92%) rename code/solr/{ => services}/SolrService.php (91%) create mode 100644 code/solr/services/SolrService_Core.php create mode 100644 code/solr/stores/SolrConfigStore.php create mode 100644 code/solr/stores/SolrConfigStore_File.php create mode 100644 code/solr/stores/SolrConfigStore_WebDAV.php create mode 100644 code/solr/tasks/Solr_BuildTask.php create mode 100644 code/solr/tasks/Solr_Configure.php create mode 100644 code/solr/tasks/Solr_Reindex.php diff --git a/code/solr/Solr.php b/code/solr/Solr.php index c9bc780..98d3972 100644 --- a/code/solr/Solr.php +++ b/code/solr/Solr.php @@ -1,13 +1,7 @@ get('Logger'); - } - - /** - * Assign a new logger - * - * @param LoggerInterface $logger - */ - public function setLogger(LoggerInterface $logger) - { - $this->logger = $logger; - } - - /** - * @return SearchLogFactory - */ - protected function getLoggerFactory() - { -// return Injector::inst()->get('SearchLogFactory'); - } - - /** - * Setup task - * - * @param SS_HTTPReqest $request - */ - public function run($request) - { - $name = get_class($this); - $verbose = $request->getVar('verbose'); - - // Set new logger - $logger = $this - ->getLoggerFactory(); -//@todo: Cannot instantiate interface SearchLogFactory -// ->getOutputLogger($name, $verbose); - $this->setLogger($logger); - } -} - - -class Solr_Configure extends Solr_BuildTask -{ - protected $enabled = true; - - public function run($request) - { - parent::run($request); - - // Find the IndexStore handler, which will handle uploading config files to Solr - $store = $this->getSolrConfigStore(); - - $indexes = Solr::get_indexes(); - foreach ($indexes as $instance) { - try { - $this->updateIndex($instance, $store); - } catch (Exception $e) { - // We got an exception. Warn, but continue to next index. - $this - ->getLogger() - ->error("Failure: " . $e->getMessage()); - } - } - } - - /** - * Update the index on the given store - * - * @param SolrIndex $instance Instance - * @param SolrConfigStore $store - */ - protected function updateIndex($instance, $store) - { - $index = $instance->getIndexName(); - $this->getLogger()->addInfo("Configuring $index."); - - // Upload the config files for this index - $this->getLogger()->addInfo("Uploading configuration ..."); - $instance->uploadConfig($store); - - // Then tell Solr to use those config files - $service = Solr::service(); - if ($service->coreIsActive($index)) { - $this->getLogger()->addInfo("Reloading core ..."); - $service->coreReload($index); - } else { - $this->getLogger()->addInfo("Creating core ..."); - $service->coreCreate($index, $store->instanceDir($index)); - } - - $this->getLogger()->addInfo("Done"); - } - - /** - * Get config store - * - * @return SolrConfigStore - */ - protected function getSolrConfigStore() - { - $options = Solr::solr_options(); - - if (!isset($options['indexstore']) || !($indexstore = $options['indexstore'])) { - throw new Exception('No index configuration for Solr provided', E_USER_ERROR); - } - - // Find the IndexStore handler, which will handle uploading config files to Solr - $mode = $indexstore['mode']; - - if ($mode == 'file') { - return new SolrConfigStore_File($indexstore); - } elseif ($mode == 'webdav') { - return new SolrConfigStore_WebDAV($indexstore); - } elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, 'SolrConfigStore')) { - return new $mode($indexstore); - } else { - user_error('Unknown Solr index mode '.$indexstore['mode'], E_USER_ERROR); - } - } -} - -/** - * Task used for both initiating a new reindex, as well as for processing incremental batches - * within a reindex. - * - * When running a complete reindex you can provide any of the following - * - class (to limit to a single class) - * - verbose (optional) - * - * When running with a single batch, provide the following querystring arguments: - * - start - * - index - * - class - * - variantstate - * - verbose (optional) - */ -class Solr_Reindex extends Solr_BuildTask -{ - protected $enabled = true; - - /** - * Number of records to load and index per request - * - * @var int - * @config - */ - private static $recordsPerRequest = 200; - - /** - * Get the reindex handler - * - * @return SolrReindexHandler - */ - protected function getHandler() - { - //@todo: this needs to determine the best class from a Factory implementation - //@todo: it was 'SolrReindexHandler' but that doesn't work on 4.0 - return Injector::inst()->get('SolrReindexImmediateHandler'); - } - - /** - * @param SS_HTTPRequest $request - */ - public function run($request) - { - parent::run($request); - - // Reset state - $originalState = SearchVariant::current_state(); - $this->doReindex($request); - SearchVariant::activate_state($originalState); - } - - /** - * @param SS_HTTPRequest $request - */ - protected function doReindex($request) - { - $class = $request->getVar('class'); - - $index = $request->getVar('index'); - - //find the index classname by IndexName - // this is for when index names do not match the class name (this can be done by overloading getIndexName() on - // indexes - if ($index && !ClassInfo::exists($index)) { - foreach(ClassInfo::subclassesFor('SolrIndex') as $solrIndexClass) { - $reflection = new ReflectionClass($solrIndexClass); - //skip over abstract classes - if (!$reflection->isInstantiable()) { - continue; - } - //check the indexname matches the index passed to the request - if (!strcasecmp(singleton($solrIndexClass)->getIndexName(), $index)) { - //if we match, set the correct index name and move on - $index = $solrIndexClass; - break; - } - } - } - - // Deprecated reindex mechanism - $start = $request->getVar('start'); - if ($start !== null) { - // Run single batch directly - $indexInstance = singleton($index); - $state = json_decode($request->getVar('variantstate'), true); - $this->runFrom($indexInstance, $class, $start, $state); - return; - } - - // Check if we are re-indexing a single group - // If not using queuedjobs, we need to invoke Solr_Reindex as a separate process - // Otherwise each group is processed via a SolrReindexGroupJob - $groups = $request->getVar('groups'); - - $handler = $this->getHandler(); - if ($groups) { - // Run grouped batches (id % groups = group) - $group = $request->getVar('group'); - $indexInstance = singleton($index); - $state = json_decode($request->getVar('variantstate'), true); - - $handler->runGroup($this->getLogger(), $indexInstance, $state, $class, $groups, $group); - return; - } - - // If run at the top level, delegate to appropriate handler - $self = get_class($this); - $handler->triggerReindex($this->getLogger(), $this->config()->recordsPerRequest, $self, $class); - } - - /** - * @deprecated since version 2.0.0 - */ - protected function runFrom($index, $class, $start, $variantstate) - { - DeprecationTest_Deprecation::notice('2.0.0', 'Solr_Reindex now uses a new grouping mechanism'); - - // Set time limit and state - increase_time_limit_to(); - SearchVariant::activate_state($variantstate); - - // Generate filtered list - $items = DataList::create($class) - ->limit($this->config()->recordsPerRequest, $start); - - // Add child filter - $classes = $index->getClasses(); - $options = $classes[$class]; - if (!$options['include_children']) { - $items = $items->filter('ClassName', $class); - } - - // Process selected records in this class - $this->getLogger()->info("Adding $class"); - foreach ($items->sort("ID") as $item) { - $this->getLogger()->debug($item->ID); - - // See SearchUpdater_ObjectHandler::triggerReindex - $item->triggerReindex(); - $item->destroy(); - } - - $this->getLogger()->info("Done"); - } -} +} \ No newline at end of file diff --git a/code/solr/SolrConfigStore.php b/code/solr/SolrConfigStore.php deleted file mode 100644 index 5e856d3..0000000 --- a/code/solr/SolrConfigStore.php +++ /dev/null @@ -1,134 +0,0 @@ -local = $config['path']; - $this->remote = isset($config['remotepath']) ? $config['remotepath'] : $config['path']; - } - - public function getTargetDir($index) - { - $targetDir = "{$this->local}/{$index}/conf"; - - if (!is_dir($targetDir)) { - $worked = @mkdir($targetDir, 0770, true); - - if (!$worked) { - throw new RuntimeException( - sprintf('Failed creating target directory %s, please check permissions', $targetDir) - ); - } - } - - return $targetDir; - } - - public function uploadFile($index, $file) - { - $targetDir = $this->getTargetDir($index); - copy($file, $targetDir.'/'.basename($file)); - } - - public function uploadString($index, $filename, $string) - { - $targetDir = $this->getTargetDir($index); - file_put_contents("$targetDir/$filename", $string); - } - - public function instanceDir($index) - { - return $this->remote.'/'.$index; - } -} - -/** - * Class SolrConfigStore_WebDAV - * - * A ConfigStore that uploads files to a Solr instance via a WebDAV server - */ -class SolrConfigStore_WebDAV implements SolrConfigStore -{ - public function __construct($config) - { - $options = Solr::solr_options(); - - $this->url = implode('', array( - 'http://', - isset($config['auth']) ? $config['auth'].'@' : '', - $options['host'].':'.(isset($config['port']) ? $config['port'] : $options['port']), - $config['path'] - )); - $this->remote = $config['remotepath']; - } - - public function getTargetDir($index) - { - $indexdir = "{$this->url}/$index"; - if (!WebDAV::exists($indexdir)) { - WebDAV::mkdir($indexdir); - } - - $targetDir = "{$this->url}/$index/conf"; - if (!WebDAV::exists($targetDir)) { - WebDAV::mkdir($targetDir); - } - - return $targetDir; - } - - public function uploadFile($index, $file) - { - $targetDir = $this->getTargetDir($index); - WebDAV::upload_from_file($file, $targetDir.'/'.basename($file)); - } - - public function uploadString($index, $filename, $string) - { - $targetDir = $this->getTargetDir($index); - WebDAV::upload_from_string($string, "$targetDir/$filename"); - } - - public function instanceDir($index) - { - return $this->remote ? "{$this->remote}/$index" : $index; - } -} diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index 157b53e..68e13b4 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -2,7 +2,6 @@ namespace SilverStripe\FullTextSearch\Solr; Solr::include_client_api(); -use SilverStripe\Dev\BuildTask; use SilverStripe\Control\Director; use SilverStripe\FulltextSearch\SearchIndex; diff --git a/code/solr/Solr3Service.php b/code/solr/services/Solr3Service.php similarity index 51% rename from code/solr/Solr3Service.php rename to code/solr/services/Solr3Service.php index 2bdcee5..f2546a6 100644 --- a/code/solr/Solr3Service.php +++ b/code/solr/services/Solr3Service.php @@ -1,8 +1,5 @@ '; return $this->_sendRawPost($this->_updateUrl, $rawPost, $timeout); } - + /** - * @inheritdoc + * @inheritdoc * @see Solr4Service_Core::addDocuments */ public function addDocument(Apache_Solr_Document $document, $allowDups = false, @@ -50,9 +52,4 @@ class Solr4Service_Core extends SolrService_Core return $this->add($rawPost); } -} - -class Solr4Service extends SolrService -{ - private static $core_class = 'Solr4Service_Core'; -} +} \ No newline at end of file diff --git a/code/solr/SolrService.php b/code/solr/services/SolrService.php similarity index 91% rename from code/solr/SolrService.php rename to code/solr/services/SolrService.php index f2766ac..6aae39b 100644 --- a/code/solr/SolrService.php +++ b/code/solr/services/SolrService.php @@ -1,16 +1,8 @@ local = $config['path']; + $this->remote = isset($config['remotepath']) ? $config['remotepath'] : $config['path']; + } + + public function getTargetDir($index) + { + $targetDir = "{$this->local}/{$index}/conf"; + + if (!is_dir($targetDir)) { + $worked = @mkdir($targetDir, 0770, true); + + if (!$worked) { + throw new RuntimeException( + sprintf('Failed creating target directory %s, please check permissions', $targetDir) + ); + } + } + + return $targetDir; + } + + public function uploadFile($index, $file) + { + $targetDir = $this->getTargetDir($index); + copy($file, $targetDir.'/'.basename($file)); + } + + public function uploadString($index, $filename, $string) + { + $targetDir = $this->getTargetDir($index); + file_put_contents("$targetDir/$filename", $string); + } + + public function instanceDir($index) + { + return $this->remote.'/'.$index; + } +} \ No newline at end of file diff --git a/code/solr/stores/SolrConfigStore_WebDAV.php b/code/solr/stores/SolrConfigStore_WebDAV.php new file mode 100644 index 0000000..96259cb --- /dev/null +++ b/code/solr/stores/SolrConfigStore_WebDAV.php @@ -0,0 +1,56 @@ +url = implode('', array( + 'http://', + isset($config['auth']) ? $config['auth'].'@' : '', + $options['host'].':'.(isset($config['port']) ? $config['port'] : $options['port']), + $config['path'] + )); + $this->remote = $config['remotepath']; + } + + public function getTargetDir($index) + { + $indexdir = "{$this->url}/$index"; + if (!WebDAV::exists($indexdir)) { + WebDAV::mkdir($indexdir); + } + + $targetDir = "{$this->url}/$index/conf"; + if (!WebDAV::exists($targetDir)) { + WebDAV::mkdir($targetDir); + } + + return $targetDir; + } + + public function uploadFile($index, $file) + { + $targetDir = $this->getTargetDir($index); + WebDAV::upload_from_file($file, $targetDir.'/'.basename($file)); + } + + public function uploadString($index, $filename, $string) + { + $targetDir = $this->getTargetDir($index); + WebDAV::upload_from_string($string, "$targetDir/$filename"); + } + + public function instanceDir($index) + { + return $this->remote ? "{$this->remote}/$index" : $index; + } +} \ No newline at end of file diff --git a/code/solr/tasks/Solr_BuildTask.php b/code/solr/tasks/Solr_BuildTask.php new file mode 100644 index 0000000..d26f647 --- /dev/null +++ b/code/solr/tasks/Solr_BuildTask.php @@ -0,0 +1,63 @@ +get('Logger'); + } + + /** + * Assign a new logger + * + * @param LoggerInterface $logger + */ + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * @return SearchLogFactory + */ + protected function getLoggerFactory() + { +// return Injector::inst()->get('SearchLogFactory'); + } + + /** + * Setup task + * + * @param SS_HTTPReqest $request + */ + public function run($request) + { + $name = get_class($this); + $verbose = $request->getVar('verbose'); + + // Set new logger + $logger = $this + ->getLoggerFactory(); +//@todo: Cannot instantiate interface SearchLogFactory +// ->getOutputLogger($name, $verbose); + $this->setLogger($logger); + } +} diff --git a/code/solr/tasks/Solr_Configure.php b/code/solr/tasks/Solr_Configure.php new file mode 100644 index 0000000..8989f9c --- /dev/null +++ b/code/solr/tasks/Solr_Configure.php @@ -0,0 +1,81 @@ +getSolrConfigStore(); + + $indexes = Solr::get_indexes(); + foreach ($indexes as $instance) { + try { + $this->updateIndex($instance, $store); + } catch (Exception $e) { + // We got an exception. Warn, but continue to next index. + $this + ->getLogger() + ->error("Failure: " . $e->getMessage()); + } + } + } + + /** + * Update the index on the given store + * + * @param SolrIndex $instance Instance + * @param SolrConfigStore $store + */ + protected function updateIndex($instance, $store) + { + $index = $instance->getIndexName(); + $this->getLogger()->addInfo("Configuring $index."); + + // Upload the config files for this index + $this->getLogger()->addInfo("Uploading configuration ..."); + $instance->uploadConfig($store); + + // Then tell Solr to use those config files + $service = Solr::service(); + if ($service->coreIsActive($index)) { + $this->getLogger()->addInfo("Reloading core ..."); + $service->coreReload($index); + } else { + $this->getLogger()->addInfo("Creating core ..."); + $service->coreCreate($index, $store->instanceDir($index)); + } + + $this->getLogger()->addInfo("Done"); + } + + /** + * Get config store + * + * @return SolrConfigStore + */ + protected function getSolrConfigStore() + { + $options = Solr::solr_options(); + + if (!isset($options['indexstore']) || !($indexstore = $options['indexstore'])) { + throw new Exception('No index configuration for Solr provided', E_USER_ERROR); + } + + // Find the IndexStore handler, which will handle uploading config files to Solr + $mode = $indexstore['mode']; + + if ($mode == 'file') { + return new SolrConfigStore_File($indexstore); + } elseif ($mode == 'webdav') { + return new SolrConfigStore_WebDAV($indexstore); + } elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, 'SolrConfigStore')) { + return new $mode($indexstore); + } else { + user_error('Unknown Solr index mode '.$indexstore['mode'], E_USER_ERROR); + } + } +} \ No newline at end of file diff --git a/code/solr/tasks/Solr_Reindex.php b/code/solr/tasks/Solr_Reindex.php new file mode 100644 index 0000000..b4f614c --- /dev/null +++ b/code/solr/tasks/Solr_Reindex.php @@ -0,0 +1,148 @@ +get('SolrReindexImmediateHandler'); + } + + /** + * @param SS_HTTPRequest $request + */ + public function run($request) + { + parent::run($request); + + // Reset state + $originalState = SearchVariant::current_state(); + $this->doReindex($request); + SearchVariant::activate_state($originalState); + } + + /** + * @param SS_HTTPRequest $request + */ + protected function doReindex($request) + { + $class = $request->getVar('class'); + + $index = $request->getVar('index'); + + //find the index classname by IndexName + // this is for when index names do not match the class name (this can be done by overloading getIndexName() on + // indexes + if ($index && !ClassInfo::exists($index)) { + foreach(ClassInfo::subclassesFor('SolrIndex') as $solrIndexClass) { + $reflection = new ReflectionClass($solrIndexClass); + //skip over abstract classes + if (!$reflection->isInstantiable()) { + continue; + } + //check the indexname matches the index passed to the request + if (!strcasecmp(singleton($solrIndexClass)->getIndexName(), $index)) { + //if we match, set the correct index name and move on + $index = $solrIndexClass; + break; + } + } + } + + // Deprecated reindex mechanism + $start = $request->getVar('start'); + if ($start !== null) { + // Run single batch directly + $indexInstance = singleton($index); + $state = json_decode($request->getVar('variantstate'), true); + $this->runFrom($indexInstance, $class, $start, $state); + return; + } + + // Check if we are re-indexing a single group + // If not using queuedjobs, we need to invoke Solr_Reindex as a separate process + // Otherwise each group is processed via a SolrReindexGroupJob + $groups = $request->getVar('groups'); + + $handler = $this->getHandler(); + if ($groups) { + // Run grouped batches (id % groups = group) + $group = $request->getVar('group'); + $indexInstance = singleton($index); + $state = json_decode($request->getVar('variantstate'), true); + + $handler->runGroup($this->getLogger(), $indexInstance, $state, $class, $groups, $group); + return; + } + + // If run at the top level, delegate to appropriate handler + $self = get_class($this); + $handler->triggerReindex($this->getLogger(), $this->config()->recordsPerRequest, $self, $class); + } + + /** + * @deprecated since version 2.0.0 + */ + protected function runFrom($index, $class, $start, $variantstate) + { + DeprecationTest_Deprecation::notice('2.0.0', 'Solr_Reindex now uses a new grouping mechanism'); + + // Set time limit and state + increase_time_limit_to(); + SearchVariant::activate_state($variantstate); + + // Generate filtered list + $items = DataList::create($class) + ->limit($this->config()->recordsPerRequest, $start); + + // Add child filter + $classes = $index->getClasses(); + $options = $classes[$class]; + if (!$options['include_children']) { + $items = $items->filter('ClassName', $class); + } + + // Process selected records in this class + $this->getLogger()->info("Adding $class"); + foreach ($items->sort("ID") as $item) { + $this->getLogger()->debug($item->ID); + + // See SearchUpdater_ObjectHandler::triggerReindex + $item->triggerReindex(); + $item->destroy(); + } + + $this->getLogger()->info("Done"); + } +} From 0ebf6e62203629352960dc7b4ce9d664764be9f0 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Fri, 21 Apr 2017 13:18:37 +1200 Subject: [PATCH 12/63] Second push of Test changes + namespacing --- .../solr/reindex/handlers/SolrReindexBase.php | 4 + .../reindex/handlers/SolrReindexHandler.php | 3 + .../handlers/SolrReindexImmediateHandler.php | 3 + .../handlers/SolrReindexQueuedHandler.php | 3 + tests/Solr4ServiceTest.php | 18 +- .../Solr4ServiceTest_RecordingService.php | 19 ++ tests/SolrIndexSubsitesTest.php | 13 +- .../SolrIndexSubsitesTest.yml | 0 .../SolrIndexSubsitesTest_Index.php | 15 + tests/SolrIndexTest.php | 55 +--- .../SolrIndexTest_BoostedIndex.php | 22 ++ .../SolrIndexTest/SolrIndexTest_FakeIndex.php | 19 ++ .../SolrIndexTest_FakeIndex2.php | 23 ++ tests/SolrIndexVersionedTest.php | 68 +---- .../SolrDocumentMatcher.php | 39 +++ .../SolrIndexVersionedTest_Object.php | 22 ++ .../SolrVersionedTest_Index.php | 16 + tests/SolrReindexTest.php | 284 ------------------ .../SolrReindexTest_Handler.php | 39 +++ .../SolrReindexTest/SolrReindexTest_Index.php | 15 + .../SolrReindexTest/SolrReindexTest_Item.php | 21 ++ .../SolrReindexTest_ItemExtension.php | 29 ++ .../SolrReindexTest_RecordingLogger.php | 74 +++++ .../SolrReindexTest_TestHandler.php | 26 ++ .../SolrReindexTest_Variant.php | 117 ++++++++ 25 files changed, 523 insertions(+), 424 deletions(-) create mode 100644 tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php rename tests/{ => SolrIndexSubsitesTest}/SolrIndexSubsitesTest.yml (100%) create mode 100644 tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php create mode 100644 tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php create mode 100644 tests/SolrIndexTest/SolrIndexTest_FakeIndex.php create mode 100644 tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php create mode 100644 tests/SolrIndexVersionedTest/SolrDocumentMatcher.php create mode 100644 tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php create mode 100644 tests/SolrIndexVersionedTest/SolrVersionedTest_Index.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_Handler.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_Index.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_Item.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_ItemExtension.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_RecordingLogger.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_TestHandler.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_Variant.php diff --git a/code/solr/reindex/handlers/SolrReindexBase.php b/code/solr/reindex/handlers/SolrReindexBase.php index 5c67f35..f127537 100644 --- a/code/solr/reindex/handlers/SolrReindexBase.php +++ b/code/solr/reindex/handlers/SolrReindexBase.php @@ -1,6 +1,10 @@ setField('id', $id); $document->setField('title', "Item $id"); return $document; @@ -60,16 +63,3 @@ class Solr4ServiceTest extends SapphireTest ); } } - -class Solr4ServiceTest_RecordingService extends Solr4Service_Core -{ - protected function _sendRawPost($url, $rawPost, $timeout = false, $contentType = 'text/xml; charset=UTF-8') - { - return $rawPost; - } - - protected function _sendRawGet($url, $timeout = false) - { - return $url; - } -} diff --git a/tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php b/tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php new file mode 100644 index 0000000..3fd0adc --- /dev/null +++ b/tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php @@ -0,0 +1,19 @@ +addClass('File'); - $this->addClass('SiteTree'); - $this->addAllFulltextFields(); - } -} diff --git a/tests/SolrIndexSubsitesTest.yml b/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest.yml similarity index 100% rename from tests/SolrIndexSubsitesTest.yml rename to tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest.yml diff --git a/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php b/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php new file mode 100644 index 0000000..97e9dfb --- /dev/null +++ b/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php @@ -0,0 +1,15 @@ +addClass('File'); + $this->addClass('SiteTree'); + $this->addAllFulltextFields(); + } +} diff --git a/tests/SolrIndexTest.php b/tests/SolrIndexTest.php index e75b8e5..0a6b82f 100644 --- a/tests/SolrIndexTest.php +++ b/tests/SolrIndexTest.php @@ -1,6 +1,10 @@ addClass('SearchUpdaterTest_Container'); - - $this->addFilterField('Field1'); - $this->addFilterField('MyDate', 'Date'); - $this->addFilterField('HasOneObject.Field1'); - $this->addFilterField('HasManyObjects.Field1'); - $this->addFilterField('ManyManyObjects.Field1'); - } -} - - -class SolrIndexTest_FakeIndex2 extends SolrIndex -{ - protected function getStoredDefault() - { - // Override isDev defaulting to stored - return 'false'; - } - - public function init() - { - $this->addClass('SearchUpdaterTest_Container'); - $this->addFilterField('MyDate', 'Date'); - $this->addFilterField('HasOneObject.Field1'); - $this->addFilterField('HasManyObjects.Field1'); - $this->addFilterField('ManyManyObjects.Field1'); - } -} - - -class SolrIndexTest_BoostedIndex extends SolrIndex -{ - protected function getStoredDefault() - { - // Override isDev defaulting to stored - return 'false'; - } - - public function init() - { - $this->addClass('SearchUpdaterTest_Container'); - $this->addAllFulltextFields(); - $this->setFieldBoosting('SearchUpdaterTest_Container_Field1', 1.5); - $this->addBoostedField('Field2', null, array(), 2.1); - } -} diff --git a/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php b/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php new file mode 100644 index 0000000..65dae12 --- /dev/null +++ b/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php @@ -0,0 +1,22 @@ +addClass('SearchUpdaterTest_Container'); + $this->addAllFulltextFields(); + $this->setFieldBoosting('SearchUpdaterTest_Container_Field1', 1.5); + $this->addBoostedField('Field2', null, array(), 2.1); + } +} diff --git a/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php b/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php new file mode 100644 index 0000000..b04e6ce --- /dev/null +++ b/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php @@ -0,0 +1,19 @@ +addClass('SearchUpdaterTest_Container'); + + $this->addFilterField('Field1'); + $this->addFilterField('MyDate', 'Date'); + $this->addFilterField('HasOneObject.Field1'); + $this->addFilterField('HasManyObjects.Field1'); + $this->addFilterField('ManyManyObjects.Field1'); + } +} diff --git a/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php b/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php new file mode 100644 index 0000000..a9b58ac --- /dev/null +++ b/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php @@ -0,0 +1,23 @@ +addClass('SearchUpdaterTest_Container'); + $this->addFilterField('MyDate', 'Date'); + $this->addFilterField('HasOneObject.Field1'); + $this->addFilterField('HasManyObjects.Field1'); + $this->addFilterField('ManyManyObjects.Field1'); + } +} diff --git a/tests/SolrIndexVersionedTest.php b/tests/SolrIndexVersionedTest.php index 2c06ea5..4533576 100644 --- a/tests/SolrIndexVersionedTest.php +++ b/tests/SolrIndexVersionedTest.php @@ -1,8 +1,10 @@ deleteById($this->getExpectedDocumentId($id, 'Live')); } } - - -class SolrVersionedTest_Index extends SolrIndex -{ - public function init() - { - $this->addClass('SearchVariantVersionedTest_Item'); - $this->addClass('SolrIndexVersionedTest_Object'); - $this->addFilterField('TestText'); - $this->addFulltextField('Content'); - } -} - -/** - * Non-sitetree versioned dataobject - */ -class SolrIndexVersionedTest_Object extends DataObject implements TestOnly { - - private static $extensions = array( - 'Versioned' - ); - - private static $db = array( - 'Title' => 'Varchar', - 'Content' => 'Text', - 'TestText' => 'Varchar', - ); -} - -if (!class_exists('Phockito')) { - return; -} - -class SolrDocumentMatcher extends Hamcrest_BaseMatcher -{ - protected $properties; - - public function __construct($properties) - { - $this->properties = $properties; - } - - public function describeTo(\Hamcrest_Description $description) - { - $description->appendText('Apache_Solr_Document with properties '.var_export($this->properties, true)); - } - - public function matches($item) - { - if (! ($item instanceof Apache_Solr_Document)) { - return false; - } - - foreach ($this->properties as $key => $value) { - if ($item->{$key} != $value) { - return false; - } - } - - return true; - } -} diff --git a/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php b/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php new file mode 100644 index 0000000..5c9298e --- /dev/null +++ b/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php @@ -0,0 +1,39 @@ +properties = $properties; + } + + public function describeTo(\Hamcrest_Description $description) + { + $description->appendText('Apache_Solr_Document with properties '.var_export($this->properties, true)); + } + + public function matches($item) + { + if (! ($item instanceof Apache_Solr_Document)) { + return false; + } + + foreach ($this->properties as $key => $value) { + if ($item->{$key} != $value) { + return false; + } + } + + return true; + } +} diff --git a/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php b/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php new file mode 100644 index 0000000..919d573 --- /dev/null +++ b/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php @@ -0,0 +1,22 @@ + 'Varchar', + 'Content' => 'Text', + 'TestText' => 'Varchar', + ); +} diff --git a/tests/SolrIndexVersionedTest/SolrVersionedTest_Index.php b/tests/SolrIndexVersionedTest/SolrVersionedTest_Index.php new file mode 100644 index 0000000..7ac3a5b --- /dev/null +++ b/tests/SolrIndexVersionedTest/SolrVersionedTest_Index.php @@ -0,0 +1,16 @@ +addClass('SearchVariantVersionedTest_Item'); + $this->addClass('SolrIndexVersionedTest_Object'); + $this->addFilterField('TestText'); + $this->addFulltextField('Content'); + } +} diff --git a/tests/SolrReindexTest.php b/tests/SolrReindexTest.php index 5f696fb..a740edf 100644 --- a/tests/SolrReindexTest.php +++ b/tests/SolrReindexTest.php @@ -1,13 +1,6 @@ getIndexName(); - $stateName = json_encode($state); - $logger->info("Called processGroup with {$indexName}, {$stateName}, {$class}, group {$group} of {$groups}"); - } - - public function triggerReindex(LoggerInterface $logger, $batchSize, $taskName, $classes = null) - { - $logger->info("Called triggerReindex"); - } -} - - -class SolrReindexTest_Index extends SolrIndex implements TestOnly -{ - public function init() - { - $this->addClass('SolrReindexTest_Item'); - $this->addAllFulltextFields(); - } -} - -/** - * Does not have any variant extensions - */ -class SolrReindexTest_Item extends DataObject implements TestOnly -{ - private static $extensions = array( - 'SolrReindexTest_ItemExtension' - ); - - private static $db = array( - 'Title' => 'Varchar(255)', - 'Variant' => 'Int(0)' - ); -} - -/** - * Select only records in the current variant - */ -class SolrReindexTest_ItemExtension extends DataExtension implements TestOnly -{ - /** - * Filter records on the current variant - * - * @param SQLQuery $query - * @param DataQuery $dataQuery - */ - public function augmentSQL(SilverStripe\ORM\Queries\SQLSelect $query, SilverStripe\ORM\DataQuery $dataQuery = NULL) - { - $variant = SolrReindexTest_Variant::get_current(); - if ($variant !== null && !$query->filtersOnID()) { - $sqlVariant = Convert::raw2sql($variant); - $query->addWhere("\"Variant\" = '{$sqlVariant}'"); - } - } -} - - -/** - * Dummy variant that selects items with field Varient matching the current value - * - * Variant states are 0 and 1, or null if disabled - */ -class SolrReindexTest_Variant extends SearchVariant implements TestOnly -{ - /** - * Value of this variant (either null, 0, or 1) - * - * @var int|null - */ - protected static $current = null; - - /** - * Activate this variant - */ - public static function enable() - { - self::disable(); - - self::$current = 0; - self::$variants = array( - 'SolrReindexTest_Variant' => singleton('SolrReindexTest_Variant') - ); - } - - /** - * Disable this variant and reset - */ - public static function disable() - { - self::$current = null; - self::$variants = null; - self::$class_variants = array(); - self::$call_instances = array(); - } - - public function activateState($state) - { - self::set_current($state); - } - - /** - * Set the current variant to the given state - * - * @param int $current 0, 1, 2, or null (disabled) - */ - public static function set_current($current) - { - self::$current = $current; - } - - /** - * Get the current state - * - * @return string|null - */ - public static function get_current() - { - // Always use string values for states for consistent json_encode value - if (isset(self::$current)) { - return (string)self::$current; - } - } - - public function alterDefinition($class, $index) - { - $self = get_class($this); - - $this->addFilterField($index, '_testvariant', array( - 'name' => '_testvariant', - 'field' => '_testvariant', - 'fullfield' => '_testvariant', - 'base' => ClassInfo::baseDataClass($class), - 'origin' => $class, - 'type' => 'Int', - 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) - )); - } - - public function alterQuery($query, $index) - { - // I guess just calling it _testvariant is ok? - $query->filter('_testvariant', $this->currentState()); - } - - public function appliesTo($class, $includeSubclasses) - { - return $class === 'SolrReindexTest_Item' || - ($includeSubclasses && is_subclass_of($class, 'SolrReindexTest_Item', true)); - } - - public function appliesToEnvironment() - { - // Set to null to disable - return self::$current !== null; - } - - public function currentState() - { - return self::get_current(); - } - - public function reindexStates() - { - // Always use string values for states for consistent json_encode value - return array('0', '1', '2'); - } -} - -/** - * Test logger for recording messages - */ -class SolrReindexTest_RecordingLogger extends Logger implements TestOnly -{ - /** - * @var SolrReindexTest_Handler - */ - protected $testHandler = null; - - public function __construct($name = 'testlogger', array $handlers = array(), array $processors = array()) - { - parent::__construct($name, $handlers, $processors); - - $this->testHandler = new SolrReindexTest_Handler(); - $this->pushHandler($this->testHandler); - } - - /** - * @return array - */ - public function getMessages() - { - return $this->testHandler->getMessages(); - } - - /** - * Clear all messages - */ - public function clear() - { - $this->testHandler->clear(); - } - - /** - * Get messages with the given filter - * - * @param string $containing - * @return array Filtered array - */ - public function filterMessages($containing) - { - return array_values(array_filter( - $this->getMessages(), - function ($content) use ($containing) { - return stripos($content, $containing) !== false; - } - )); - } - - /** - * Count all messages containing the given substring - * - * @param string $containing Message to filter by - * @return int - */ - public function countMessages($containing = null) - { - if ($containing) { - $messages = $this->filterMessages($containing); - } else { - $messages = $this->getMessages(); - } - return count($messages); - } -} - -/** - * Logger for recording messages for later retrieval - */ -class SolrReindexTest_Handler extends AbstractProcessingHandler implements TestOnly -{ - /** - * Messages - * - * @var array - */ - protected $messages = array(); - - /** - * Get all messages - * - * @return array - */ - public function getMessages() - { - return $this->messages; - } - - public function clear() - { - $this->messages = array(); - } - - protected function write(array $record) - { - $this->messages[] = $record['message']; - } -} diff --git a/tests/SolrReindexTest/SolrReindexTest_Handler.php b/tests/SolrReindexTest/SolrReindexTest_Handler.php new file mode 100644 index 0000000..ea29bcd --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_Handler.php @@ -0,0 +1,39 @@ +messages; + } + + public function clear() + { + $this->messages = array(); + } + + protected function write(array $record) + { + $this->messages[] = $record['message']; + } +} diff --git a/tests/SolrReindexTest/SolrReindexTest_Index.php b/tests/SolrReindexTest/SolrReindexTest_Index.php new file mode 100644 index 0000000..64e85b2 --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_Index.php @@ -0,0 +1,15 @@ +addClass('SolrReindexTest_Item'); + $this->addAllFulltextFields(); + } +} diff --git a/tests/SolrReindexTest/SolrReindexTest_Item.php b/tests/SolrReindexTest/SolrReindexTest_Item.php new file mode 100644 index 0000000..a77343a --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_Item.php @@ -0,0 +1,21 @@ + 'Varchar(255)', + 'Variant' => 'Int(0)' + ); +} diff --git a/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php b/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php new file mode 100644 index 0000000..8306d5d --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php @@ -0,0 +1,29 @@ +filtersOnID()) { + $sqlVariant = Convert::raw2sql($variant); + $query->addWhere("\"Variant\" = '{$sqlVariant}'"); + } + } +} diff --git a/tests/SolrReindexTest/SolrReindexTest_RecordingLogger.php b/tests/SolrReindexTest/SolrReindexTest_RecordingLogger.php new file mode 100644 index 0000000..3606e02 --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_RecordingLogger.php @@ -0,0 +1,74 @@ +testHandler = new SolrReindexTest_Handler(); + $this->pushHandler($this->testHandler); + } + + /** + * @return array + */ + public function getMessages() + { + return $this->testHandler->getMessages(); + } + + /** + * Clear all messages + */ + public function clear() + { + $this->testHandler->clear(); + } + + /** + * Get messages with the given filter + * + * @param string $containing + * @return array Filtered array + */ + public function filterMessages($containing) + { + return array_values(array_filter( + $this->getMessages(), + function ($content) use ($containing) { + return stripos($content, $containing) !== false; + } + )); + } + + /** + * Count all messages containing the given substring + * + * @param string $containing Message to filter by + * @return int + */ + public function countMessages($containing = null) + { + if ($containing) { + $messages = $this->filterMessages($containing); + } else { + $messages = $this->getMessages(); + } + return count($messages); + } +} diff --git a/tests/SolrReindexTest/SolrReindexTest_TestHandler.php b/tests/SolrReindexTest/SolrReindexTest_TestHandler.php new file mode 100644 index 0000000..fd86b88 --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_TestHandler.php @@ -0,0 +1,26 @@ +getIndexName(); + $stateName = json_encode($state); + $logger->info("Called processGroup with {$indexName}, {$stateName}, {$class}, group {$group} of {$groups}"); + } + + public function triggerReindex(LoggerInterface $logger, $batchSize, $taskName, $classes = null) + { + $logger->info("Called triggerReindex"); + } +} diff --git a/tests/SolrReindexTest/SolrReindexTest_Variant.php b/tests/SolrReindexTest/SolrReindexTest_Variant.php new file mode 100644 index 0000000..038c4cc --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_Variant.php @@ -0,0 +1,117 @@ + singleton('SolrReindexTest_Variant') + ); + } + + /** + * Disable this variant and reset + */ + public static function disable() + { + self::$current = null; + self::$variants = null; + self::$class_variants = array(); + self::$call_instances = array(); + } + + public function activateState($state) + { + self::set_current($state); + } + + /** + * Set the current variant to the given state + * + * @param int $current 0, 1, 2, or null (disabled) + */ + public static function set_current($current) + { + self::$current = $current; + } + + /** + * Get the current state + * + * @return string|null + */ + public static function get_current() + { + // Always use string values for states for consistent json_encode value + if (isset(self::$current)) { + return (string)self::$current; + } + } + + public function alterDefinition($class, $index) + { + $self = get_class($this); + + $this->addFilterField($index, '_testvariant', array( + 'name' => '_testvariant', + 'field' => '_testvariant', + 'fullfield' => '_testvariant', + 'base' => ClassInfo::baseDataClass($class), + 'origin' => $class, + 'type' => 'Int', + 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) + )); + } + + public function alterQuery($query, $index) + { + // I guess just calling it _testvariant is ok? + $query->filter('_testvariant', $this->currentState()); + } + + public function appliesTo($class, $includeSubclasses) + { + return $class === 'SolrReindexTest_Item' || + ($includeSubclasses && is_subclass_of($class, 'SolrReindexTest_Item', true)); + } + + public function appliesToEnvironment() + { + // Set to null to disable + return self::$current !== null; + } + + public function currentState() + { + return self::get_current(); + } + + public function reindexStates() + { + // Always use string values for states for consistent json_encode value + return array('0', '1', '2'); + } +} From 0ee34e49e262e2b083199c996c51003dfbc6036d Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Fri, 21 Apr 2017 13:26:07 +1200 Subject: [PATCH 13/63] Fix PHP errors in test --- tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php | 2 +- tests/SolrReindexQueuedTest.php | 3 +++ tests/SolrReindexTest.php | 3 +++ tests/SolrReindexTest/SolrReindexTest_ItemExtension.php | 4 +++- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php b/tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php index 3fd0adc..480ab1b 100644 --- a/tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php +++ b/tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php @@ -2,7 +2,7 @@ namespace SilverStripe\FullTextSearch\Tests\Solr4ServiceTest; -use SilverStripe\FullTextSearch\Solr\Solr4Service_Core; +use SilverStripe\FullTextSearch\Solr\Services\Solr4Service_Core; class Solr4ServiceTest_RecordingService extends Solr4Service_Core { diff --git a/tests/SolrReindexQueuedTest.php b/tests/SolrReindexQueuedTest.php index 3eb5c89..ed7aa0c 100644 --- a/tests/SolrReindexQueuedTest.php +++ b/tests/SolrReindexQueuedTest.php @@ -2,6 +2,9 @@ use SilverStripe\Dev\SapphireTest; +use SilverStripe\FullTextSearch\Search\FullTextSearch; +use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Variant; + /** * Additional tests of solr reindexing processes when run with queuedjobs */ diff --git a/tests/SolrReindexTest.php b/tests/SolrReindexTest.php index a740edf..1c2c2a6 100644 --- a/tests/SolrReindexTest.php +++ b/tests/SolrReindexTest.php @@ -2,6 +2,9 @@ use SilverStripe\Dev\SapphireTest; +use SilverStripe\FullTextSearch\Search\FullTextSearch; +use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Variant; + if (class_exists('Phockito')) { Phockito::include_hamcrest(false); } diff --git a/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php b/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php index 8306d5d..9981932 100644 --- a/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php +++ b/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php @@ -4,6 +4,8 @@ namespace SilverStripe\FullTextSearch\Tests\SolrReindexTest; use SilverStripe\ORM\DataExtension; use SilverStripe\Dev\TestOnly; +use SilverStripe\ORM\Queries\SQLSelect; +use SilverStripe\ORM\DataQuery; use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Variant; use SilverStripe\Core\Convert; @@ -18,7 +20,7 @@ class SolrReindexTest_ItemExtension extends DataExtension implements TestOnly * @param SQLQuery $query * @param DataQuery $dataQuery */ - public function augmentSQL(SilverStripe\ORM\Queries\SQLSelect $query, SilverStripe\ORM\DataQuery $dataQuery = NULL) + public function augmentSQL(SQLSelect $query, DataQuery $dataQuery = NULL) { $variant = SolrReindexTest_Variant::get_current(); if ($variant !== null && !$query->filtersOnID()) { From 13bef6eb0d7d02d5558520171c5d32ee79b2c282 Mon Sep 17 00:00:00 2001 From: elliot sawyer Date: Fri, 21 Apr 2017 13:26:24 +1200 Subject: [PATCH 14/63] break out search components with multiple classes into individual files and change namespaces --- code/search/{ => indexes}/SearchIndex.php | 2 +- .../search/{ => indexes}/SearchIndex_Null.php | 4 +- .../{ => indexes}/SearchIndex_Recording.php | 4 +- code/search/{ => queries}/SearchQuery.php | 31 +------ code/search/queries/SearchQuery_Range.php | 34 ++++++++ code/search/{ => updaters}/SearchUpdater.php | 80 +------------------ ...hUpdater_BindManipulationCaptureFilter.php | 23 ++++++ .../updaters/SearchUpdater_ObjectHandler.php | 66 +++++++++++++++ code/search/{ => variants}/SearchVariant.php | 30 +------ .../SearchVariantSiteTreeSubsitesPolyhome.php | 2 +- .../{ => variants}/SearchVariantSubsites.php | 2 +- .../{ => variants}/SearchVariantVersioned.php | 3 +- code/search/variants/SearchVariant_Caller.php | 38 +++++++++ code/solr/SolrIndex.php | 2 +- 14 files changed, 174 insertions(+), 147 deletions(-) rename code/search/{ => indexes}/SearchIndex.php (99%) rename code/search/{ => indexes}/SearchIndex_Null.php (70%) rename code/search/{ => indexes}/SearchIndex_Recording.php (93%) rename code/search/{ => queries}/SearchQuery.php (85%) create mode 100644 code/search/queries/SearchQuery_Range.php rename code/search/{ => updaters}/SearchUpdater.php (77%) create mode 100644 code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php create mode 100644 code/search/updaters/SearchUpdater_ObjectHandler.php rename code/search/{ => variants}/SearchVariant.php (91%) rename code/search/{ => variants}/SearchVariantSiteTreeSubsitesPolyhome.php (98%) rename code/search/{ => variants}/SearchVariantSubsites.php (98%) rename code/search/{ => variants}/SearchVariantVersioned.php (97%) create mode 100644 code/search/variants/SearchVariant_Caller.php diff --git a/code/search/SearchIndex.php b/code/search/indexes/SearchIndex.php similarity index 99% rename from code/search/SearchIndex.php rename to code/search/indexes/SearchIndex.php index f4dc86a..04d3136 100644 --- a/code/search/SearchIndex.php +++ b/code/search/indexes/SearchIndex.php @@ -1,6 +1,6 @@ start = $start; - $this->end = $end; - } - - public function start($start) - { - $this->start = $start; - } - - public function end($end) - { - $this->end = $end; - } - - public function isfiltered() - { - return $this->start !== null || $this->end !== null; - } -} diff --git a/code/search/queries/SearchQuery_Range.php b/code/search/queries/SearchQuery_Range.php new file mode 100644 index 0000000..33b35e5 --- /dev/null +++ b/code/search/queries/SearchQuery_Range.php @@ -0,0 +1,34 @@ +start = $start; + $this->end = $end; + } + + public function start($start) + { + $this->start = $start; + } + + public function end($end) + { + $this->end = $end; + } + + public function isfiltered() + { + return $this->start !== null || $this->end !== null; + } +} \ No newline at end of file diff --git a/code/search/SearchUpdater.php b/code/search/updaters/SearchUpdater.php similarity index 77% rename from code/search/SearchUpdater.php rename to code/search/updaters/SearchUpdater.php index b1fa58d..90a1500 100644 --- a/code/search/SearchUpdater.php +++ b/code/search/updaters/SearchUpdater.php @@ -1,5 +1,5 @@ owner->ID) { - return; - } - - // Force SearchUpdater to mark this record as dirty - $manipulation = array( - $this->owner->ClassName => array( - 'fields' => array(), - 'id' => $this->owner->ID, - 'command' => 'update' - ) - ); - $this->owner->extend('augmentWrite', $manipulation); - SearchUpdater::handle_manipulation($manipulation); - } - - /** - * Forces this object to trigger a re-index in the current state - */ - public function triggerReindex() - { - if (!$this->owner->ID) { - return; - } - - $id = $this->owner->ID; - $class = $this->owner->ClassName; - $state = SearchVariant::current_state($class); - $base = ClassInfo::baseDataClass($class); - $key = "$id:$base:".serialize($state); - - $statefulids = array(array( - 'id' => $id, - 'state' => $state - )); - - $writes = array( - $key => array( - 'base' => $base, - 'class' => $class, - 'id' => $id, - 'statefulids' => $statefulids, - 'fields' => array() - ) - ); - - SearchUpdater::process_writes($writes); - } -} diff --git a/code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php b/code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php new file mode 100644 index 0000000..e6b4e05 --- /dev/null +++ b/code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php @@ -0,0 +1,23 @@ +owner->ID) { + return; + } + + // Force SearchUpdater to mark this record as dirty + $manipulation = array( + $this->owner->ClassName => array( + 'fields' => array(), + 'id' => $this->owner->ID, + 'command' => 'update' + ) + ); + $this->owner->extend('augmentWrite', $manipulation); + SearchUpdater::handle_manipulation($manipulation); + } + + /** + * Forces this object to trigger a re-index in the current state + */ + public function triggerReindex() + { + if (!$this->owner->ID) { + return; + } + + $id = $this->owner->ID; + $class = $this->owner->ClassName; + $state = SearchVariant::current_state($class); + $base = ClassInfo::baseDataClass($class); + $key = "$id:$base:".serialize($state); + + $statefulids = array(array( + 'id' => $id, + 'state' => $state + )); + + $writes = array( + $key => array( + 'base' => $base, + 'class' => $class, + 'id' => $id, + 'statefulids' => $statefulids, + 'fields' => array() + ) + ); + + SearchUpdater::process_writes($writes); + } +} \ No newline at end of file diff --git a/code/search/SearchVariant.php b/code/search/variants/SearchVariant.php similarity index 91% rename from code/search/SearchVariant.php rename to code/search/variants/SearchVariant.php index f8a68ad..57f6479 100644 --- a/code/search/SearchVariant.php +++ b/code/search/variants/SearchVariant.php @@ -1,5 +1,5 @@ variants = $variants; - } - - public function call($method, &$a1=null, &$a2=null, &$a3=null, &$a4=null, &$a5=null, &$a6=null, &$a7=null) - { - $values = array(); - - foreach ($this->variants as $variant) { - if (method_exists($variant, $method)) { - $value = $variant->$method($a1, $a2, $a3, $a4, $a5, $a6, $a7); - if ($value !== null) { - $values[] = $value; - } - } - } - - return $values; - } -} diff --git a/code/search/SearchVariantSiteTreeSubsitesPolyhome.php b/code/search/variants/SearchVariantSiteTreeSubsitesPolyhome.php similarity index 98% rename from code/search/SearchVariantSiteTreeSubsitesPolyhome.php rename to code/search/variants/SearchVariantSiteTreeSubsitesPolyhome.php index 100788a..5101dd1 100644 --- a/code/search/SearchVariantSiteTreeSubsitesPolyhome.php +++ b/code/search/variants/SearchVariantSiteTreeSubsitesPolyhome.php @@ -1,5 +1,5 @@ variants = $variants; + } + + public function call($method, &$a1=null, &$a2=null, &$a3=null, &$a4=null, &$a5=null, &$a6=null, &$a7=null) + { + $values = array(); + + foreach ($this->variants as $variant) { + if (method_exists($variant, $method)) { + $value = $variant->$method($a1, $a2, $a3, $a4, $a5, $a6, $a7); + if ($value !== null) { + $values[] = $value; + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index 2a7f655..76842a2 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -3,7 +3,7 @@ namespace SilverStripe\FullTextSearch\Solr; Solr::include_client_api(); use SilverStripe\Control\Director; -use SilverStripe\FulltextSearch\Search\SearchIndex; +use SilverStripe\FulltextSearch\Search\Indexes\SearchIndex; abstract class SolrIndex extends SearchIndex { From 6a2a4a8dd2162c449d92aafe32c57494ba449a66 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Fri, 21 Apr 2017 13:32:39 +1200 Subject: [PATCH 15/63] Update namespacing for Search indexes and variants in tests --- tests/BatchedProcessorTest/BatchedProcessorTest_Index.php | 2 +- tests/SearchUpdaterTest.php | 2 +- tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php | 2 +- tests/SearchVariantVersionedTest.php | 2 +- tests/SolrReindexTest/SolrReindexTest_Variant.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php b/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php index c62ea6b..7116af1 100644 --- a/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php +++ b/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php @@ -3,7 +3,7 @@ namespace SilverStripe\FullTextSearch\Tests\BatchedProcessorTest; use SilverStripe\Dev\TestOnly; -use SilverStripe\FullTextSearch\Search\SearchIndex_Recording; +use SilverStripe\FullTextSearch\Search\Indexes\SearchIndex_Recording; class BatchedProcessorTest_Index extends SearchIndex_Recording implements TestOnly { diff --git a/tests/SearchUpdaterTest.php b/tests/SearchUpdaterTest.php index 9cbb9c8..cb8142a 100644 --- a/tests/SearchUpdaterTest.php +++ b/tests/SearchUpdaterTest.php @@ -1,7 +1,7 @@ Date: Fri, 21 Apr 2017 14:14:30 +1200 Subject: [PATCH 16/63] Batch fixes for tests #2 --- code/search/SearchIntrospection.php | 7 ++++++- code/search/indexes/SearchIndex.php | 11 +++++++---- code/search/updaters/SearchUpdater.php | 3 +++ tests/SearchUpdaterTest.php | 1 + .../SolrIndexVersionedTest_Object.php | 11 ++++++----- tests/SolrReindexTest/SolrReindexTest_Item.php | 7 ++++--- 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/code/search/SearchIntrospection.php b/code/search/SearchIntrospection.php index 6305e43..67de910 100644 --- a/code/search/SearchIntrospection.php +++ b/code/search/SearchIntrospection.php @@ -43,7 +43,12 @@ class SearchIntrospection $classes = array_unique(array_merge($classes, array_values(ClassInfo::subclassesFor($class)))); } - $idx = array_search('DataObject', $classes); + $idx = array_search('SilverStripe\View\ViewableData', $classes); + if ($idx !== false) { + array_splice($classes, 0, $idx+1); + } + + $idx = array_search('SilverStripe\Core\Object', $classes); if ($idx !== false) { array_splice($classes, 0, $idx+1); } diff --git a/code/search/indexes/SearchIndex.php b/code/search/indexes/SearchIndex.php index 04d3136..2e1750d 100644 --- a/code/search/indexes/SearchIndex.php +++ b/code/search/indexes/SearchIndex.php @@ -7,6 +7,9 @@ use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObjectSchema; use SilverStripe\Core\Object; use SilverStripe\Core\ClassInfo; +use SilverStripe\FullTextSearch\Search\SearchIntrospection; +use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; +use SilverStripe\FullTextSearch\Utils\MultipleArrayIterator; /** * SearchIndex is the base index class. Each connector will provide a subclass of this that * provides search engine specific behavior. @@ -90,20 +93,20 @@ abstract class SearchIndex extends ViewableData foreach (SearchIntrospection::hierarchy($source, $options['include_children']) as $dataclass) { $singleton = singleton($dataclass); - if ($hasOne = $singleton->has_one($lookup)) { + if ($hasOne = $singleton->hasOne($lookup)) { $class = $hasOne; $options['lookup_chain'][] = array( 'call' => 'method', 'method' => $lookup, 'through' => 'has_one', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => "{$lookup}ID" ); - } elseif ($hasMany = $singleton->has_many($lookup)) { + } elseif ($hasMany = $singleton->hasMany($lookup)) { $class = $hasMany; $options['multi_valued'] = true; $options['lookup_chain'][] = array( 'call' => 'method', 'method' => $lookup, 'through' => 'has_many', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => $singleton->getRemoteJoinField($lookup, 'has_many') ); - } elseif ($manyMany = $singleton->many_many($lookup)) { + } elseif ($manyMany = $singleton->manyMany($lookup)) { $class = $manyMany[1]; $options['multi_valued'] = true; $options['lookup_chain'][] = array( @@ -112,7 +115,7 @@ abstract class SearchIndex extends ViewableData ); } - if ($class) { + if (is_string($class) && $class) { if (!isset($options['origin'])) { $options['origin'] = $dataclass; } diff --git a/code/search/updaters/SearchUpdater.php b/code/search/updaters/SearchUpdater.php index 90a1500..b4460c3 100644 --- a/code/search/updaters/SearchUpdater.php +++ b/code/search/updaters/SearchUpdater.php @@ -1,5 +1,8 @@ 'Varchar', 'Content' => 'Text', 'TestText' => 'Varchar', - ); + ]; } diff --git a/tests/SolrReindexTest/SolrReindexTest_Item.php b/tests/SolrReindexTest/SolrReindexTest_Item.php index a77343a..6a08387 100644 --- a/tests/SolrReindexTest/SolrReindexTest_Item.php +++ b/tests/SolrReindexTest/SolrReindexTest_Item.php @@ -4,15 +4,16 @@ namespace SilverStripe\FullTextSearch\Tests\SolrReindexTest; use SilverStripe\Dev\TestOnly; use SilverStripe\ORM\DataObject; +use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_ItemExtension; /** * Does not have any variant extensions */ class SolrReindexTest_Item extends DataObject implements TestOnly { - private static $extensions = array( - 'SolrReindexTest_ItemExtension' - ); + private static $extensions = [ + SolrReindexTest_ItemExtension::class + ]; private static $db = array( 'Title' => 'Varchar(255)', From 62ba5315435ae82ec7a53e1bd96e09fe2013e477 Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Fri, 21 Apr 2017 16:32:03 +1200 Subject: [PATCH 17/63] Update _config.php to use namespace --- _config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_config.php b/_config.php index 3a5121a..a1de033 100644 --- a/_config.php +++ b/_config.php @@ -1,4 +1,4 @@ Date: Fri, 21 Apr 2017 16:32:47 +1200 Subject: [PATCH 18/63] Use root namespace in referencing Apache_Solr_Document --- code/solr/services/Solr4Service_Core.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/solr/services/Solr4Service_Core.php b/code/solr/services/Solr4Service_Core.php index 48b8285..bdde99a 100644 --- a/code/solr/services/Solr4Service_Core.php +++ b/code/solr/services/Solr4Service_Core.php @@ -25,7 +25,7 @@ class Solr4Service_Core extends SolrService_Core * @inheritdoc * @see Solr4Service_Core::addDocuments */ - public function addDocument(Apache_Solr_Document $document, $allowDups = false, + public function addDocument(\Apache_Solr_Document $document, $allowDups = false, $overwritePending = true, $overwriteCommitted = true, $commitWithin = 0 ) { return $this->addDocuments(array($document), $allowDups, $overwritePending, $overwriteCommitted, $commitWithin); @@ -52,4 +52,4 @@ class Solr4Service_Core extends SolrService_Core return $this->add($rawPost); } -} \ No newline at end of file +} From 6066af5841fd1df21ef32ff3fa089c6e48ea4f26 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Fri, 21 Apr 2017 16:34:04 +1200 Subject: [PATCH 19/63] Update Search Manipulater --- _config/config.yml | 3 + .../SearchManipulateCapture_MySQLDatabase.php | 17 ++++ .../SearchUpdateImmediateProcessor.php | 2 + .../processors/SearchUpdateProcessor.php | 8 +- code/search/updaters/SearchUpdater.php | 48 +++++------ tests/SearchUpdaterTest.php | 80 ++----------------- .../SearchUpdaterTest_Container.php | 31 +++++++ .../SearchUpdaterTest_HasMany.php | 20 +++++ .../SearchUpdaterTest_HasOne.php | 20 +++++ .../SearchUpdaterTest_Index.php | 17 ++++ .../SearchUpdaterTest_ManyMany.php | 20 +++++ tests/SolrIndexTest.php | 2 +- 12 files changed, 164 insertions(+), 104 deletions(-) create mode 100644 code/search/captures/SearchManipulateCapture_MySQLDatabase.php create mode 100644 tests/SearchUpdaterTest/SearchUpdaterTest_Container.php create mode 100644 tests/SearchUpdaterTest/SearchUpdaterTest_HasMany.php create mode 100644 tests/SearchUpdaterTest/SearchUpdaterTest_HasOne.php create mode 100644 tests/SearchUpdaterTest/SearchUpdaterTest_Index.php create mode 100644 tests/SearchUpdaterTest/SearchUpdaterTest_ManyMany.php diff --git a/_config/config.yml b/_config/config.yml index 7193cb2..0c6c2ab 100644 --- a/_config/config.yml +++ b/_config/config.yml @@ -1,3 +1,6 @@ DataObject: extensions: - 'SearchUpdater_ObjectHandler' +Database: + extensions: + - 'SearchManipulateCaptureExtension' diff --git a/code/search/captures/SearchManipulateCapture_MySQLDatabase.php b/code/search/captures/SearchManipulateCapture_MySQLDatabase.php new file mode 100644 index 0000000..f1b9296 --- /dev/null +++ b/code/search/captures/SearchManipulateCapture_MySQLDatabase.php @@ -0,0 +1,17 @@ +baseDataClass($class); $forclass = isset($this->dirty[$base]) ? $this->dirty[$base] : array(); foreach ($statefulids as $statefulid) { diff --git a/code/search/updaters/SearchUpdater.php b/code/search/updaters/SearchUpdater.php index b4460c3..9beb6ee 100644 --- a/code/search/updaters/SearchUpdater.php +++ b/code/search/updaters/SearchUpdater.php @@ -3,6 +3,14 @@ namespace SilverStripe\FullTextSearch\Search\Updaters; use SilverStripe\ORM\DB; +use SilverStripe\Core\Object; +use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; +use SilverStripe\ORM\DataObject; +use SilverStripe\FullTextSearch\Search\FullTextSearch; +use SilverStripe\FullTextSearch\Search\SearchIntrospection; +use SilverStripe\Core\Injector\Injector; +use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateImmediateProcessor; +use SilverStripe\FullTextSearch\Captures\SearchManipulateCapture_MySQLDatabase; /** * This class is responsible for capturing changes to DataObjects and triggering index updates of the resulting dirty index * items. @@ -15,8 +23,6 @@ use SilverStripe\ORM\DB; * * TODO: The way we bind in is awful hacky. */ -use SilverStripe\Core\Object; -use SilverStripe\ORM\DataExtension; class SearchUpdater extends Object { @@ -27,31 +33,13 @@ class SearchUpdater extends Object { global $databaseConfig; - $current = DB::getConn(); - if (!$current || !$current->currentDatabase() || @$current->isManipulationCapture) { + $current = DB::get_conn(); + if (!$current || !$current->getSelectedDatabase() || @$current->isManipulationCapture) { return; } // If not yet set, or its already captured, just return - $type = get_class($current); - $file = TEMP_FOLDER."/.cache.SMC.$type"; - - if (!is_file($file)) { - file_put_contents($file, "selectDatabase($current->currentDatabase()); - DB::setConn($captured); + $captured->selectDatabase($current->getSelectedDatabase()); + DB::set_conn($captured); } public static $registered = false; @@ -85,7 +73,9 @@ class SearchUpdater extends Object { // First, extract any state that is in the manipulation itself foreach ($manipulation as $table => $details) { - $manipulation[$table]['class'] = $table; + if (!isset($manipulation[$table]['class'])) { + $manipulation[$table]['class'] = DataObject::getSchema()->tableClass($table); + } $manipulation[$table]['state'] = array(); } @@ -105,7 +95,7 @@ class SearchUpdater extends Object $class = $details['class']; $fields = isset($details['fields']) ? $details['fields'] : array(); - $base = ClassInfo::baseDataClass($class); + $base = DataObject::getSchema()->baseDataClass($class); $key = "$id:$base:".serialize($state); $statefulids = array(array('id' => $id, 'state' => $state)); @@ -166,7 +156,7 @@ class SearchUpdater extends Object foreach ($dirtyids as $dirtyclass => $ids) { if ($ids) { if (!self::$processor) { - self::$processor = Injector::inst()->create('SearchUpdateProcessor'); + self::$processor = Injector::inst()->create(SearchUpdateImmediateProcessor::class); } self::$processor->addDirtyIDs($dirtyclass, $ids, $index); } @@ -182,7 +172,7 @@ class SearchUpdater extends Object $runningTests = class_exists('SapphireTest', false) && SapphireTest::is_running_test(); if (self::$processor && !self::$registered && !$runningTests) { - register_shutdown_function(array("SearchUpdater", "flush_dirty_indexes")); + register_shutdown_function(array(SearchUpdater::class, "flush_dirty_indexes")); self::$registered = true; } } diff --git a/tests/SearchUpdaterTest.php b/tests/SearchUpdaterTest.php index ee2df21..000283c 100644 --- a/tests/SearchUpdaterTest.php +++ b/tests/SearchUpdaterTest.php @@ -1,78 +1,13 @@ 'Varchar', - 'Field2' => 'Varchar', - 'MyDate' => 'Date', - ); - - private static $has_one = array( - 'HasOneObject' => 'SearchUpdaterTest_HasOne' - ); - - private static $has_many = array( - 'HasManyObjects' => 'SearchUpdaterTest_HasMany' - ); - - private static $many_many = array( - 'ManyManyObjects' => 'SearchUpdaterTest_ManyMany' - ); -} - -class SearchUpdaterTest_HasOne extends DataObject -{ - private static $db = array( - 'Field1' => 'Varchar', - 'Field2' => 'Varchar' - ); - - private static $has_many = array( - 'HasManyContainers' => 'SearchUpdaterTest_Container' - ); -} - -class SearchUpdaterTest_HasMany extends DataObject -{ - private static $db = array( - 'Field1' => 'Varchar', - 'Field2' => 'Varchar' - ); - - private static $has_one = array( - 'HasManyContainer' => 'SearchUpdaterTest_Container' - ); -} - -class SearchUpdaterTest_ManyMany extends DataObject -{ - private static $db = array( - 'Field1' => 'Varchar', - 'Field2' => 'Varchar' - ); - - private static $belongs_many_many = array( - 'ManyManyContainer' => 'SearchUpdaterTest_Container' - ); -} - -class SearchUpdaterTest_Index extends SearchIndex_Recording -{ - public function init() - { - $this->addClass('SearchUpdaterTest_Container'); - - $this->addFilterField('Field1'); - $this->addFilterField('HasOneObject.Field1'); - $this->addFilterField('HasManyObjects.Field1'); - } -} +use SilverStripe\Core\Config\Config; +use SilverStripe\FullTextSearch\Search\FullTextSearch; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasOne; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasMany; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Index; class SearchUpdaterTest extends SapphireTest { @@ -85,7 +20,7 @@ class SearchUpdaterTest extends SapphireTest parent::setUp(); if (self::$index === null) { - self::$index = singleton(get_class($this).'_Index'); + self::$index = SearchUpdaterTest_Index::singleton(); } else { self::$index->reset(); } @@ -132,7 +67,6 @@ class SearchUpdaterTest extends SapphireTest // Check the default "writing a document updates the document" SearchUpdater::flush_dirty_indexes(); - $added = self::$index->getAdded(array('ID')); // Some databases don't output $added in a consistent order; that's okay usort($added, function ($a, $b) {return $a['ID']-$b['ID']; }); diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_Container.php b/tests/SearchUpdaterTest/SearchUpdaterTest_Container.php new file mode 100644 index 0000000..a374a0a --- /dev/null +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_Container.php @@ -0,0 +1,31 @@ + 'Varchar', + 'Field2' => 'Varchar', + 'MyDate' => 'Date', + ); + + private static $table_name = 'SearchUpdaterTest_Container'; + + private static $has_one = array( + 'HasOneObject' => SearchUpdaterTest_HasOne::class + ); + + private static $has_many = array( + 'HasManyObjects' => SearchUpdaterTest_HasMany::class + ); + + private static $many_many = array( + 'ManyManyObjects' => SearchUpdaterTest_ManyMany::class + ); +} diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_HasMany.php b/tests/SearchUpdaterTest/SearchUpdaterTest_HasMany.php new file mode 100644 index 0000000..f008582 --- /dev/null +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_HasMany.php @@ -0,0 +1,20 @@ + 'Varchar', + 'Field2' => 'Varchar' + ); + + private static $table_name = 'SearchUpdaterTest_HasMany'; + + private static $has_one = array( + 'HasManyContainer' => SearchUpdaterTest_Container::class + ); +} diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_HasOne.php b/tests/SearchUpdaterTest/SearchUpdaterTest_HasOne.php new file mode 100644 index 0000000..cc81587 --- /dev/null +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_HasOne.php @@ -0,0 +1,20 @@ + 'Varchar', + 'Field2' => 'Varchar' + ); + + private static $table_name = 'SearchUpdaterTest_HasOne'; + + private static $has_many = array( + 'HasManyContainers' => SearchUpdaterTest_Container::class + ); +} diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_Index.php b/tests/SearchUpdaterTest/SearchUpdaterTest_Index.php new file mode 100644 index 0000000..2142e0e --- /dev/null +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_Index.php @@ -0,0 +1,17 @@ +addClass('SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container'); + + $this->addFilterField('Field1'); + $this->addFilterField('HasOneObject.Field1'); + $this->addFilterField('HasManyObjects.Field1'); + } +} diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_ManyMany.php b/tests/SearchUpdaterTest/SearchUpdaterTest_ManyMany.php new file mode 100644 index 0000000..191fe6f --- /dev/null +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_ManyMany.php @@ -0,0 +1,20 @@ + 'Varchar', + 'Field2' => 'Varchar' + ); + + private static $table_name = 'SearchUpdaterTest_ManyMany'; + + private static $belongs_many_many = array( + 'ManyManyContainer' => SearchUpdaterTest_Container::class + ); +} diff --git a/tests/SolrIndexTest.php b/tests/SolrIndexTest.php index 0a6b82f..c02d62c 100644 --- a/tests/SolrIndexTest.php +++ b/tests/SolrIndexTest.php @@ -187,7 +187,7 @@ class SolrIndexTest extends SapphireTest $serviceMock = $this->getServiceMock(); $index = new SolrIndexTest_FakeIndex(); $index->setService($serviceMock); - $obj = new SearchUpdaterTest_Container(); + $obj = new Container(); $obj->Field1 = 'Field1 val'; $obj->Field2 = null; From fcf9a4f8887e9e47e184ef6dbb36b42d7f30f30e Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Sat, 22 Apr 2017 21:22:54 +1200 Subject: [PATCH 20/63] SS 4.0 - Update Database Captures to support Postgres & SQLite --- ...chManipulateCapture_PostgreSQLDatabase.php | 21 +++++++++++++++++++ ...earchManipulateCapture_SQLite3Database.php | 21 +++++++++++++++++++ code/search/updaters/SearchUpdater.php | 18 +++++++++------- 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 code/search/captures/SearchManipulateCapture_PostgreSQLDatabase.php create mode 100644 code/search/captures/SearchManipulateCapture_SQLite3Database.php diff --git a/code/search/captures/SearchManipulateCapture_PostgreSQLDatabase.php b/code/search/captures/SearchManipulateCapture_PostgreSQLDatabase.php new file mode 100644 index 0000000..12906b3 --- /dev/null +++ b/code/search/captures/SearchManipulateCapture_PostgreSQLDatabase.php @@ -0,0 +1,21 @@ +getShortName(); + $dbClass = 'SilverStripe\FullTextSearch\Captures\SearchManipulateCapture_' . $type; + + // Check if Capture class exists. + if (!class_exists($dbClass)) { + return; + } - $dbClass = SearchManipulateCapture_MySQLDatabase::class; /** @var SS_Database $captured */ $captured = new $dbClass($databaseConfig); - // Framework 3.2+ ORM needs some dependencies set - if (method_exists($captured, "setConnector")) { - $captured->setConnector($current->getConnector()); - $captured->setQueryBuilder($current->getQueryBuilder()); - $captured->setSchemaManager($current->getSchemaManager()); - } + $captured->setConnector($current->getConnector()); + $captured->setQueryBuilder($current->getQueryBuilder()); + $captured->setSchemaManager($current->getSchemaManager()); // The connection might have had it's name changed (like if we're currently in a test) $captured->selectDatabase($current->getSelectedDatabase()); From eac9485924f9d3f534efde3903246ec56c90cf71 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Sat, 22 Apr 2017 21:24:33 +1200 Subject: [PATCH 21/63] SS 4.0 - Update Variants --- code/search/variants/SearchVariant.php | 7 ++++++- .../variants/SearchVariantSiteTreeSubsitesPolyhome.php | 4 +++- code/search/variants/SearchVariantSubsites.php | 6 +++++- code/search/variants/SearchVariantVersioned.php | 7 +------ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/code/search/variants/SearchVariant.php b/code/search/variants/SearchVariant.php index 57f6479..cb03fbb 100644 --- a/code/search/variants/SearchVariant.php +++ b/code/search/variants/SearchVariant.php @@ -1,5 +1,7 @@ execute()->column()); } diff --git a/code/search/variants/SearchVariantSubsites.php b/code/search/variants/SearchVariantSubsites.php index 1f62f71..f331407 100644 --- a/code/search/variants/SearchVariantSubsites.php +++ b/code/search/variants/SearchVariantSubsites.php @@ -1,5 +1,9 @@ execute()->column()); foreach ($writes as $key => $write) { diff --git a/code/search/variants/SearchVariantVersioned.php b/code/search/variants/SearchVariantVersioned.php index 767bdec..e155d96 100644 --- a/code/search/variants/SearchVariantVersioned.php +++ b/code/search/variants/SearchVariantVersioned.php @@ -3,14 +3,9 @@ namespace SilverStripe\FullTextSearch\Search\Variants; class SearchVariantVersioned extends SearchVariant { - public function appliesToEnvironment() - { - return class_exists('Versioned'); - } - public function appliesTo($class, $includeSubclasses) { - return SearchIntrospection::has_extension($class, 'Versioned', $includeSubclasses); + return SearchIntrospection::has_extension($class, Versioned::class, $includeSubclasses); } public function currentState() From 0b7281b25e1705eddbe3ca0704c74c0671471e6d Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Sat, 22 Apr 2017 21:25:41 +1200 Subject: [PATCH 22/63] SS 4.0 - Update references to thirdparty Solr API as its not namespaced --- code/solr/SolrIndex.php | 2 +- code/solr/services/Solr4Service_Core.php | 4 ++-- tests/SolrIndexVersionedTest/SolrDocumentMatcher.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index 76842a2..8884a4a 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -541,7 +541,7 @@ abstract class SolrIndex extends SearchIndex { $includeSubs = $options['include_children']; - $doc = new Apache_Solr_Document(); + $doc = new \Apache_Solr_Document(); // Always present fields diff --git a/code/solr/services/Solr4Service_Core.php b/code/solr/services/Solr4Service_Core.php index 48b8285..e392882 100644 --- a/code/solr/services/Solr4Service_Core.php +++ b/code/solr/services/Solr4Service_Core.php @@ -25,7 +25,7 @@ class Solr4Service_Core extends SolrService_Core * @inheritdoc * @see Solr4Service_Core::addDocuments */ - public function addDocument(Apache_Solr_Document $document, $allowDups = false, + public function addDocument(\Apache_Solr_Document $document, $allowDups = false, $overwritePending = true, $overwriteCommitted = true, $commitWithin = 0 ) { return $this->addDocuments(array($document), $allowDups, $overwritePending, $overwriteCommitted, $commitWithin); @@ -44,7 +44,7 @@ class Solr4Service_Core extends SolrService_Core $rawPost = ""; foreach ($documents as $document) { - if ($document instanceof Apache_Solr_Document) { + if ($document instanceof \Apache_Solr_Document) { $rawPost .= $this->_documentToXmlFragment($document); } } diff --git a/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php b/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php index 5c9298e..91eb810 100644 --- a/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php +++ b/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php @@ -19,12 +19,12 @@ class SolrDocumentMatcher extends Hamcrest_BaseMatcher public function describeTo(\Hamcrest_Description $description) { - $description->appendText('Apache_Solr_Document with properties '.var_export($this->properties, true)); + $description->appendText('\Apache_Solr_Document with properties '.var_export($this->properties, true)); } public function matches($item) { - if (! ($item instanceof Apache_Solr_Document)) { + if (! ($item instanceof \Apache_Solr_Document)) { return false; } From faacb6bc47e5afe38cdd6e649994ef01f6e2d582 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Sat, 22 Apr 2017 21:30:29 +1200 Subject: [PATCH 23/63] SS 4.0 - Fix SearchIntrospection and SearchIndex --- code/search/SearchIntrospection.php | 6 +----- code/search/indexes/SearchIndex.php | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/code/search/SearchIntrospection.php b/code/search/SearchIntrospection.php index 67de910..a214bc9 100644 --- a/code/search/SearchIntrospection.php +++ b/code/search/SearchIntrospection.php @@ -43,15 +43,11 @@ class SearchIntrospection $classes = array_unique(array_merge($classes, array_values(ClassInfo::subclassesFor($class)))); } - $idx = array_search('SilverStripe\View\ViewableData', $classes); + $idx = array_search('SilverStripe\ORM\DataObject', $classes); if ($idx !== false) { array_splice($classes, 0, $idx+1); } - $idx = array_search('SilverStripe\Core\Object', $classes); - if ($idx !== false) { - array_splice($classes, 0, $idx+1); - } //@todo find another way to determine if a dataobject does not have a table // if ($dataOnly) { // foreach ($classes as $i => $class) { diff --git a/code/search/indexes/SearchIndex.php b/code/search/indexes/SearchIndex.php index 2e1750d..fa9b962 100644 --- a/code/search/indexes/SearchIndex.php +++ b/code/search/indexes/SearchIndex.php @@ -10,6 +10,7 @@ use SilverStripe\Core\ClassInfo; use SilverStripe\FullTextSearch\Search\SearchIntrospection; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; use SilverStripe\FullTextSearch\Utils\MultipleArrayIterator; +use SilverStripe\ORM\Queries\SQLSelect; /** * SearchIndex is the base index class. Each connector will provide a subclass of this that * provides search engine specific behavior. @@ -92,21 +93,23 @@ abstract class SearchIndex extends ViewableData foreach (SearchIntrospection::hierarchy($source, $options['include_children']) as $dataclass) { $singleton = singleton($dataclass); + $schema = DataObject::getSchema(); + $className = $singleton->getClassName(); - if ($hasOne = $singleton->hasOne($lookup)) { + if ($hasOne = $schema->hasOneComponent($className, $lookup)) { $class = $hasOne; $options['lookup_chain'][] = array( 'call' => 'method', 'method' => $lookup, 'through' => 'has_one', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => "{$lookup}ID" ); - } elseif ($hasMany = $singleton->hasMany($lookup)) { + } elseif ($hasMany = $schema->hasManyComponent($className, $lookup)) { $class = $hasMany; $options['multi_valued'] = true; $options['lookup_chain'][] = array( 'call' => 'method', 'method' => $lookup, - 'through' => 'has_many', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => $singleton->getRemoteJoinField($lookup, 'has_many') + 'through' => 'has_many', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => $schema->getRemoteJoinField($className, $lookup, 'has_many') ); - } elseif ($manyMany = $singleton->manyMany($lookup)) { + } elseif ($manyMany = $schema->manyManyComponent($className, $lookup)) { $class = $manyMany[1]; $options['multi_valued'] = true; $options['lookup_chain'][] = array( @@ -555,14 +558,20 @@ abstract class SearchIndex extends ViewableData $ids = array($id); foreach ($derivation['chain'] as $step) { + // Use TableName for queries + $tableName = DataObject::getSchema()->tableName($step['class']); + if ($step['through'] == 'has_one') { - $sql = new SQLQuery('"ID"', '"'.$step['class'].'"', '"'.$step['foreignkey'].'" IN ('.implode(',', $ids).')'); + $sql = new SQLSelect('"ID"', '"'.$tableName.'"', '"'.$step['foreignkey'].'" IN ('.implode(',', $ids).')'); singleton($step['class'])->extend('augmentSQL', $sql); $ids = $sql->execute()->column(); } elseif ($step['through'] == 'has_many') { - $sql = new SQLQuery('"'.$step['class'].'"."ID"', '"'.$step['class'].'"', '"'.$step['otherclass'].'"."ID" IN ('.implode(',', $ids).')'); - $sql->addInnerJoin($step['otherclass'], '"'.$step['class'].'"."ID" = "'.$step['otherclass'].'"."'.$step['foreignkey'].'"'); + // Use TableName for queries + $otherTableName = DataObject::getSchema()->tableName($step['otherclass']); + + $sql = new SQLSelect('"'.$tableName.'"."ID"', '"'.$tableName.'"', '"'.$otherTableName.'"."ID" IN ('.implode(',', $ids).')'); + $sql->addInnerJoin($otherTableName, '"'.$tableName.'"."ID" = "'.$otherTableName.'"."'.$step['foreignkey'].'"'); singleton($step['class'])->extend('augmentSQL', $sql); $ids = $sql->execute()->column(); From 43dd2ba3981453f9bcaa762456708ba8c6918837 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Sat, 22 Apr 2017 21:31:34 +1200 Subject: [PATCH 24/63] SS 4.0 - Replace inst()->update with modify()->set and hasOne with hasOneComponent --- tests/BatchedProcessorTest.php | 12 ++++++------ tests/SearchUpdaterTest.php | 3 ++- tests/SearchVariantVersionedTest.php | 2 +- tests/SolrIndexSubsitesTest.php | 4 ++-- tests/SolrIndexTest.php | 2 +- tests/SolrIndexVersionedTest.php | 4 ++-- tests/SolrReindexQueuedTest.php | 2 +- tests/SolrReindexTest.php | 2 +- .../SolrReindexTest_ItemExtension.php | 2 +- 9 files changed, 17 insertions(+), 16 deletions(-) diff --git a/tests/BatchedProcessorTest.php b/tests/BatchedProcessorTest.php index fcb96b3..54d384c 100644 --- a/tests/BatchedProcessorTest.php +++ b/tests/BatchedProcessorTest.php @@ -48,9 +48,9 @@ class BatchedProcessorTest extends SapphireTest SS_Datetime::set_mock_now('2015-05-07 06:00:00'); - Config::inst()->update('SearchUpdateBatchedProcessor', 'batch_size', 5); - Config::inst()->update('SearchUpdateBatchedProcessor', 'batch_soft_cap', 0); - Config::inst()->update('SearchUpdateCommitJobProcessor', 'cooldown', 600); + Config::modify()->set('SearchUpdateBatchedProcessor', 'batch_size', 5); + Config::modify()->set('SearchUpdateBatchedProcessor', 'batch_soft_cap', 0); + Config::modify()->set('SearchUpdateCommitJobProcessor', 'cooldown', 600); Versioned::reading_stage("Stage"); @@ -195,20 +195,20 @@ class BatchedProcessorTest extends SapphireTest $processor = $this->generateDirtyIds(); // Test that increasing the soft cap to 2 will reduce the number of batches - Config::inst()->update('SearchUpdateBatchedProcessor', 'batch_soft_cap', 2); + Config::modify()->set('SearchUpdateBatchedProcessor', 'batch_soft_cap', 2); $processor->batchData(); $data = $processor->getJobData(); //Debug::dump($data);die; $this->assertEquals(8, $data->totalSteps); // A soft cap of 1 should not fit in the hanging two items - Config::inst()->update('SearchUpdateBatchedProcessor', 'batch_soft_cap', 1); + Config::modify()->set('SearchUpdateBatchedProcessor', 'batch_soft_cap', 1); $processor->batchData(); $data = $processor->getJobData(); $this->assertEquals(9, $data->totalSteps); // Extra large soft cap should fit both items - Config::inst()->update('SearchUpdateBatchedProcessor', 'batch_soft_cap', 4); + Config::modify()->set('SearchUpdateBatchedProcessor', 'batch_soft_cap', 4); $processor->batchData(); $data = $processor->getJobData(); $this->assertEquals(8, $data->totalSteps); diff --git a/tests/SearchUpdaterTest.php b/tests/SearchUpdaterTest.php index 000283c..e786c2b 100644 --- a/tests/SearchUpdaterTest.php +++ b/tests/SearchUpdaterTest.php @@ -27,7 +27,7 @@ class SearchUpdaterTest extends SapphireTest SearchUpdater::bind_manipulation_capture(); - Config::inst()->update('Injector', 'SearchUpdateProcessor', array( + Config::modify()->set('Injector', 'SearchUpdateProcessor', array( 'class' => 'SearchUpdateImmediateProcessor' )); @@ -86,6 +86,7 @@ class SearchUpdaterTest extends SapphireTest SearchUpdater::flush_dirty_indexes(); $added = self::$index->getAdded(array('ID')); + // Some databases don't output $added in a consistent order; that's okay usort($added, function ($a, $b) {return $a['ID']-$b['ID']; }); diff --git a/tests/SearchVariantVersionedTest.php b/tests/SearchVariantVersionedTest.php index 1b73373..bff85c7 100644 --- a/tests/SearchVariantVersionedTest.php +++ b/tests/SearchVariantVersionedTest.php @@ -31,7 +31,7 @@ class SearchVariantVersionedTest extends SapphireTest SearchUpdater::bind_manipulation_capture(); - Config::inst()->update('Injector', 'SearchUpdateProcessor', array( + Config::modify()->set('Injector', 'SearchUpdateProcessor', array( 'class' => 'SearchUpdateImmediateProcessor' )); diff --git a/tests/SolrIndexSubsitesTest.php b/tests/SolrIndexSubsitesTest.php index 3534104..0d557df 100644 --- a/tests/SolrIndexSubsitesTest.php +++ b/tests/SolrIndexSubsitesTest.php @@ -51,7 +51,7 @@ class SolrIndexSubsitesTest extends SapphireTest { SearchUpdater::bind_manipulation_capture(); - Config::inst()->update('Injector', 'SearchUpdateProcessor', array( + Config::modify()->set('Injector', 'SearchUpdateProcessor', array( 'class' => 'SearchUpdateImmediateProcessor' )); @@ -86,7 +86,7 @@ class SolrIndexSubsitesTest extends SapphireTest { $variants = array(); // Check subsite - if(class_exists('Subsite') && $object->hasOne('Subsite')) { + if(class_exists('Subsite') && DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite')) { $variants[] = '"SearchVariantSubsites":"' . $subsiteID. '"'; } diff --git a/tests/SolrIndexTest.php b/tests/SolrIndexTest.php index c02d62c..154f960 100644 --- a/tests/SolrIndexTest.php +++ b/tests/SolrIndexTest.php @@ -209,7 +209,7 @@ class SolrIndexTest extends SapphireTest public function testAddFieldExtraOptions() { Config::inst()->nest(); - Config::inst()->update('Director', 'environment_type', 'live'); // dev mode sets stored=true for everything + Config::modify()->set('Director', 'environment_type', 'live'); // dev mode sets stored=true for everything $index = new SolrIndexTest_FakeIndex(); diff --git a/tests/SolrIndexVersionedTest.php b/tests/SolrIndexVersionedTest.php index 4533576..a0f7013 100644 --- a/tests/SolrIndexVersionedTest.php +++ b/tests/SolrIndexVersionedTest.php @@ -44,7 +44,7 @@ class SolrIndexVersionedTest extends SapphireTest SearchUpdater::bind_manipulation_capture(); - Config::inst()->update('Injector', 'SearchUpdateProcessor', array( + Config::modify()->set('Injector', 'SearchUpdateProcessor', array( 'class' => 'SearchUpdateImmediateProcessor' )); @@ -77,7 +77,7 @@ class SolrIndexVersionedTest extends SapphireTest $class = ClassInfo::baseDataClass($object); // Prevent subsites from breaking tests $subsites = ''; - if(class_exists('Subsite') && $object->hasOne('Subsite')) { + if(class_exists('Subsite') && DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite')) { $subsites = '"SearchVariantSubsites":"0",'; } return $id.'-'.$class.'-{'.$subsites.'"SearchVariantVersioned":"'.$stage.'"}'; diff --git a/tests/SolrReindexQueuedTest.php b/tests/SolrReindexQueuedTest.php index ed7aa0c..c048d5a 100644 --- a/tests/SolrReindexQueuedTest.php +++ b/tests/SolrReindexQueuedTest.php @@ -45,7 +45,7 @@ class SolrReindexQueuedTest extends SapphireTest } // Set queued handler for reindex - Config::inst()->update('Injector', 'SolrReindexHandler', array( + Config::modify()->set('Injector', 'SolrReindexHandler', array( 'class' => 'SolrReindexQueuedHandler' )); Injector::inst()->registerService(new SolrReindexQueuedHandler(), 'SolrReindexHandler'); diff --git a/tests/SolrReindexTest.php b/tests/SolrReindexTest.php index 1c2c2a6..340c135 100644 --- a/tests/SolrReindexTest.php +++ b/tests/SolrReindexTest.php @@ -41,7 +41,7 @@ class SolrReindexTest extends SapphireTest } // Set test handler for reindex - Config::inst()->update('Injector', 'SolrReindexHandler', array( + Config::modify()->set('Injector', 'SolrReindexHandler', array( 'class' => 'SolrReindexTest_TestHandler' )); Injector::inst()->registerService(new SolrReindexTest_TestHandler(), 'SolrReindexHandler'); diff --git a/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php b/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php index 9981932..faa2e22 100644 --- a/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php +++ b/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php @@ -17,7 +17,7 @@ class SolrReindexTest_ItemExtension extends DataExtension implements TestOnly /** * Filter records on the current variant * - * @param SQLQuery $query + * @param SQLSelect $query * @param DataQuery $dataQuery */ public function augmentSQL(SQLSelect $query, DataQuery $dataQuery = NULL) From 168b6745b44928882cd3e1761406a7ceda9b12c8 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Sat, 22 Apr 2017 21:36:40 +1200 Subject: [PATCH 25/63] SS 4.0 - Skip Subsite tests if module is not installed --- tests/SolrIndexSubsitesTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/SolrIndexSubsitesTest.php b/tests/SolrIndexSubsitesTest.php index 0d557df..1cd3889 100644 --- a/tests/SolrIndexSubsitesTest.php +++ b/tests/SolrIndexSubsitesTest.php @@ -26,6 +26,7 @@ class SolrIndexSubsitesTest extends SapphireTest { // Prevent parent::setUp() crashing on db build if (!class_exists('Subsite')) { $this->skipTest = true; + $this->markTestSkipped("These tests need the Subsite module installed to run"); } parent::setUp(); From 8228c762c9ec774d7fbed8408a9b26af5c526348 Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Sun, 23 Apr 2017 06:21:06 +1200 Subject: [PATCH 26/63] Explicit namespace definition on YAML files --- _config/binding.yml | 2 +- _config/config.yml | 4 +-- _config/processor.yml | 34 +++++++++---------- code/search/FullTextSearch.php | 3 +- code/search/indexes/SearchIndex.php | 4 ++- code/search/updaters/SearchUpdater.php | 5 +++ code/solr/Solr.php | 3 +- .../solr/reindex/handlers/SolrReindexBase.php | 1 + .../handlers/SolrReindexImmediateHandler.php | 3 ++ .../reindex/jobs/SolrReindexQueuedJobBase.php | 4 +-- code/solr/services/Solr3Service.php | 2 +- code/solr/services/Solr4Service.php | 2 +- code/solr/services/Solr4Service_Core.php | 2 +- code/solr/services/SolrService.php | 2 +- code/solr/stores/SolrConfigStore_WebDAV.php | 4 +++ code/solr/tasks/Solr_BuildTask.php | 12 ++++--- code/solr/tasks/Solr_Configure.php | 8 ++++- code/solr/tasks/Solr_Reindex.php | 13 ++++--- code/utils/logging/MonologFactory.php | 2 ++ docs/en/Solr.md | 16 ++++----- tests/SolrReindexQueuedTest.php | 2 +- tests/SolrReindexTest.php | 2 +- 22 files changed, 81 insertions(+), 49 deletions(-) diff --git a/_config/binding.yml b/_config/binding.yml index 5f1cfd2..14702a3 100644 --- a/_config/binding.yml +++ b/_config/binding.yml @@ -1,4 +1,4 @@ -Injector: +SilverStripe\Core\Injector\Injector: RequestProcessor: properties: filters: diff --git a/_config/config.yml b/_config/config.yml index 7193cb2..86f8423 100644 --- a/_config/config.yml +++ b/_config/config.yml @@ -1,3 +1,3 @@ -DataObject: +SilverStripe\ORM\DataObject\DataObject: extensions: - - 'SearchUpdater_ObjectHandler' + - 'SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater_ObjectHandler' diff --git a/_config/processor.yml b/_config/processor.yml index 430ec5e..fbd4b3e 100644 --- a/_config/processor.yml +++ b/_config/processor.yml @@ -1,13 +1,13 @@ --- Name: defaultprocessor --- -Injector: - SearchUpdateProcessor: - class: SearchUpdateImmediateProcessor - SolrReindexHandler: - class: SolrReindexImmediateHandler - SearchLogFactory: - class: 'MonologFactory' +SilverStripe\Core\Injector\Injector: + SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor: + class: SilverStripe\FullTextSearch\Search\Processors\SearchUpdateImmediateProcessor + SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler: + class: SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexImmediateHandler + SilverStripe\FullTextSearch\Utils\Logging\SearchLogFactory: + class: 'SilverStripe\FullTextSearch\Utils\Logging\MonologFactory' --- Name: messagequeueprocessor Only: @@ -15,11 +15,11 @@ Only: Except: Environment: 'dev' --- -Injector: - SearchUpdateProcessor: - class: SearchUpdateMessageQueueProcessor - SolrReindexHandler: - class: SolrReindexMessageHandler +SilverStripe\Core\Injector\Injector: + SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor: + class: SilverStripe\FullTextSearch\Search\Processors\SearchUpdateMessageQueueProcessor + SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler: + class: SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexMessageHandler --- Name: queuedjobprocessor Only: @@ -27,8 +27,8 @@ Only: Except: Environment: 'dev' --- -Injector: - SearchUpdateProcessor: - class: SearchUpdateQueuedJobProcessor - SolrReindexHandler: - class: SolrReindexQueuedHandler +SilverStripe\Core\Injector\Injector: + SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor: + class: SilverStripe\FullTextSearch\Search\Processors\SearchUpdateQueuedJobProcessor + SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler: + class: SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexQueuedHandler diff --git a/code/search/FullTextSearch.php b/code/search/FullTextSearch.php index b419d25..bebe9fd 100644 --- a/code/search/FullTextSearch.php +++ b/code/search/FullTextSearch.php @@ -2,6 +2,7 @@ namespace SilverStripe\FullTextSearch\Search; +use ReflectionClass; use SilverStripe\Core\Config\Config; use SilverStripe\Core\ClassInfo; /** @@ -41,7 +42,7 @@ class FullTextSearch if (self::$all_indexes === null) { // Get declared indexes, or otherwise default to all subclasses of SearchIndex $classes = Config::inst()->get(__CLASS__, 'indexes') - ?: ClassInfo::subclassesFor('SearchIndex'); + ?: ClassInfo::subclassesFor('SilverStripe\FullTextSearch\Solr\SearchIndex'); $hidden = array(); $candidates = array(); diff --git a/code/search/indexes/SearchIndex.php b/code/search/indexes/SearchIndex.php index 2e1750d..bd75ab5 100644 --- a/code/search/indexes/SearchIndex.php +++ b/code/search/indexes/SearchIndex.php @@ -2,6 +2,8 @@ namespace SilverStripe\FullTextSearch\Search\Indexes; +use Exception; +use InvalidArgumentException; use SilverStripe\View\ViewableData; use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObjectSchema; @@ -303,7 +305,7 @@ abstract class SearchIndex extends ViewableData $type = $match[1]; } list($type, $args) = Object::parse_class_spec($type); - if (is_subclass_of($type, 'StringField')) { + if (is_subclass_of($type, 'SilverStripe\ORM\FieldType\DBString')) { $this->addFulltextField($field); } } diff --git a/code/search/updaters/SearchUpdater.php b/code/search/updaters/SearchUpdater.php index b4460c3..5a1699b 100644 --- a/code/search/updaters/SearchUpdater.php +++ b/code/search/updaters/SearchUpdater.php @@ -2,7 +2,12 @@ namespace SilverStripe\FullTextSearch\Search\Updaters; +use SilverStripe\Dev\SapphireTest; +use SilverStripe\FullTextSearch\Search\FullTextSearch; +use SilverStripe\FullTextSearch\Search\SearchIntrospection; +use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; use SilverStripe\ORM\DB; +use SilverStripe\Core\ClassInfo; /** * This class is responsible for capturing changes to DataObjects and triggering index updates of the resulting dirty index * items. diff --git a/code/solr/Solr.php b/code/solr/Solr.php index 98d3972..8fe496d 100644 --- a/code/solr/Solr.php +++ b/code/solr/Solr.php @@ -3,6 +3,7 @@ namespace SilverStripe\FullTextSearch\Solr; use SilverStripe\Control\Director; use SilverStripe\Core\Object; +use SilverStripe\FullTextSearch\Search\FullTextSearch; class Solr { @@ -136,7 +137,7 @@ class Solr public static function get_indexes() { - return FullTextSearch::get_indexes('SolrIndex'); + return FullTextSearch::get_indexes('SilverStripe\FullTextSearch\Solr\SolrIndex'); } /** diff --git a/code/solr/reindex/handlers/SolrReindexBase.php b/code/solr/reindex/handlers/SolrReindexBase.php index f127537..0afea23 100644 --- a/code/solr/reindex/handlers/SolrReindexBase.php +++ b/code/solr/reindex/handlers/SolrReindexBase.php @@ -3,6 +3,7 @@ namespace SilverStripe\FullTextSearch\Solr\Reindex\Handlers; use Psr\Log\LoggerInterface; +use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; use SilverStripe\FullTextSearch\Solr\Solr; use SilverStripe\FullTextSearch\Solr\SolrIndex; diff --git a/code/solr/reindex/handlers/SolrReindexImmediateHandler.php b/code/solr/reindex/handlers/SolrReindexImmediateHandler.php index c0c48bb..b67a33f 100644 --- a/code/solr/reindex/handlers/SolrReindexImmediateHandler.php +++ b/code/solr/reindex/handlers/SolrReindexImmediateHandler.php @@ -3,7 +3,10 @@ namespace SilverStripe\FullTextSearch\Solr\Reindex\Handlers; use Psr\Log\LoggerInterface; +use SilverStripe\Control\Director; +use SilverStripe\FullTextSearch\Solr\Solr; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\ORM\DB; /** * Invokes an immediate reindex diff --git a/code/solr/reindex/jobs/SolrReindexQueuedJobBase.php b/code/solr/reindex/jobs/SolrReindexQueuedJobBase.php index 3d5903e..e1cb64b 100644 --- a/code/solr/reindex/jobs/SolrReindexQueuedJobBase.php +++ b/code/solr/reindex/jobs/SolrReindexQueuedJobBase.php @@ -44,7 +44,7 @@ abstract class SolrReindexQueuedJobBase implements QueuedJob */ protected function getLoggerFactory() { - return Injector::inst()->get('SearchLogFactory'); + return Injector::inst()->get('SilverStripe\FullTextSearch\Utils\Logging\SearchLogFactory'); } /** @@ -103,7 +103,7 @@ abstract class SolrReindexQueuedJobBase implements QueuedJob */ protected function getHandler() { - return Injector::inst()->get('SolrReindexHandler'); + return Injector::inst()->get('SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler'); } public function jobFinished() diff --git a/code/solr/services/Solr3Service.php b/code/solr/services/Solr3Service.php index f2546a6..d540de2 100644 --- a/code/solr/services/Solr3Service.php +++ b/code/solr/services/Solr3Service.php @@ -3,5 +3,5 @@ namespace SilverStripe\FullTextSearch\Solr\Services; class Solr3Service extends SolrService { - private static $core_class = 'Solr3Service_Core'; + private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\Solr3Service'; } diff --git a/code/solr/services/Solr4Service.php b/code/solr/services/Solr4Service.php index ea69e77..9dc3346 100644 --- a/code/solr/services/Solr4Service.php +++ b/code/solr/services/Solr4Service.php @@ -3,5 +3,5 @@ namespace SilverStripe\FullTextSearch\Solr\Services; class Solr4Service extends SolrService { - private static $core_class = 'Solr4Service_Core'; + private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\Solr4Service'; } diff --git a/code/solr/services/Solr4Service_Core.php b/code/solr/services/Solr4Service_Core.php index bdde99a..056c658 100644 --- a/code/solr/services/Solr4Service_Core.php +++ b/code/solr/services/Solr4Service_Core.php @@ -44,7 +44,7 @@ class Solr4Service_Core extends SolrService_Core $rawPost = ""; foreach ($documents as $document) { - if ($document instanceof Apache_Solr_Document) { + if ($document instanceof \Apache_Solr_Document) { $rawPost .= $this->_documentToXmlFragment($document); } } diff --git a/code/solr/services/SolrService.php b/code/solr/services/SolrService.php index 6aae39b..a7f53d5 100644 --- a/code/solr/services/SolrService.php +++ b/code/solr/services/SolrService.php @@ -10,7 +10,7 @@ Solr::include_client_api(); */ class SolrService extends SolrService_Core { - private static $core_class = 'SolrService_Core'; + private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\SolrService'; /** * Handle encoding the GET parameters and making the HTTP call to execute a core command diff --git a/code/solr/stores/SolrConfigStore_WebDAV.php b/code/solr/stores/SolrConfigStore_WebDAV.php index 96259cb..037821e 100644 --- a/code/solr/stores/SolrConfigStore_WebDAV.php +++ b/code/solr/stores/SolrConfigStore_WebDAV.php @@ -2,6 +2,10 @@ namespace SilverStripe\FullTextSearch\Solr\Stores; +use SilverStripe\FullTextSearch\Solr\Solr; +use SilverStripe\FullTextSearch\Utils\WebDAV; + + /** * Class SolrConfigStore_WebDAV * diff --git a/code/solr/tasks/Solr_BuildTask.php b/code/solr/tasks/Solr_BuildTask.php index d26f647..fa06e23 100644 --- a/code/solr/tasks/Solr_BuildTask.php +++ b/code/solr/tasks/Solr_BuildTask.php @@ -1,6 +1,9 @@ get('Logger'); + return Injector::inst()->get('Psr\Log\LoggerInterface'); } /** @@ -40,7 +43,7 @@ class Solr_BuildTask extends BuildTask */ protected function getLoggerFactory() { -// return Injector::inst()->get('SearchLogFactory'); + return Injector::inst()->get('SilverStripe\FullTextSearch\Utils\Logging\SearchLogFactory'); } /** @@ -55,9 +58,8 @@ class Solr_BuildTask extends BuildTask // Set new logger $logger = $this - ->getLoggerFactory(); -//@todo: Cannot instantiate interface SearchLogFactory -// ->getOutputLogger($name, $verbose); + ->getLoggerFactory() + ->getOutputLogger($name, $verbose); $this->setLogger($logger); } } diff --git a/code/solr/tasks/Solr_Configure.php b/code/solr/tasks/Solr_Configure.php index 8989f9c..31471fe 100644 --- a/code/solr/tasks/Solr_Configure.php +++ b/code/solr/tasks/Solr_Configure.php @@ -1,5 +1,11 @@ get('SolrReindexImmediateHandler'); + return Injector::inst()->get('SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler'); } /** @@ -65,7 +70,7 @@ class Solr_Reindex extends Solr_BuildTask // this is for when index names do not match the class name (this can be done by overloading getIndexName() on // indexes if ($index && !ClassInfo::exists($index)) { - foreach(ClassInfo::subclassesFor('SolrIndex') as $solrIndexClass) { + foreach(ClassInfo::subclassesFor('SilverStripe\FullTextSearch\Solr\SolrIndex') as $solrIndexClass) { $reflection = new ReflectionClass($solrIndexClass); //skip over abstract classes if (!$reflection->isInstantiable()) { diff --git a/code/utils/logging/MonologFactory.php b/code/utils/logging/MonologFactory.php index bff773f..d92b4bf 100644 --- a/code/utils/logging/MonologFactory.php +++ b/code/utils/logging/MonologFactory.php @@ -4,6 +4,8 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Monolog\Handler\HandlerInterface; use Monolog\Logger; +use SilverStripe\Core\Injector\Injector; +use SilverStripe\Control\Director; /** * Provides logging based on monolog diff --git a/docs/en/Solr.md b/docs/en/Solr.md index 89e22bb..a5e1773 100644 --- a/docs/en/Solr.md +++ b/docs/en/Solr.md @@ -56,16 +56,16 @@ All possible parameters incl optional ones with example values: Solr::configure_server(array( 'host' => 'localhost', // default: localhost | The host or IP Solr is listening on 'port' => '8983', // default: 8983 | The port Solr is listening on - 'path' => '/solr' // default: /solr | The suburl the solr service is available on - 'version' => '4' // default: 4 | Solr server version - currently only 3 and 4 supported - 'service' => 'Solr4Service' // default: depends on version, Solr3Service for 3, Solr4Service for 4 | the class that provides actual communcation to the Solr server - 'extraspath' => BASE_PATH .'/fulltextsearch/conf/solr/4/extras/' // default: /fulltextsearch/conf/solr/{version}/extras/ | Absolute path to the folder containing templates which are used for generating the schema and field definitions. - 'templates' => BASE_PATH . '/fulltextsearch/conf/solr/4/templates/' // default: /fulltextsearch/conf/solr/{version}/templates/ | Absolute path to the configuration default files, e.g. solrconfig.xml + 'path' => '/solr', // default: /solr | The suburl the solr service is available on + 'version' => '4', // default: 4 | Solr server version - currently only 3 and 4 supported + 'service' => 'Solr4Service', // default: depends on version, Solr3Service for 3, Solr4Service for 4 | the class that provides actual communcation to the Solr server + 'extraspath' => BASE_PATH .'/fulltextsearch/conf/solr/4/extras/', // default: /fulltextsearch/conf/solr/{version}/extras/ | Absolute path to the folder containing templates which are used for generating the schema and field definitions. + 'templates' => BASE_PATH . '/fulltextsearch/conf/solr/4/templates/', // default: /fulltextsearch/conf/solr/{version}/templates/ | Absolute path to the configuration default files, e.g. solrconfig.xml 'indexstore' => array( 'mode' => 'file', // a classname which implements SolrConfigStore, or 'file' or 'webdav' - 'path' => BASE_PATH . '/.solr' // The (locally accessible) path to write the index configurations to OR The suburl on the solr host that is set up to accept index configurations via webdav - 'remotepath' => '/opt/solr/config' // default (file mode only): same as 'path' above | The path that the Solr server will read the index configurations from - 'auth' => 'solr:solr' // default: none | Webdav only - A username:password pair string to use to auth against the webdav server + 'path' => BASE_PATH . '/.solr', // The (locally accessible) path to write the index configurations to OR The suburl on the solr host that is set up to accept index configurations via webdav + 'remotepath' => '/opt/solr/config', // default (file mode only): same as 'path' above | The path that the Solr server will read the index configurations from + 'auth' => 'solr:solr', // default: none | Webdav only - A username:password pair string to use to auth against the webdav server 'port' => '80' // default: same as solr port | The port for WebDAV if different from the Solr port ) )); diff --git a/tests/SolrReindexQueuedTest.php b/tests/SolrReindexQueuedTest.php index ed7aa0c..1baf385 100644 --- a/tests/SolrReindexQueuedTest.php +++ b/tests/SolrReindexQueuedTest.php @@ -106,7 +106,7 @@ class SolrReindexQueuedTest extends SapphireTest */ protected function getHandler() { - return Injector::inst()->get('SolrReindexHandler'); + return Injector::inst()->get('SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler'); } /** diff --git a/tests/SolrReindexTest.php b/tests/SolrReindexTest.php index 1c2c2a6..6338e35 100644 --- a/tests/SolrReindexTest.php +++ b/tests/SolrReindexTest.php @@ -102,7 +102,7 @@ class SolrReindexTest extends SapphireTest */ protected function getHandler() { - return Injector::inst()->get('SolrReindexHandler'); + return Injector::inst()->get('SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler'); } /** From d13601f827bafad964b31540a2ed1c5d23a91a9d Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Mon, 24 Apr 2017 10:01:49 +1200 Subject: [PATCH 27/63] Fix invalid namespace reference for SolrService_Core --- code/solr/services/SolrService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/solr/services/SolrService.php b/code/solr/services/SolrService.php index a7f53d5..2786605 100644 --- a/code/solr/services/SolrService.php +++ b/code/solr/services/SolrService.php @@ -10,7 +10,7 @@ Solr::include_client_api(); */ class SolrService extends SolrService_Core { - private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\SolrService'; + private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\SolrService_Core'; /** * Handle encoding the GET parameters and making the HTTP call to execute a core command From 1728a62af52fc29ccbe3e4da1e347658297971db Mon Sep 17 00:00:00 2001 From: Elliot Sawyer Date: Fri, 17 Feb 2017 12:03:51 +1300 Subject: [PATCH 28/63] WIP: Silverstripe 4 compatibility Thanks to Marco Hermo and Brett Tasker for helping with this * Bump framework/cms to ^4.0@dev * WIP Silverstripe 4 compatibility fixes * more replacements and patches to migrate this module to 4.0 * Update composer.json * remove php <5.5 from travis.yml * WIP more SS4 compatibility fixes * WIP fix solr path to use DIR, avoid hardcoded module name * WIP respect current include path * WIP Namespacing and use on SearchIndex class * Namespacing for tests * WIP add namespaces to all classes * Second push of Test changes + namespacing * WIP split Solr files with multiple classes into single file / single class. Adjust namespaces * Fix PHP errors in test * break out search components with multiple classes into individual files and change namespaces * Update namespacing for Search indexes and variants in tests * Batch fixes for tests #2 * Update _config.php to use namespace * Use root namespace in referencing Apache_Solr_Document * Migrate task names so that the name is not fully qualified --- .travis.yml | 3 - _config.php | 4 +- code/search/FullTextSearch.php | 3 + code/search/SearchIntrospection.php | 23 +- code/search/{ => indexes}/SearchIndex.php | 116 +------ code/search/indexes/SearchIndex_Null.php | 23 ++ code/search/indexes/SearchIndex_Recording.php | 79 +++++ .../SearchUpdateBatchedProcessor.php | 2 +- .../SearchUpdateCommitJobProcessor.php | 2 +- .../SearchUpdateImmediateProcessor.php | 2 +- .../SearchUpdateMessageQueueProcessor.php | 2 +- .../processors/SearchUpdateProcessor.php | 2 +- .../SearchUpdateQueuedJobProcessor.php | 2 +- code/search/{ => queries}/SearchQuery.php | 32 +- code/search/queries/SearchQuery_Range.php | 34 ++ code/search/{ => updaters}/SearchUpdater.php | 78 +---- ...hUpdater_BindManipulationCaptureFilter.php | 23 ++ .../updaters/SearchUpdater_ObjectHandler.php | 66 ++++ code/search/{ => variants}/SearchVariant.php | 31 +- .../SearchVariantSiteTreeSubsitesPolyhome.php | 1 + .../{ => variants}/SearchVariantSubsites.php | 2 +- .../{ => variants}/SearchVariantVersioned.php | 1 + code/search/variants/SearchVariant_Caller.php | 38 +++ code/solr/Solr.php | 300 +----------------- code/solr/SolrConfigStore.php | 134 -------- code/solr/SolrIndex.php | 5 +- .../solr/reindex/handlers/SolrReindexBase.php | 4 + .../reindex/handlers/SolrReindexHandler.php | 3 + .../handlers/SolrReindexImmediateHandler.php | 3 + .../handlers/SolrReindexMessageHandler.php | 2 +- .../handlers/SolrReindexQueuedHandler.php | 3 + .../jobs/SolrReindexGroupQueuedJob.php | 2 +- .../reindex/jobs/SolrReindexQueuedJob.php | 2 +- .../reindex/jobs/SolrReindexQueuedJobBase.php | 2 +- code/solr/{ => services}/Solr3Service.php | 5 +- code/solr/services/Solr3Service_Core.php | 8 + code/solr/services/Solr4Service.php | 7 + .../Solr4Service_Core.php} | 13 +- code/solr/{ => services}/SolrService.php | 12 +- code/solr/services/SolrService_Core.php | 18 ++ code/solr/stores/SolrConfigStore.php | 36 +++ code/solr/stores/SolrConfigStore_File.php | 53 ++++ code/solr/stores/SolrConfigStore_WebDAV.php | 56 ++++ code/solr/tasks/Solr_BuildTask.php | 63 ++++ code/solr/tasks/Solr_Configure.php | 83 +++++ code/solr/tasks/Solr_Reindex.php | 150 +++++++++ code/utils/CombinationsArrayIterator.php | 3 +- code/utils/MultipleArrayIterator.php | 3 +- code/utils/WebDAV.php | 2 +- code/utils/logging/MonologFactory.php | 2 +- code/utils/logging/QueuedJobLogHandler.php | 2 +- code/utils/logging/SearchLogFactory.php | 2 +- composer.json | 4 +- tests/BatchedProcessorTest.php | 37 +-- .../BatchedProcessorTest_Index.php | 15 + .../BatchedProcessorTest_Object.php | 13 + .../BatchedProcessor_QueuedJobService.php | 22 ++ tests/SearchUpdaterTest.php | 5 + ...rchVariantSiteTreeSubsitesPolyhomeTest.php | 4 + tests/SearchVariantVersionedTest.php | 5 + tests/Solr4ServiceTest.php | 20 +- .../Solr4ServiceTest_RecordingService.php | 19 ++ tests/SolrIndexSubsitesTest.php | 15 +- .../SolrIndexSubsitesTest.yml | 0 .../SolrIndexSubsitesTest_Index.php | 15 + tests/SolrIndexTest.php | 58 +--- .../SolrIndexTest_BoostedIndex.php | 22 ++ .../SolrIndexTest/SolrIndexTest_FakeIndex.php | 19 ++ .../SolrIndexTest_FakeIndex2.php | 23 ++ tests/SolrIndexVersionedTest.php | 68 +--- .../SolrDocumentMatcher.php | 39 +++ .../SolrIndexVersionedTest_Object.php | 23 ++ .../SolrVersionedTest_Index.php | 16 + tests/SolrReindexQueuedTest.php | 5 + tests/SolrReindexTest.php | 285 +---------------- .../SolrReindexTest_Handler.php | 39 +++ .../SolrReindexTest/SolrReindexTest_Index.php | 15 + .../SolrReindexTest/SolrReindexTest_Item.php | 22 ++ .../SolrReindexTest_ItemExtension.php | 31 ++ .../SolrReindexTest_RecordingLogger.php | 74 +++++ .../SolrReindexTest_TestHandler.php | 26 ++ .../SolrReindexTest_Variant.php | 117 +++++++ 82 files changed, 1439 insertions(+), 1164 deletions(-) rename code/search/{ => indexes}/SearchIndex.php (90%) create mode 100644 code/search/indexes/SearchIndex_Null.php create mode 100644 code/search/indexes/SearchIndex_Recording.php rename code/search/{ => queries}/SearchQuery.php (86%) create mode 100644 code/search/queries/SearchQuery_Range.php rename code/search/{ => updaters}/SearchUpdater.php (78%) create mode 100644 code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php create mode 100644 code/search/updaters/SearchUpdater_ObjectHandler.php rename code/search/{ => variants}/SearchVariant.php (92%) rename code/search/{ => variants}/SearchVariantSiteTreeSubsitesPolyhome.php (98%) rename code/search/{ => variants}/SearchVariantSubsites.php (98%) rename code/search/{ => variants}/SearchVariantVersioned.php (97%) create mode 100644 code/search/variants/SearchVariant_Caller.php delete mode 100644 code/solr/SolrConfigStore.php rename code/solr/{ => services}/Solr3Service.php (65%) create mode 100644 code/solr/services/Solr3Service_Core.php create mode 100644 code/solr/services/Solr4Service.php rename code/solr/{Solr4Service.php => services/Solr4Service_Core.php} (90%) rename code/solr/{ => services}/SolrService.php (94%) create mode 100644 code/solr/services/SolrService_Core.php create mode 100644 code/solr/stores/SolrConfigStore.php create mode 100644 code/solr/stores/SolrConfigStore_File.php create mode 100644 code/solr/stores/SolrConfigStore_WebDAV.php create mode 100644 code/solr/tasks/Solr_BuildTask.php create mode 100644 code/solr/tasks/Solr_Configure.php create mode 100644 code/solr/tasks/Solr_Reindex.php create mode 100644 tests/BatchedProcessorTest/BatchedProcessorTest_Index.php create mode 100644 tests/BatchedProcessorTest/BatchedProcessorTest_Object.php create mode 100644 tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php create mode 100644 tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php rename tests/{ => SolrIndexSubsitesTest}/SolrIndexSubsitesTest.yml (100%) create mode 100644 tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php create mode 100644 tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php create mode 100644 tests/SolrIndexTest/SolrIndexTest_FakeIndex.php create mode 100644 tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php create mode 100644 tests/SolrIndexVersionedTest/SolrDocumentMatcher.php create mode 100644 tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php create mode 100644 tests/SolrIndexVersionedTest/SolrVersionedTest_Index.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_Handler.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_Index.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_Item.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_ItemExtension.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_RecordingLogger.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_TestHandler.php create mode 100644 tests/SolrReindexTest/SolrReindexTest_Variant.php diff --git a/.travis.yml b/.travis.yml index 303e94c..29a5d37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ language: php sudo: false php: - - 5.4 - 5.5 - 5.6 @@ -14,8 +13,6 @@ env: matrix: include: - - php: 5.3 - env: DB=PGSQL CORE_RELEASE=3.1 - php: 5.6 env: DB=MYSQL CORE_RELEASE=3.2 - php: 5.6 diff --git a/_config.php b/_config.php index c9e422a..a1de033 100644 --- a/_config.php +++ b/_config.php @@ -1,6 +1,4 @@ $class) { - if (!DataObject::has_own_table($class)) { - unset($classes[$i]); - } - } + $idx = array_search('SilverStripe\Core\Object', $classes); + if ($idx !== false) { + array_splice($classes, 0, $idx+1); } +//@todo find another way to determine if a dataobject does not have a table +// if ($dataOnly) { +// foreach ($classes as $i => $class) { +// if (!DataObject::has_own_table($class)) { +// unset($classes[$i]); +// } +// } +// } self::$hierarchy[$key] = $classes; } diff --git a/code/search/SearchIndex.php b/code/search/indexes/SearchIndex.php similarity index 90% rename from code/search/SearchIndex.php rename to code/search/indexes/SearchIndex.php index 7e4ab9a..2e1750d 100644 --- a/code/search/SearchIndex.php +++ b/code/search/indexes/SearchIndex.php @@ -1,5 +1,15 @@ has_one($lookup)) { + if ($hasOne = $singleton->hasOne($lookup)) { $class = $hasOne; $options['lookup_chain'][] = array( 'call' => 'method', 'method' => $lookup, 'through' => 'has_one', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => "{$lookup}ID" ); - } elseif ($hasMany = $singleton->has_many($lookup)) { + } elseif ($hasMany = $singleton->hasMany($lookup)) { $class = $hasMany; $options['multi_valued'] = true; $options['lookup_chain'][] = array( 'call' => 'method', 'method' => $lookup, 'through' => 'has_many', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => $singleton->getRemoteJoinField($lookup, 'has_many') ); - } elseif ($manyMany = $singleton->many_many($lookup)) { + } elseif ($manyMany = $singleton->manyMany($lookup)) { $class = $manyMany[1]; $options['multi_valued'] = true; $options['lookup_chain'][] = array( @@ -105,7 +115,7 @@ abstract class SearchIndex extends ViewableData ); } - if ($class) { + if (is_string($class) && $class) { if (!isset($options['origin'])) { $options['origin'] = $dataclass; } @@ -130,7 +140,7 @@ abstract class SearchIndex extends ViewableData $type = null; $fieldoptions = $options; - $fields = DataObject::database_fields($dataclass); + $fields = DataObject::getSchema()->databaseFields($class); if (isset($fields[$field])) { $type = $fields[$field]; @@ -209,7 +219,7 @@ abstract class SearchIndex extends ViewableData throw new Exception('Can\'t add class to Index after fields have already been added'); } - if (!DataObject::has_own_table($class)) { + if (!DataObject::getSchema()->classHasTable($class)) { throw new InvalidArgumentException('Can\'t add classes which don\'t have data tables (no $db or $has_one set on the class)'); } @@ -286,7 +296,7 @@ abstract class SearchIndex extends ViewableData { foreach ($this->getClasses() as $class => $options) { foreach (SearchIntrospection::hierarchy($class, $includeSubclasses, true) as $dataclass) { - $fields = DataObject::database_fields($dataclass); + $fields = DataObject::getSchema()->databaseFields($class); foreach ($fields as $field => $type) { if (preg_match('/^(\w+)\(/', $type, $match)) { @@ -599,95 +609,3 @@ abstract class SearchIndex extends ViewableData */ abstract public function init(); } - -/** - * A search index that does nothing. Useful for testing - */ -abstract class SearchIndex_Null extends SearchIndex -{ - public function add($object) - { - } - - public function delete($base, $id, $state) - { - } - - public function commit() - { - } -} - -/** - * A search index that just records actions. Useful for testing - */ -abstract class SearchIndex_Recording extends SearchIndex -{ - public $added = array(); - public $deleted = array(); - public $committed = false; - - public function reset() - { - $this->added = array(); - $this->deleted = array(); - $this->committed = false; - } - - public function add($object) - { - $res = array(); - - $res['ID'] = $object->ID; - - foreach ($this->getFieldsIterator() as $name => $field) { - $val = $this->_getFieldValue($object, $field); - $res[$name] = $val; - } - - $this->added[] = $res; - } - - public function getAdded($fields = array()) - { - $res = array(); - - foreach ($this->added as $added) { - $filtered = array(); - foreach ($fields as $field) { - if (isset($added[$field])) { - $filtered[$field] = $added[$field]; - } - } - $res[] = $filtered; - } - - return $res; - } - - public function delete($base, $id, $state) - { - $this->deleted[] = array('base' => $base, 'id' => $id, 'state' => $state); - } - - public function commit() - { - $this->committed = true; - } - - public function getIndexName() - { - return get_class($this); - } - - public function getIsCommitted() - { - return $this->committed; - } - - public function getService() - { - // Causes commits to the service to be redirected back to the same object - return $this; - } -} diff --git a/code/search/indexes/SearchIndex_Null.php b/code/search/indexes/SearchIndex_Null.php new file mode 100644 index 0000000..b2a2896 --- /dev/null +++ b/code/search/indexes/SearchIndex_Null.php @@ -0,0 +1,23 @@ +added = array(); + $this->deleted = array(); + $this->committed = false; + } + + public function add($object) + { + $res = array(); + + $res['ID'] = $object->ID; + + foreach ($this->getFieldsIterator() as $name => $field) { + $val = $this->_getFieldValue($object, $field); + $res[$name] = $val; + } + + $this->added[] = $res; + } + + public function getAdded($fields = array()) + { + $res = array(); + + foreach ($this->added as $added) { + $filtered = array(); + foreach ($fields as $field) { + if (isset($added[$field])) { + $filtered[$field] = $added[$field]; + } + } + $res[] = $filtered; + } + + return $res; + } + + public function delete($base, $id, $state) + { + $this->deleted[] = array('base' => $base, 'id' => $id, 'state' => $state); + } + + public function commit() + { + $this->committed = true; + } + + public function getIndexName() + { + return get_class($this); + } + + public function getIsCommitted() + { + return $this->committed; + } + + public function getService() + { + // Causes commits to the service to be redirected back to the same object + return $this; + } +} diff --git a/code/search/processors/SearchUpdateBatchedProcessor.php b/code/search/processors/SearchUpdateBatchedProcessor.php index b684939..eaf2fd4 100644 --- a/code/search/processors/SearchUpdateBatchedProcessor.php +++ b/code/search/processors/SearchUpdateBatchedProcessor.php @@ -1,5 +1,5 @@ start = $start; - $this->end = $end; - } - - public function start($start) - { - $this->start = $start; - } - - public function end($end) - { - $this->end = $end; - } - - public function isfiltered() - { - return $this->start !== null || $this->end !== null; - } -} diff --git a/code/search/queries/SearchQuery_Range.php b/code/search/queries/SearchQuery_Range.php new file mode 100644 index 0000000..33b35e5 --- /dev/null +++ b/code/search/queries/SearchQuery_Range.php @@ -0,0 +1,34 @@ +start = $start; + $this->end = $end; + } + + public function start($start) + { + $this->start = $start; + } + + public function end($end) + { + $this->end = $end; + } + + public function isfiltered() + { + return $this->start !== null || $this->end !== null; + } +} \ No newline at end of file diff --git a/code/search/SearchUpdater.php b/code/search/updaters/SearchUpdater.php similarity index 78% rename from code/search/SearchUpdater.php rename to code/search/updaters/SearchUpdater.php index 0c836f0..b4460c3 100644 --- a/code/search/SearchUpdater.php +++ b/code/search/updaters/SearchUpdater.php @@ -1,5 +1,8 @@ owner->ID) { - return; - } - - // Force SearchUpdater to mark this record as dirty - $manipulation = array( - $this->owner->ClassName => array( - 'fields' => array(), - 'id' => $this->owner->ID, - 'command' => 'update' - ) - ); - $this->owner->extend('augmentWrite', $manipulation); - SearchUpdater::handle_manipulation($manipulation); - } - - /** - * Forces this object to trigger a re-index in the current state - */ - public function triggerReindex() - { - if (!$this->owner->ID) { - return; - } - - $id = $this->owner->ID; - $class = $this->owner->ClassName; - $state = SearchVariant::current_state($class); - $base = ClassInfo::baseDataClass($class); - $key = "$id:$base:".serialize($state); - - $statefulids = array(array( - 'id' => $id, - 'state' => $state - )); - - $writes = array( - $key => array( - 'base' => $base, - 'class' => $class, - 'id' => $id, - 'statefulids' => $statefulids, - 'fields' => array() - ) - ); - - SearchUpdater::process_writes($writes); - } -} diff --git a/code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php b/code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php new file mode 100644 index 0000000..e6b4e05 --- /dev/null +++ b/code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php @@ -0,0 +1,23 @@ +owner->ID) { + return; + } + + // Force SearchUpdater to mark this record as dirty + $manipulation = array( + $this->owner->ClassName => array( + 'fields' => array(), + 'id' => $this->owner->ID, + 'command' => 'update' + ) + ); + $this->owner->extend('augmentWrite', $manipulation); + SearchUpdater::handle_manipulation($manipulation); + } + + /** + * Forces this object to trigger a re-index in the current state + */ + public function triggerReindex() + { + if (!$this->owner->ID) { + return; + } + + $id = $this->owner->ID; + $class = $this->owner->ClassName; + $state = SearchVariant::current_state($class); + $base = ClassInfo::baseDataClass($class); + $key = "$id:$base:".serialize($state); + + $statefulids = array(array( + 'id' => $id, + 'state' => $state + )); + + $writes = array( + $key => array( + 'base' => $base, + 'class' => $class, + 'id' => $id, + 'statefulids' => $statefulids, + 'fields' => array() + ) + ); + + SearchUpdater::process_writes($writes); + } +} \ No newline at end of file diff --git a/code/search/SearchVariant.php b/code/search/variants/SearchVariant.php similarity index 92% rename from code/search/SearchVariant.php rename to code/search/variants/SearchVariant.php index df6e187..57f6479 100644 --- a/code/search/SearchVariant.php +++ b/code/search/variants/SearchVariant.php @@ -1,5 +1,6 @@ variants = $variants; - } - - public function call($method, &$a1=null, &$a2=null, &$a3=null, &$a4=null, &$a5=null, &$a6=null, &$a7=null) - { - $values = array(); - - foreach ($this->variants as $variant) { - if (method_exists($variant, $method)) { - $value = $variant->$method($a1, $a2, $a3, $a4, $a5, $a6, $a7); - if ($value !== null) { - $values[] = $value; - } - } - } - - return $values; - } -} diff --git a/code/search/SearchVariantSiteTreeSubsitesPolyhome.php b/code/search/variants/SearchVariantSiteTreeSubsitesPolyhome.php similarity index 98% rename from code/search/SearchVariantSiteTreeSubsitesPolyhome.php rename to code/search/variants/SearchVariantSiteTreeSubsitesPolyhome.php index 52fc83d..5101dd1 100644 --- a/code/search/SearchVariantSiteTreeSubsitesPolyhome.php +++ b/code/search/variants/SearchVariantSiteTreeSubsitesPolyhome.php @@ -1,4 +1,5 @@ variants = $variants; + } + + public function call($method, &$a1=null, &$a2=null, &$a3=null, &$a4=null, &$a5=null, &$a6=null, &$a7=null) + { + $values = array(); + + foreach ($this->variants as $variant) { + if (method_exists($variant, $method)) { + $value = $variant->$method($a1, $a2, $a3, $a4, $a5, $a6, $a7); + if ($value !== null) { + $values[] = $value; + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/code/solr/Solr.php b/code/solr/Solr.php index fb460fa..98d3972 100644 --- a/code/solr/Solr.php +++ b/code/solr/Solr.php @@ -1,9 +1,8 @@ logger; - } - - /** - * Assign a new logger - * - * @param LoggerInterface $logger - */ - public function setLogger(LoggerInterface $logger) - { - $this->logger = $logger; - } - - /** - * @return SearchLogFactory - */ - protected function getLoggerFactory() - { - return Injector::inst()->get('SearchLogFactory'); - } - - /** - * Setup task - * - * @param SS_HTTPReqest $request - */ - public function run($request) - { - $name = get_class($this); - $verbose = $request->getVar('verbose'); - - // Set new logger - $logger = $this - ->getLoggerFactory() - ->getOutputLogger($name, $verbose); - $this->setLogger($logger); - } -} - - -class Solr_Configure extends Solr_BuildTask -{ - protected $enabled = true; - - public function run($request) - { - parent::run($request); - - // Find the IndexStore handler, which will handle uploading config files to Solr - $store = $this->getSolrConfigStore(); - $indexes = Solr::get_indexes(); - foreach ($indexes as $instance) { - try { - $this->updateIndex($instance, $store); - } catch (Exception $e) { - // We got an exception. Warn, but continue to next index. - $this - ->getLogger() - ->error("Failure: " . $e->getMessage()); - } - } - } - - /** - * Update the index on the given store - * - * @param SolrIndex $instance Instance - * @param SolrConfigStore $store - */ - protected function updateIndex($instance, $store) - { - $index = $instance->getIndexName(); - $this->getLogger()->info("Configuring $index."); - - // Upload the config files for this index - $this->getLogger()->info("Uploading configuration ..."); - $instance->uploadConfig($store); - - // Then tell Solr to use those config files - $service = Solr::service(); - if ($service->coreIsActive($index)) { - $this->getLogger()->info("Reloading core ..."); - $service->coreReload($index); - } else { - $this->getLogger()->info("Creating core ..."); - $service->coreCreate($index, $store->instanceDir($index)); - } - - $this->getLogger()->info("Done"); - } - - /** - * Get config store - * - * @return SolrConfigStore - */ - protected function getSolrConfigStore() - { - $options = Solr::solr_options(); - - if (!isset($options['indexstore']) || !($indexstore = $options['indexstore'])) { - user_error('No index configuration for Solr provided', E_USER_ERROR); - } - - // Find the IndexStore handler, which will handle uploading config files to Solr - $mode = $indexstore['mode']; - - if ($mode == 'file') { - return new SolrConfigStore_File($indexstore); - } elseif ($mode == 'webdav') { - return new SolrConfigStore_WebDAV($indexstore); - } elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, 'SolrConfigStore')) { - return new $mode($indexstore); - } else { - user_error('Unknown Solr index mode '.$indexstore['mode'], E_USER_ERROR); - } - } -} - -/** - * Task used for both initiating a new reindex, as well as for processing incremental batches - * within a reindex. - * - * When running a complete reindex you can provide any of the following - * - class (to limit to a single class) - * - verbose (optional) - * - * When running with a single batch, provide the following querystring arguments: - * - start - * - index - * - class - * - variantstate - * - verbose (optional) - */ -class Solr_Reindex extends Solr_BuildTask -{ - protected $enabled = true; - - /** - * Number of records to load and index per request - * - * @var int - * @config - */ - private static $recordsPerRequest = 200; - - /** - * Get the reindex handler - * - * @return SolrReindexHandler - */ - protected function getHandler() - { - return Injector::inst()->get('SolrReindexHandler'); - } - - /** - * @param SS_HTTPRequest $request - */ - public function run($request) - { - parent::run($request); - - // Reset state - $originalState = SearchVariant::current_state(); - $this->doReindex($request); - SearchVariant::activate_state($originalState); - } - - /** - * @param SS_HTTPRequest $request - */ - protected function doReindex($request) - { - $class = $request->getVar('class'); - - $index = $request->getVar('index'); - - //find the index classname by IndexName - // this is for when index names do not match the class name (this can be done by overloading getIndexName() on - // indexes - if ($index && !ClassInfo::exists($index)) { - foreach(ClassInfo::subclassesFor('SolrIndex') as $solrIndexClass) { - $reflection = new ReflectionClass($solrIndexClass); - //skip over abstract classes - if (!$reflection->isInstantiable()) { - continue; - } - //check the indexname matches the index passed to the request - if (!strcasecmp(singleton($solrIndexClass)->getIndexName(), $index)) { - //if we match, set the correct index name and move on - $index = $solrIndexClass; - break; - } - } - } - - // Deprecated reindex mechanism - $start = $request->getVar('start'); - if ($start !== null) { - // Run single batch directly - $indexInstance = singleton($index); - $state = json_decode($request->getVar('variantstate'), true); - $this->runFrom($indexInstance, $class, $start, $state); - return; - } - - // Check if we are re-indexing a single group - // If not using queuedjobs, we need to invoke Solr_Reindex as a separate process - // Otherwise each group is processed via a SolrReindexGroupJob - $groups = $request->getVar('groups'); - $handler = $this->getHandler(); - if ($groups) { - // Run grouped batches (id % groups = group) - $group = $request->getVar('group'); - $indexInstance = singleton($index); - $state = json_decode($request->getVar('variantstate'), true); - - $handler->runGroup($this->getLogger(), $indexInstance, $state, $class, $groups, $group); - return; - } - - // If run at the top level, delegate to appropriate handler - $self = get_class($this); - $handler->triggerReindex($this->getLogger(), $this->config()->recordsPerRequest, $self, $class); - } - - /** - * @deprecated since version 2.0.0 - */ - protected function runFrom($index, $class, $start, $variantstate) - { - DeprecationTest_Deprecation::notice('2.0.0', 'Solr_Reindex now uses a new grouping mechanism'); - - // Set time limit and state - increase_time_limit_to(); - SearchVariant::activate_state($variantstate); - - // Generate filtered list - $items = DataList::create($class) - ->limit($this->config()->recordsPerRequest, $start); - - // Add child filter - $classes = $index->getClasses(); - $options = $classes[$class]; - if (!$options['include_children']) { - $items = $items->filter('ClassName', $class); - } - - // Process selected records in this class - $this->getLogger()->info("Adding $class"); - foreach ($items->sort("ID") as $item) { - $this->getLogger()->debug($item->ID); - - // See SearchUpdater_ObjectHandler::triggerReindex - $item->triggerReindex(); - $item->destroy(); - } - - $this->getLogger()->info("Done"); - } -} +} \ No newline at end of file diff --git a/code/solr/SolrConfigStore.php b/code/solr/SolrConfigStore.php deleted file mode 100644 index 0f16439..0000000 --- a/code/solr/SolrConfigStore.php +++ /dev/null @@ -1,134 +0,0 @@ -local = $config['path']; - $this->remote = isset($config['remotepath']) ? $config['remotepath'] : $config['path']; - } - - public function getTargetDir($index) - { - $targetDir = "{$this->local}/{$index}/conf"; - - if (!is_dir($targetDir)) { - $worked = @mkdir($targetDir, 0770, true); - - if (!$worked) { - throw new RuntimeException( - sprintf('Failed creating target directory %s, please check permissions', $targetDir) - ); - } - } - - return $targetDir; - } - - public function uploadFile($index, $file) - { - $targetDir = $this->getTargetDir($index); - copy($file, $targetDir.'/'.basename($file)); - } - - public function uploadString($index, $filename, $string) - { - $targetDir = $this->getTargetDir($index); - file_put_contents("$targetDir/$filename", $string); - } - - public function instanceDir($index) - { - return $this->remote.'/'.$index; - } -} - -/** - * Class SolrConfigStore_WebDAV - * - * A ConfigStore that uploads files to a Solr instance via a WebDAV server - */ -class SolrConfigStore_WebDAV implements SolrConfigStore -{ - public function __construct($config) - { - $options = Solr::solr_options(); - - $this->url = implode('', array( - 'http://', - isset($config['auth']) ? $config['auth'].'@' : '', - $options['host'].':'.(isset($config['port']) ? $config['port'] : $options['port']), - $config['path'] - )); - $this->remote = $config['remotepath']; - } - - public function getTargetDir($index) - { - $indexdir = "{$this->url}/$index"; - if (!WebDAV::exists($indexdir)) { - WebDAV::mkdir($indexdir); - } - - $targetDir = "{$this->url}/$index/conf"; - if (!WebDAV::exists($targetDir)) { - WebDAV::mkdir($targetDir); - } - - return $targetDir; - } - - public function uploadFile($index, $file) - { - $targetDir = $this->getTargetDir($index); - WebDAV::upload_from_file($file, $targetDir.'/'.basename($file)); - } - - public function uploadString($index, $filename, $string) - { - $targetDir = $this->getTargetDir($index); - WebDAV::upload_from_string($string, "$targetDir/$filename"); - } - - public function instanceDir($index) - { - return $this->remote ? "{$this->remote}/$index" : $index; - } -} diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index 49e1dc8..76842a2 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -1,7 +1,10 @@ '; return $this->_sendRawPost($this->_updateUrl, $rawPost, $timeout); } - + /** - * @inheritdoc + * @inheritdoc * @see Solr4Service_Core::addDocuments */ - public function addDocument(Apache_Solr_Document $document, $allowDups = false, + public function addDocument(\Apache_Solr_Document $document, $allowDups = false, $overwritePending = true, $overwriteCommitted = true, $commitWithin = 0 ) { return $this->addDocuments(array($document), $allowDups, $overwritePending, $overwriteCommitted, $commitWithin); @@ -51,8 +53,3 @@ class Solr4Service_Core extends SolrService_Core return $this->add($rawPost); } } - -class Solr4Service extends SolrService -{ - private static $core_class = 'Solr4Service_Core'; -} diff --git a/code/solr/SolrService.php b/code/solr/services/SolrService.php similarity index 94% rename from code/solr/SolrService.php rename to code/solr/services/SolrService.php index 7b8c448..6aae39b 100644 --- a/code/solr/SolrService.php +++ b/code/solr/services/SolrService.php @@ -1,14 +1,8 @@ local = $config['path']; + $this->remote = isset($config['remotepath']) ? $config['remotepath'] : $config['path']; + } + + public function getTargetDir($index) + { + $targetDir = "{$this->local}/{$index}/conf"; + + if (!is_dir($targetDir)) { + $worked = @mkdir($targetDir, 0770, true); + + if (!$worked) { + throw new RuntimeException( + sprintf('Failed creating target directory %s, please check permissions', $targetDir) + ); + } + } + + return $targetDir; + } + + public function uploadFile($index, $file) + { + $targetDir = $this->getTargetDir($index); + copy($file, $targetDir.'/'.basename($file)); + } + + public function uploadString($index, $filename, $string) + { + $targetDir = $this->getTargetDir($index); + file_put_contents("$targetDir/$filename", $string); + } + + public function instanceDir($index) + { + return $this->remote.'/'.$index; + } +} \ No newline at end of file diff --git a/code/solr/stores/SolrConfigStore_WebDAV.php b/code/solr/stores/SolrConfigStore_WebDAV.php new file mode 100644 index 0000000..96259cb --- /dev/null +++ b/code/solr/stores/SolrConfigStore_WebDAV.php @@ -0,0 +1,56 @@ +url = implode('', array( + 'http://', + isset($config['auth']) ? $config['auth'].'@' : '', + $options['host'].':'.(isset($config['port']) ? $config['port'] : $options['port']), + $config['path'] + )); + $this->remote = $config['remotepath']; + } + + public function getTargetDir($index) + { + $indexdir = "{$this->url}/$index"; + if (!WebDAV::exists($indexdir)) { + WebDAV::mkdir($indexdir); + } + + $targetDir = "{$this->url}/$index/conf"; + if (!WebDAV::exists($targetDir)) { + WebDAV::mkdir($targetDir); + } + + return $targetDir; + } + + public function uploadFile($index, $file) + { + $targetDir = $this->getTargetDir($index); + WebDAV::upload_from_file($file, $targetDir.'/'.basename($file)); + } + + public function uploadString($index, $filename, $string) + { + $targetDir = $this->getTargetDir($index); + WebDAV::upload_from_string($string, "$targetDir/$filename"); + } + + public function instanceDir($index) + { + return $this->remote ? "{$this->remote}/$index" : $index; + } +} \ No newline at end of file diff --git a/code/solr/tasks/Solr_BuildTask.php b/code/solr/tasks/Solr_BuildTask.php new file mode 100644 index 0000000..d26f647 --- /dev/null +++ b/code/solr/tasks/Solr_BuildTask.php @@ -0,0 +1,63 @@ +get('Logger'); + } + + /** + * Assign a new logger + * + * @param LoggerInterface $logger + */ + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * @return SearchLogFactory + */ + protected function getLoggerFactory() + { +// return Injector::inst()->get('SearchLogFactory'); + } + + /** + * Setup task + * + * @param SS_HTTPReqest $request + */ + public function run($request) + { + $name = get_class($this); + $verbose = $request->getVar('verbose'); + + // Set new logger + $logger = $this + ->getLoggerFactory(); +//@todo: Cannot instantiate interface SearchLogFactory +// ->getOutputLogger($name, $verbose); + $this->setLogger($logger); + } +} diff --git a/code/solr/tasks/Solr_Configure.php b/code/solr/tasks/Solr_Configure.php new file mode 100644 index 0000000..aec6356 --- /dev/null +++ b/code/solr/tasks/Solr_Configure.php @@ -0,0 +1,83 @@ +getSolrConfigStore(); + + $indexes = Solr::get_indexes(); + foreach ($indexes as $instance) { + try { + $this->updateIndex($instance, $store); + } catch (Exception $e) { + // We got an exception. Warn, but continue to next index. + $this + ->getLogger() + ->error("Failure: " . $e->getMessage()); + } + } + } + + /** + * Update the index on the given store + * + * @param SolrIndex $instance Instance + * @param SolrConfigStore $store + */ + protected function updateIndex($instance, $store) + { + $index = $instance->getIndexName(); + $this->getLogger()->addInfo("Configuring $index."); + + // Upload the config files for this index + $this->getLogger()->addInfo("Uploading configuration ..."); + $instance->uploadConfig($store); + + // Then tell Solr to use those config files + $service = Solr::service(); + if ($service->coreIsActive($index)) { + $this->getLogger()->addInfo("Reloading core ..."); + $service->coreReload($index); + } else { + $this->getLogger()->addInfo("Creating core ..."); + $service->coreCreate($index, $store->instanceDir($index)); + } + + $this->getLogger()->addInfo("Done"); + } + + /** + * Get config store + * + * @return SolrConfigStore + */ + protected function getSolrConfigStore() + { + $options = Solr::solr_options(); + + if (!isset($options['indexstore']) || !($indexstore = $options['indexstore'])) { + throw new Exception('No index configuration for Solr provided', E_USER_ERROR); + } + + // Find the IndexStore handler, which will handle uploading config files to Solr + $mode = $indexstore['mode']; + + if ($mode == 'file') { + return new SolrConfigStore_File($indexstore); + } elseif ($mode == 'webdav') { + return new SolrConfigStore_WebDAV($indexstore); + } elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, 'SolrConfigStore')) { + return new $mode($indexstore); + } else { + user_error('Unknown Solr index mode '.$indexstore['mode'], E_USER_ERROR); + } + } +} \ No newline at end of file diff --git a/code/solr/tasks/Solr_Reindex.php b/code/solr/tasks/Solr_Reindex.php new file mode 100644 index 0000000..0adb70a --- /dev/null +++ b/code/solr/tasks/Solr_Reindex.php @@ -0,0 +1,150 @@ +get('SolrReindexImmediateHandler'); + } + + /** + * @param SS_HTTPRequest $request + */ + public function run($request) + { + parent::run($request); + + // Reset state + $originalState = SearchVariant::current_state(); + $this->doReindex($request); + SearchVariant::activate_state($originalState); + } + + /** + * @param SS_HTTPRequest $request + */ + protected function doReindex($request) + { + $class = $request->getVar('class'); + + $index = $request->getVar('index'); + + //find the index classname by IndexName + // this is for when index names do not match the class name (this can be done by overloading getIndexName() on + // indexes + if ($index && !ClassInfo::exists($index)) { + foreach(ClassInfo::subclassesFor('SolrIndex') as $solrIndexClass) { + $reflection = new ReflectionClass($solrIndexClass); + //skip over abstract classes + if (!$reflection->isInstantiable()) { + continue; + } + //check the indexname matches the index passed to the request + if (!strcasecmp(singleton($solrIndexClass)->getIndexName(), $index)) { + //if we match, set the correct index name and move on + $index = $solrIndexClass; + break; + } + } + } + + // Deprecated reindex mechanism + $start = $request->getVar('start'); + if ($start !== null) { + // Run single batch directly + $indexInstance = singleton($index); + $state = json_decode($request->getVar('variantstate'), true); + $this->runFrom($indexInstance, $class, $start, $state); + return; + } + + // Check if we are re-indexing a single group + // If not using queuedjobs, we need to invoke Solr_Reindex as a separate process + // Otherwise each group is processed via a SolrReindexGroupJob + $groups = $request->getVar('groups'); + + $handler = $this->getHandler(); + if ($groups) { + // Run grouped batches (id % groups = group) + $group = $request->getVar('group'); + $indexInstance = singleton($index); + $state = json_decode($request->getVar('variantstate'), true); + + $handler->runGroup($this->getLogger(), $indexInstance, $state, $class, $groups, $group); + return; + } + + // If run at the top level, delegate to appropriate handler + $self = get_class($this); + $handler->triggerReindex($this->getLogger(), $this->config()->recordsPerRequest, $self, $class); + } + + /** + * @deprecated since version 2.0.0 + */ + protected function runFrom($index, $class, $start, $variantstate) + { + DeprecationTest_Deprecation::notice('2.0.0', 'Solr_Reindex now uses a new grouping mechanism'); + + // Set time limit and state + increase_time_limit_to(); + SearchVariant::activate_state($variantstate); + + // Generate filtered list + $items = DataList::create($class) + ->limit($this->config()->recordsPerRequest, $start); + + // Add child filter + $classes = $index->getClasses(); + $options = $classes[$class]; + if (!$options['include_children']) { + $items = $items->filter('ClassName', $class); + } + + // Process selected records in this class + $this->getLogger()->info("Adding $class"); + foreach ($items->sort("ID") as $item) { + $this->getLogger()->debug($item->ID); + + // See SearchUpdater_ObjectHandler::triggerReindex + $item->triggerReindex(); + $item->destroy(); + } + + $this->getLogger()->info("Done"); + } +} diff --git a/code/utils/CombinationsArrayIterator.php b/code/utils/CombinationsArrayIterator.php index 69e5727..0e873a8 100644 --- a/code/utils/CombinationsArrayIterator.php +++ b/code/utils/CombinationsArrayIterator.php @@ -1,5 +1,6 @@ 'Varchar' - ); -} - -class BatchedProcessorTest_Index extends SearchIndex_Recording implements TestOnly -{ - public function init() - { - $this->addClass('BatchedProcessorTest_Object'); - $this->addFilterField('TestText'); - } -} - -class BatchedProcessor_QueuedJobService -{ - protected $jobs = array(); - - public function queueJob(QueuedJob $job, $startAfter = null, $userId = null, $queueName = null) - { - $this->jobs[] = array( - 'job' => $job, - 'startAfter' => $startAfter - ); - return $job; - } - - public function getJobs() - { - return $this->jobs; - } -} +use SilverStripe\Dev\SapphireTest; +use SilverStripe\FullTextSearch\Search\FullTextSearch; /** * Tests {@see SearchUpdateQueuedJobProcessor} diff --git a/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php b/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php new file mode 100644 index 0000000..7116af1 --- /dev/null +++ b/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php @@ -0,0 +1,15 @@ +addClass('BatchedProcessorTest_Object'); + $this->addFilterField('TestText'); + } +} diff --git a/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php b/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php new file mode 100644 index 0000000..b596a3a --- /dev/null +++ b/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php @@ -0,0 +1,13 @@ + 'Varchar' + ); +} diff --git a/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php b/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php new file mode 100644 index 0000000..1cf5253 --- /dev/null +++ b/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php @@ -0,0 +1,22 @@ +jobs[] = array( + 'job' => $job, + 'startAfter' => $startAfter + ); + return $job; + } + + public function getJobs() + { + return $this->jobs; + } +} diff --git a/tests/SearchUpdaterTest.php b/tests/SearchUpdaterTest.php index d2211c0..ee2df21 100644 --- a/tests/SearchUpdaterTest.php +++ b/tests/SearchUpdaterTest.php @@ -1,5 +1,10 @@ setField('id', $id); $document->setField('title', "Item $id"); return $document; @@ -58,16 +63,3 @@ class Solr4ServiceTest extends SapphireTest ); } } - -class Solr4ServiceTest_RecordingService extends Solr4Service_Core -{ - protected function _sendRawPost($url, $rawPost, $timeout = false, $contentType = 'text/xml; charset=UTF-8') - { - return $rawPost; - } - - protected function _sendRawGet($url, $timeout = false) - { - return $url; - } -} diff --git a/tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php b/tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php new file mode 100644 index 0000000..480ab1b --- /dev/null +++ b/tests/Solr4ServiceTest/Solr4ServiceTest_RecordingService.php @@ -0,0 +1,19 @@ +addClass('File'); - $this->addClass('SiteTree'); - $this->addAllFulltextFields(); - } -} diff --git a/tests/SolrIndexSubsitesTest.yml b/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest.yml similarity index 100% rename from tests/SolrIndexSubsitesTest.yml rename to tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest.yml diff --git a/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php b/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php new file mode 100644 index 0000000..97e9dfb --- /dev/null +++ b/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php @@ -0,0 +1,15 @@ +addClass('File'); + $this->addClass('SiteTree'); + $this->addAllFulltextFields(); + } +} diff --git a/tests/SolrIndexTest.php b/tests/SolrIndexTest.php index c710113..0a6b82f 100644 --- a/tests/SolrIndexTest.php +++ b/tests/SolrIndexTest.php @@ -1,4 +1,11 @@ addClass('SearchUpdaterTest_Container'); - - $this->addFilterField('Field1'); - $this->addFilterField('MyDate', 'Date'); - $this->addFilterField('HasOneObject.Field1'); - $this->addFilterField('HasManyObjects.Field1'); - $this->addFilterField('ManyManyObjects.Field1'); - } -} - - -class SolrIndexTest_FakeIndex2 extends SolrIndex -{ - protected function getStoredDefault() - { - // Override isDev defaulting to stored - return 'false'; - } - - public function init() - { - $this->addClass('SearchUpdaterTest_Container'); - $this->addFilterField('MyDate', 'Date'); - $this->addFilterField('HasOneObject.Field1'); - $this->addFilterField('HasManyObjects.Field1'); - $this->addFilterField('ManyManyObjects.Field1'); - } -} - - -class SolrIndexTest_BoostedIndex extends SolrIndex -{ - protected function getStoredDefault() - { - // Override isDev defaulting to stored - return 'false'; - } - - public function init() - { - $this->addClass('SearchUpdaterTest_Container'); - $this->addAllFulltextFields(); - $this->setFieldBoosting('SearchUpdaterTest_Container_Field1', 1.5); - $this->addBoostedField('Field2', null, array(), 2.1); - } -} diff --git a/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php b/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php new file mode 100644 index 0000000..65dae12 --- /dev/null +++ b/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php @@ -0,0 +1,22 @@ +addClass('SearchUpdaterTest_Container'); + $this->addAllFulltextFields(); + $this->setFieldBoosting('SearchUpdaterTest_Container_Field1', 1.5); + $this->addBoostedField('Field2', null, array(), 2.1); + } +} diff --git a/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php b/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php new file mode 100644 index 0000000..b04e6ce --- /dev/null +++ b/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php @@ -0,0 +1,19 @@ +addClass('SearchUpdaterTest_Container'); + + $this->addFilterField('Field1'); + $this->addFilterField('MyDate', 'Date'); + $this->addFilterField('HasOneObject.Field1'); + $this->addFilterField('HasManyObjects.Field1'); + $this->addFilterField('ManyManyObjects.Field1'); + } +} diff --git a/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php b/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php new file mode 100644 index 0000000..a9b58ac --- /dev/null +++ b/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php @@ -0,0 +1,23 @@ +addClass('SearchUpdaterTest_Container'); + $this->addFilterField('MyDate', 'Date'); + $this->addFilterField('HasOneObject.Field1'); + $this->addFilterField('HasManyObjects.Field1'); + $this->addFilterField('ManyManyObjects.Field1'); + } +} diff --git a/tests/SolrIndexVersionedTest.php b/tests/SolrIndexVersionedTest.php index f9df86f..4533576 100644 --- a/tests/SolrIndexVersionedTest.php +++ b/tests/SolrIndexVersionedTest.php @@ -1,5 +1,11 @@ deleteById($this->getExpectedDocumentId($id, 'Live')); } } - - -class SolrVersionedTest_Index extends SolrIndex -{ - public function init() - { - $this->addClass('SearchVariantVersionedTest_Item'); - $this->addClass('SolrIndexVersionedTest_Object'); - $this->addFilterField('TestText'); - $this->addFulltextField('Content'); - } -} - -/** - * Non-sitetree versioned dataobject - */ -class SolrIndexVersionedTest_Object extends DataObject implements TestOnly { - - private static $extensions = array( - 'Versioned' - ); - - private static $db = array( - 'Title' => 'Varchar', - 'Content' => 'Text', - 'TestText' => 'Varchar', - ); -} - -if (!class_exists('Phockito')) { - return; -} - -class SolrDocumentMatcher extends Hamcrest_BaseMatcher -{ - protected $properties; - - public function __construct($properties) - { - $this->properties = $properties; - } - - public function describeTo(\Hamcrest_Description $description) - { - $description->appendText('Apache_Solr_Document with properties '.var_export($this->properties, true)); - } - - public function matches($item) - { - if (! ($item instanceof Apache_Solr_Document)) { - return false; - } - - foreach ($this->properties as $key => $value) { - if ($item->{$key} != $value) { - return false; - } - } - - return true; - } -} diff --git a/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php b/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php new file mode 100644 index 0000000..5c9298e --- /dev/null +++ b/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php @@ -0,0 +1,39 @@ +properties = $properties; + } + + public function describeTo(\Hamcrest_Description $description) + { + $description->appendText('Apache_Solr_Document with properties '.var_export($this->properties, true)); + } + + public function matches($item) + { + if (! ($item instanceof Apache_Solr_Document)) { + return false; + } + + foreach ($this->properties as $key => $value) { + if ($item->{$key} != $value) { + return false; + } + } + + return true; + } +} diff --git a/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php b/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php new file mode 100644 index 0000000..62059b2 --- /dev/null +++ b/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php @@ -0,0 +1,23 @@ + 'Varchar', + 'Content' => 'Text', + 'TestText' => 'Varchar', + ]; +} diff --git a/tests/SolrIndexVersionedTest/SolrVersionedTest_Index.php b/tests/SolrIndexVersionedTest/SolrVersionedTest_Index.php new file mode 100644 index 0000000..7ac3a5b --- /dev/null +++ b/tests/SolrIndexVersionedTest/SolrVersionedTest_Index.php @@ -0,0 +1,16 @@ +addClass('SearchVariantVersionedTest_Item'); + $this->addClass('SolrIndexVersionedTest_Object'); + $this->addFilterField('TestText'); + $this->addFulltextField('Content'); + } +} diff --git a/tests/SolrReindexQueuedTest.php b/tests/SolrReindexQueuedTest.php index f3339f2..ed7aa0c 100644 --- a/tests/SolrReindexQueuedTest.php +++ b/tests/SolrReindexQueuedTest.php @@ -1,5 +1,10 @@ getIndexName(); - $stateName = json_encode($state); - $logger->info("Called processGroup with {$indexName}, {$stateName}, {$class}, group {$group} of {$groups}"); - } - - public function triggerReindex(LoggerInterface $logger, $batchSize, $taskName, $classes = null) - { - $logger->info("Called triggerReindex"); - } -} - - -class SolrReindexTest_Index extends SolrIndex implements TestOnly -{ - public function init() - { - $this->addClass('SolrReindexTest_Item'); - $this->addAllFulltextFields(); - } -} - -/** - * Does not have any variant extensions - */ -class SolrReindexTest_Item extends DataObject implements TestOnly -{ - private static $extensions = array( - 'SolrReindexTest_ItemExtension' - ); - - private static $db = array( - 'Title' => 'Varchar(255)', - 'Variant' => 'Int(0)' - ); -} - -/** - * Select only records in the current variant - */ -class SolrReindexTest_ItemExtension extends DataExtension implements TestOnly -{ - /** - * Filter records on the current variant - * - * @param SQLQuery $query - * @param DataQuery $dataQuery - */ - public function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery = null) - { - $variant = SolrReindexTest_Variant::get_current(); - if ($variant !== null && !$query->filtersOnID()) { - $sqlVariant = Convert::raw2sql($variant); - $query->addWhere("\"Variant\" = '{$sqlVariant}'"); - } - } -} - - -/** - * Dummy variant that selects items with field Varient matching the current value - * - * Variant states are 0 and 1, or null if disabled - */ -class SolrReindexTest_Variant extends SearchVariant implements TestOnly -{ - /** - * Value of this variant (either null, 0, or 1) - * - * @var int|null - */ - protected static $current = null; - - /** - * Activate this variant - */ - public static function enable() - { - self::disable(); - - self::$current = 0; - self::$variants = array( - 'SolrReindexTest_Variant' => singleton('SolrReindexTest_Variant') - ); - } - - /** - * Disable this variant and reset - */ - public static function disable() - { - self::$current = null; - self::$variants = null; - self::$class_variants = array(); - self::$call_instances = array(); - } - - public function activateState($state) - { - self::set_current($state); - } - - /** - * Set the current variant to the given state - * - * @param int $current 0, 1, 2, or null (disabled) - */ - public static function set_current($current) - { - self::$current = $current; - } - - /** - * Get the current state - * - * @return string|null - */ - public static function get_current() - { - // Always use string values for states for consistent json_encode value - if (isset(self::$current)) { - return (string)self::$current; - } - } - - public function alterDefinition($class, $index) - { - $self = get_class($this); - - $this->addFilterField($index, '_testvariant', array( - 'name' => '_testvariant', - 'field' => '_testvariant', - 'fullfield' => '_testvariant', - 'base' => ClassInfo::baseDataClass($class), - 'origin' => $class, - 'type' => 'Int', - 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) - )); - } - - public function alterQuery($query, $index) - { - // I guess just calling it _testvariant is ok? - $query->filter('_testvariant', $this->currentState()); - } - - public function appliesTo($class, $includeSubclasses) - { - return $class === 'SolrReindexTest_Item' || - ($includeSubclasses && is_subclass_of($class, 'SolrReindexTest_Item', true)); - } - - public function appliesToEnvironment() - { - // Set to null to disable - return self::$current !== null; - } - - public function currentState() - { - return self::get_current(); - } - - public function reindexStates() - { - // Always use string values for states for consistent json_encode value - return array('0', '1', '2'); - } -} - -/** - * Test logger for recording messages - */ -class SolrReindexTest_RecordingLogger extends Logger implements TestOnly -{ - /** - * @var SolrReindexTest_Handler - */ - protected $testHandler = null; - - public function __construct($name = 'testlogger', array $handlers = array(), array $processors = array()) - { - parent::__construct($name, $handlers, $processors); - - $this->testHandler = new SolrReindexTest_Handler(); - $this->pushHandler($this->testHandler); - } - - /** - * @return array - */ - public function getMessages() - { - return $this->testHandler->getMessages(); - } - - /** - * Clear all messages - */ - public function clear() - { - $this->testHandler->clear(); - } - - /** - * Get messages with the given filter - * - * @param string $containing - * @return array Filtered array - */ - public function filterMessages($containing) - { - return array_values(array_filter( - $this->getMessages(), - function ($content) use ($containing) { - return stripos($content, $containing) !== false; - } - )); - } - - /** - * Count all messages containing the given substring - * - * @param string $containing Message to filter by - * @return int - */ - public function countMessages($containing = null) - { - if ($containing) { - $messages = $this->filterMessages($containing); - } else { - $messages = $this->getMessages(); - } - return count($messages); - } -} - -/** - * Logger for recording messages for later retrieval - */ -class SolrReindexTest_Handler extends AbstractProcessingHandler implements TestOnly -{ - /** - * Messages - * - * @var array - */ - protected $messages = array(); - - /** - * Get all messages - * - * @return array - */ - public function getMessages() - { - return $this->messages; - } - - public function clear() - { - $this->messages = array(); - } - - protected function write(array $record) - { - $this->messages[] = $record['message']; - } -} diff --git a/tests/SolrReindexTest/SolrReindexTest_Handler.php b/tests/SolrReindexTest/SolrReindexTest_Handler.php new file mode 100644 index 0000000..ea29bcd --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_Handler.php @@ -0,0 +1,39 @@ +messages; + } + + public function clear() + { + $this->messages = array(); + } + + protected function write(array $record) + { + $this->messages[] = $record['message']; + } +} diff --git a/tests/SolrReindexTest/SolrReindexTest_Index.php b/tests/SolrReindexTest/SolrReindexTest_Index.php new file mode 100644 index 0000000..64e85b2 --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_Index.php @@ -0,0 +1,15 @@ +addClass('SolrReindexTest_Item'); + $this->addAllFulltextFields(); + } +} diff --git a/tests/SolrReindexTest/SolrReindexTest_Item.php b/tests/SolrReindexTest/SolrReindexTest_Item.php new file mode 100644 index 0000000..6a08387 --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_Item.php @@ -0,0 +1,22 @@ + 'Varchar(255)', + 'Variant' => 'Int(0)' + ); +} diff --git a/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php b/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php new file mode 100644 index 0000000..9981932 --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_ItemExtension.php @@ -0,0 +1,31 @@ +filtersOnID()) { + $sqlVariant = Convert::raw2sql($variant); + $query->addWhere("\"Variant\" = '{$sqlVariant}'"); + } + } +} diff --git a/tests/SolrReindexTest/SolrReindexTest_RecordingLogger.php b/tests/SolrReindexTest/SolrReindexTest_RecordingLogger.php new file mode 100644 index 0000000..3606e02 --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_RecordingLogger.php @@ -0,0 +1,74 @@ +testHandler = new SolrReindexTest_Handler(); + $this->pushHandler($this->testHandler); + } + + /** + * @return array + */ + public function getMessages() + { + return $this->testHandler->getMessages(); + } + + /** + * Clear all messages + */ + public function clear() + { + $this->testHandler->clear(); + } + + /** + * Get messages with the given filter + * + * @param string $containing + * @return array Filtered array + */ + public function filterMessages($containing) + { + return array_values(array_filter( + $this->getMessages(), + function ($content) use ($containing) { + return stripos($content, $containing) !== false; + } + )); + } + + /** + * Count all messages containing the given substring + * + * @param string $containing Message to filter by + * @return int + */ + public function countMessages($containing = null) + { + if ($containing) { + $messages = $this->filterMessages($containing); + } else { + $messages = $this->getMessages(); + } + return count($messages); + } +} diff --git a/tests/SolrReindexTest/SolrReindexTest_TestHandler.php b/tests/SolrReindexTest/SolrReindexTest_TestHandler.php new file mode 100644 index 0000000..fd86b88 --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_TestHandler.php @@ -0,0 +1,26 @@ +getIndexName(); + $stateName = json_encode($state); + $logger->info("Called processGroup with {$indexName}, {$stateName}, {$class}, group {$group} of {$groups}"); + } + + public function triggerReindex(LoggerInterface $logger, $batchSize, $taskName, $classes = null) + { + $logger->info("Called triggerReindex"); + } +} diff --git a/tests/SolrReindexTest/SolrReindexTest_Variant.php b/tests/SolrReindexTest/SolrReindexTest_Variant.php new file mode 100644 index 0000000..dbb6115 --- /dev/null +++ b/tests/SolrReindexTest/SolrReindexTest_Variant.php @@ -0,0 +1,117 @@ + singleton('SolrReindexTest_Variant') + ); + } + + /** + * Disable this variant and reset + */ + public static function disable() + { + self::$current = null; + self::$variants = null; + self::$class_variants = array(); + self::$call_instances = array(); + } + + public function activateState($state) + { + self::set_current($state); + } + + /** + * Set the current variant to the given state + * + * @param int $current 0, 1, 2, or null (disabled) + */ + public static function set_current($current) + { + self::$current = $current; + } + + /** + * Get the current state + * + * @return string|null + */ + public static function get_current() + { + // Always use string values for states for consistent json_encode value + if (isset(self::$current)) { + return (string)self::$current; + } + } + + public function alterDefinition($class, $index) + { + $self = get_class($this); + + $this->addFilterField($index, '_testvariant', array( + 'name' => '_testvariant', + 'field' => '_testvariant', + 'fullfield' => '_testvariant', + 'base' => ClassInfo::baseDataClass($class), + 'origin' => $class, + 'type' => 'Int', + 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) + )); + } + + public function alterQuery($query, $index) + { + // I guess just calling it _testvariant is ok? + $query->filter('_testvariant', $this->currentState()); + } + + public function appliesTo($class, $includeSubclasses) + { + return $class === 'SolrReindexTest_Item' || + ($includeSubclasses && is_subclass_of($class, 'SolrReindexTest_Item', true)); + } + + public function appliesToEnvironment() + { + // Set to null to disable + return self::$current !== null; + } + + public function currentState() + { + return self::get_current(); + } + + public function reindexStates() + { + // Always use string values for states for consistent json_encode value + return array('0', '1', '2'); + } +} From e422ad48c9b77ec317219c4781b6a5ec945b3a96 Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Tue, 25 Apr 2017 21:11:29 +1200 Subject: [PATCH 29/63] Use PHP5.5 class name resolution operator --- code/solr/Solr.php | 5 +++-- code/solr/reindex/jobs/SolrReindexQueuedJobBase.php | 6 ++++-- code/solr/services/Solr3Service.php | 2 +- code/solr/services/Solr4Service.php | 2 +- code/solr/services/SolrService.php | 3 ++- code/solr/tasks/Solr_BuildTask.php | 4 ++-- code/solr/tasks/Solr_Configure.php | 5 +++-- code/solr/tasks/Solr_Reindex.php | 6 ++++-- tests/SolrReindexQueuedTest.php | 5 +++-- tests/SolrReindexTest.php | 3 ++- 10 files changed, 25 insertions(+), 16 deletions(-) diff --git a/code/solr/Solr.php b/code/solr/Solr.php index 8fe496d..dc8907b 100644 --- a/code/solr/Solr.php +++ b/code/solr/Solr.php @@ -4,6 +4,7 @@ namespace SilverStripe\FullTextSearch\Solr; use SilverStripe\Control\Director; use SilverStripe\Core\Object; use SilverStripe\FullTextSearch\Search\FullTextSearch; +use SilverStripe\FullTextSearch\Solr\SolrIndex; class Solr { @@ -137,7 +138,7 @@ class Solr public static function get_indexes() { - return FullTextSearch::get_indexes('SilverStripe\FullTextSearch\Solr\SolrIndex'); + return FullTextSearch::get_indexes(SolrIndex::class); } /** @@ -157,4 +158,4 @@ class Solr $included = true; } } -} \ No newline at end of file +} diff --git a/code/solr/reindex/jobs/SolrReindexQueuedJobBase.php b/code/solr/reindex/jobs/SolrReindexQueuedJobBase.php index e1cb64b..514a449 100644 --- a/code/solr/reindex/jobs/SolrReindexQueuedJobBase.php +++ b/code/solr/reindex/jobs/SolrReindexQueuedJobBase.php @@ -2,6 +2,8 @@ namespace SilverStripe\FullTextSearch\Solr\Reindex\Jobs; use Monolog\Logger; use Psr\Log\LoggerInterface; +use SilverStripe\FullTextSearch\Utils\Logging\SearchLogFactory; +use SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler; if (!interface_exists('QueuedJob')) { return; @@ -44,7 +46,7 @@ abstract class SolrReindexQueuedJobBase implements QueuedJob */ protected function getLoggerFactory() { - return Injector::inst()->get('SilverStripe\FullTextSearch\Utils\Logging\SearchLogFactory'); + return Injector::inst()->get(SearchLogFactory::class); } /** @@ -103,7 +105,7 @@ abstract class SolrReindexQueuedJobBase implements QueuedJob */ protected function getHandler() { - return Injector::inst()->get('SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler'); + return Injector::inst()->get(SolrReindexHandler::class); } public function jobFinished() diff --git a/code/solr/services/Solr3Service.php b/code/solr/services/Solr3Service.php index d540de2..c2a9e39 100644 --- a/code/solr/services/Solr3Service.php +++ b/code/solr/services/Solr3Service.php @@ -3,5 +3,5 @@ namespace SilverStripe\FullTextSearch\Solr\Services; class Solr3Service extends SolrService { - private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\Solr3Service'; + private static $core_class = Solr3Service::class; } diff --git a/code/solr/services/Solr4Service.php b/code/solr/services/Solr4Service.php index 9dc3346..a09c268 100644 --- a/code/solr/services/Solr4Service.php +++ b/code/solr/services/Solr4Service.php @@ -3,5 +3,5 @@ namespace SilverStripe\FullTextSearch\Solr\Services; class Solr4Service extends SolrService { - private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\Solr4Service'; + private static $core_class = Solr4Service::class; } diff --git a/code/solr/services/SolrService.php b/code/solr/services/SolrService.php index 2786605..16bd6b6 100644 --- a/code/solr/services/SolrService.php +++ b/code/solr/services/SolrService.php @@ -2,6 +2,7 @@ namespace SilverStripe\FullTextSearch\Solr\Services; use SilverStripe\Core\Config\Config; use SilverStripe\FullTextSearch\Solr\Solr; +use SilverStripe\FullTextSearch\Solr\Services\SolrService_Core; Solr::include_client_api(); /** * The API for accessing the primary Solr installation, which includes both SolrService_Core, @@ -10,7 +11,7 @@ Solr::include_client_api(); */ class SolrService extends SolrService_Core { - private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\SolrService_Core'; + private static $core_class = SolrService_Core::class; /** * Handle encoding the GET parameters and making the HTTP call to execute a core command diff --git a/code/solr/tasks/Solr_BuildTask.php b/code/solr/tasks/Solr_BuildTask.php index fa06e23..9e4e3c9 100644 --- a/code/solr/tasks/Solr_BuildTask.php +++ b/code/solr/tasks/Solr_BuildTask.php @@ -25,7 +25,7 @@ class Solr_BuildTask extends BuildTask */ public function getLogger() { - return Injector::inst()->get('Psr\Log\LoggerInterface'); + return Injector::inst()->get(LoggerInterface::class); } /** @@ -43,7 +43,7 @@ class Solr_BuildTask extends BuildTask */ protected function getLoggerFactory() { - return Injector::inst()->get('SilverStripe\FullTextSearch\Utils\Logging\SearchLogFactory'); + return Injector::inst()->get(SearchLogFactory::class); } /** diff --git a/code/solr/tasks/Solr_Configure.php b/code/solr/tasks/Solr_Configure.php index 31471fe..5a363d2 100644 --- a/code/solr/tasks/Solr_Configure.php +++ b/code/solr/tasks/Solr_Configure.php @@ -5,6 +5,7 @@ use SilverStripe\Core\ClassInfo; use SilverStripe\FullTextSearch\Solr\Solr; use SilverStripe\FullTextSearch\Solr\Stores\SolrConfigStore_File; use SilverStripe\FullTextSearch\Solr\Stores\SolrConfigStore_WebDAV; +use SilverStripe\FullTextSearch\Solr\Stores\SolrConfigStore; class Solr_Configure extends Solr_BuildTask { @@ -78,10 +79,10 @@ class Solr_Configure extends Solr_BuildTask return new SolrConfigStore_File($indexstore); } elseif ($mode == 'webdav') { return new SolrConfigStore_WebDAV($indexstore); - } elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, 'SilverStripe\FullTextSearch\Solr\Stores\SolrConfigStore')) { + } elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, SolrConfigStore::class)) { return new $mode($indexstore); } else { user_error('Unknown Solr index mode '.$indexstore['mode'], E_USER_ERROR); } } -} \ No newline at end of file +} diff --git a/code/solr/tasks/Solr_Reindex.php b/code/solr/tasks/Solr_Reindex.php index 96f5df1..6671777 100644 --- a/code/solr/tasks/Solr_Reindex.php +++ b/code/solr/tasks/Solr_Reindex.php @@ -6,6 +6,8 @@ use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Injector\Injector; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; use SilverStripe\ORM\DataList; +use SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler; +use SilverStripe\FullTextSearch\Solr\SolrIndex; /** * Task used for both initiating a new reindex, as well as for processing incremental batches @@ -41,7 +43,7 @@ class Solr_Reindex extends Solr_BuildTask */ protected function getHandler() { - return Injector::inst()->get('SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler'); + return Injector::inst()->get(SolrReindexHandler::class); } /** @@ -70,7 +72,7 @@ class Solr_Reindex extends Solr_BuildTask // this is for when index names do not match the class name (this can be done by overloading getIndexName() on // indexes if ($index && !ClassInfo::exists($index)) { - foreach(ClassInfo::subclassesFor('SilverStripe\FullTextSearch\Solr\SolrIndex') as $solrIndexClass) { + foreach(ClassInfo::subclassesFor(SolrIndex::class) as $solrIndexClass) { $reflection = new ReflectionClass($solrIndexClass); //skip over abstract classes if (!$reflection->isInstantiable()) { diff --git a/tests/SolrReindexQueuedTest.php b/tests/SolrReindexQueuedTest.php index 1baf385..5bd0412 100644 --- a/tests/SolrReindexQueuedTest.php +++ b/tests/SolrReindexQueuedTest.php @@ -4,6 +4,7 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\FullTextSearch\Search\FullTextSearch; use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Variant; +use SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler; /** * Additional tests of solr reindexing processes when run with queuedjobs @@ -106,7 +107,7 @@ class SolrReindexQueuedTest extends SapphireTest */ protected function getHandler() { - return Injector::inst()->get('SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler'); + return Injector::inst()->get(SolrReindexHandler::class); } /** @@ -158,7 +159,7 @@ class SolrReindexQueuedTest extends SapphireTest $this->assertEquals(3, $logger->countMessages(' of SolrReindexTest_Item in {"SolrReindexTest_Variant":"1"}')); $this->assertEquals(1, $logger->countMessages('Completed init of reindex')); - + // Test that invalid classes are removed $this->assertNotEmpty($logger->getMessages('Clearing obsolete classes from SolrReindexTest_Index')); Phockito::verify($this->service, 1) diff --git a/tests/SolrReindexTest.php b/tests/SolrReindexTest.php index 6338e35..72226d3 100644 --- a/tests/SolrReindexTest.php +++ b/tests/SolrReindexTest.php @@ -4,6 +4,7 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\FullTextSearch\Search\FullTextSearch; use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Variant; +use SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler; if (class_exists('Phockito')) { Phockito::include_hamcrest(false); @@ -102,7 +103,7 @@ class SolrReindexTest extends SapphireTest */ protected function getHandler() { - return Injector::inst()->get('SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler'); + return Injector::inst()->get(SolrReindexHandler::class); } /** From 3160c066c0b0baa7dde0026dbc3fc51478eebf05 Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Tue, 25 Apr 2017 21:17:48 +1200 Subject: [PATCH 30/63] Use PHP5.5 class name resolution operator --- code/search/FullTextSearch.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/search/FullTextSearch.php b/code/search/FullTextSearch.php index bebe9fd..42cb3a2 100644 --- a/code/search/FullTextSearch.php +++ b/code/search/FullTextSearch.php @@ -5,6 +5,7 @@ namespace SilverStripe\FullTextSearch\Search; use ReflectionClass; use SilverStripe\Core\Config\Config; use SilverStripe\Core\ClassInfo; +use SilverStripe\FullTextSearch\Solr\SearchIndex; /** * Base class to manage active search indexes. */ @@ -42,7 +43,7 @@ class FullTextSearch if (self::$all_indexes === null) { // Get declared indexes, or otherwise default to all subclasses of SearchIndex $classes = Config::inst()->get(__CLASS__, 'indexes') - ?: ClassInfo::subclassesFor('SilverStripe\FullTextSearch\Solr\SearchIndex'); + ?: ClassInfo::subclassesFor(SearchIndex::class); $hidden = array(); $candidates = array(); From 73e48887153389966ffa2ba54d17eb0636d9e897 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 22:52:20 +1200 Subject: [PATCH 31/63] SS 4.0 - Upgrade tests to SilverStripe 4.0 & Replace Phockito --- composer.json | 3 +- tests/BatchedProcessorTest.php | 57 +++-- .../BatchedProcessorTest_Index.php | 2 +- .../BatchedProcessorTest_Object.php | 2 + .../BatchedProcessor_QueuedJobService.php | 2 + tests/SearchUpdaterTest.php | 7 +- .../SearchUpdaterTest_Index.php | 2 +- ...rchVariantSiteTreeSubsitesPolyhomeTest.php | 17 +- ...iantSiteTreeSubsitesPolyhomeTest_Index.php | 14 + ...riantSiteTreeSubsitesPolyhomeTest_Item.php | 15 ++ tests/SearchVariantVersionedTest.php | 75 ++---- .../SearchVariantVersionedTest_Index.php | 14 + ...earchVariantVersionedTest_IndexNoStage.php | 16 ++ .../SearchVariantVersionedTest_Item.php | 16 ++ tests/SolrIndexSubsitesTest.php | 18 +- .../SolrIndexSubsitesTest_Index.php | 6 +- tests/SolrIndexTest.php | 223 +++++++--------- .../SolrIndexTest_BoostedIndex.php | 5 +- .../SolrIndexTest/SolrIndexTest_FakeIndex.php | 3 +- .../SolrIndexTest_FakeIndex2.php | 3 +- tests/SolrIndexVersionedTest.php | 239 +++++++++++------- .../SolrDocumentMatcher.php | 8 +- .../SolrIndexVersionedTest_Object.php | 4 +- .../SolrVersionedTest_Index.php | 8 +- tests/SolrReindexQueuedTest.php | 107 ++++---- .../SolrReindexQueuedTest_Service.php | 27 ++ tests/SolrReindexTest.php | 129 +++++----- .../SolrReindexTest/SolrReindexTest_Index.php | 2 +- .../SolrReindexTest/SolrReindexTest_Item.php | 4 +- .../SolrReindexTest_Variant.php | 9 +- 30 files changed, 577 insertions(+), 460 deletions(-) create mode 100644 tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Index.php create mode 100644 tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Item.php create mode 100644 tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Index.php create mode 100644 tests/SearchVariantVersionedTest/SearchVariantVersionedTest_IndexNoStage.php create mode 100644 tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Item.php create mode 100644 tests/SolrReindexQueuedTest/SolrReindexQueuedTest_Service.php diff --git a/composer.json b/composer.json index 2279cfa..b2b4fd3 100644 --- a/composer.json +++ b/composer.json @@ -24,8 +24,7 @@ "monolog/monolog": "~1.15" }, "require-dev": { - "silverstripe/cms": "4.0.x-dev", - "hafriedlander/silverstripe-phockito": "*" + "silverstripe/cms": "4.0.x-dev" }, "extra": { "branch-alias": { diff --git a/tests/BatchedProcessorTest.php b/tests/BatchedProcessorTest.php index 54d384c..b775006 100644 --- a/tests/BatchedProcessorTest.php +++ b/tests/BatchedProcessorTest.php @@ -4,6 +4,19 @@ namespace SilverStripe\FullTextSearch\Tests; use SilverStripe\Dev\SapphireTest; use SilverStripe\FullTextSearch\Search\FullTextSearch; +use SilverStripe\ORM\FieldType\DBDatetime; +use SilverStripe\Core\Config\Config; +use SilverStripe\Versioned\Versioned; +use SilverStripe\Core\Injector\Injector; +use SilverStripe\FullTextSearch\Tests\BatchedProcessorTest\BatchedProcessor_QueuedJobService; +use SilverStripe\FullTextSearch\Tests\BatchedProcessorTest\BatchedProcessorTest_Index; +use SilverStripe\FullTextSearch\Tests\BatchedProcessorTest\BatchedProcessorTest_Object; +use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateCommitJobProcessor; +use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateQueuedJobProcessor; +use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateBatchedProcessor; +use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater; +use SilverStripe\FullTextSearch\Search\Variants\SearchVariantVersioned; +use SilverStripe\QueuedJobs\Services\QueuedJobService; /** * Tests {@see SearchUpdateQueuedJobProcessor} @@ -12,8 +25,8 @@ class BatchedProcessorTest extends SapphireTest { protected $oldProcessor; - protected $extraDataObjects = array( - 'BatchedProcessorTest_Object' + protected static $extra_dataobjects = array( + BatchedProcessorTest_Object::class ); protected $illegalExtensions = array( @@ -26,7 +39,7 @@ class BatchedProcessorTest extends SapphireTest public function setUpOnce() { // Disable illegal extensions if skipping this test - if (class_exists('Subsite') || !interface_exists('QueuedJob')) { + if (class_exists('Subsite') || !interface_exists('SilverStripe\QueuedJobs\Services\QueuedJob')) { $this->illegalExtensions = array(); } parent::setUpOnce(); @@ -36,7 +49,7 @@ class BatchedProcessorTest extends SapphireTest { parent::setUp(); - if (!interface_exists('QueuedJob')) { + if (!interface_exists('SilverStripe\QueuedJobs\Services\QueuedJob')) { $this->skipTest = true; $this->markTestSkipped("These tests need the QueuedJobs module installed to run"); } @@ -46,17 +59,17 @@ class BatchedProcessorTest extends SapphireTest $this->markTestSkipped(get_class() . ' skipped when running with subsites'); } - SS_Datetime::set_mock_now('2015-05-07 06:00:00'); + DBDatetime::set_mock_now('2015-05-07 06:00:00'); - Config::modify()->set('SearchUpdateBatchedProcessor', 'batch_size', 5); - Config::modify()->set('SearchUpdateBatchedProcessor', 'batch_soft_cap', 0); - Config::modify()->set('SearchUpdateCommitJobProcessor', 'cooldown', 600); + Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_size', 5); + Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 0); + Config::modify()->set(SearchUpdateCommitJobProcessor::class, 'cooldown', 600); - Versioned::reading_stage("Stage"); + Versioned::set_stage("Stage"); - Injector::inst()->registerService(new BatchedProcessor_QueuedJobService(), 'QueuedJobService'); + Injector::inst()->registerService(new BatchedProcessor_QueuedJobService(), QueuedJobService::class); - FullTextSearch::force_index_list('BatchedProcessorTest_Index'); + FullTextSearch::force_index_list(BatchedProcessorTest_Index::class); SearchUpdateCommitJobProcessor::$dirty_indexes = array(); SearchUpdateCommitJobProcessor::$has_run = false; @@ -87,12 +100,12 @@ class BatchedProcessorTest extends SapphireTest $object->write(); // Add to index manually $processor->addDirtyIDs( - 'BatchedProcessorTest_Object', + BatchedProcessorTest_Object::class, array(array( 'id' => $id, - 'state' => array('SearchVariantVersioned' => 'Stage') + 'state' => array(SearchVariantVersioned::class => 'Stage') )), - 'BatchedProcessorTest_Index' + BatchedProcessorTest_Index::class ); } $processor->batchData(); @@ -104,7 +117,7 @@ class BatchedProcessorTest extends SapphireTest */ public function testBatching() { - $index = singleton('BatchedProcessorTest_Index'); + $index = singleton(BatchedProcessorTest_Index::class); $index->reset(); $processor = $this->generateDirtyIds(); @@ -132,10 +145,10 @@ class BatchedProcessorTest extends SapphireTest // Check any additional queued jobs $processor->afterComplete(); - $service = singleton('QueuedJobService'); + $service = singleton(QueuedJobService::class); $jobs = $service->getJobs(); $this->assertEquals(1, count($jobs)); - $this->assertInstanceOf('SearchUpdateCommitJobProcessor', $jobs[0]['job']); + $this->assertInstanceOf(SearchUpdateCommitJobProcessor::class, $jobs[0]['job']); } /** @@ -143,7 +156,7 @@ class BatchedProcessorTest extends SapphireTest */ public function testMultipleCommits() { - $index = singleton('BatchedProcessorTest_Index'); + $index = singleton(BatchedProcessorTest_Index::class); $index->reset(); // Test that running a commit immediately after submitting to the indexes @@ -190,25 +203,25 @@ class BatchedProcessorTest extends SapphireTest */ public function testSoftCap() { - $index = singleton('BatchedProcessorTest_Index'); + $index = singleton(BatchedProcessorTest_Index::class); $index->reset(); $processor = $this->generateDirtyIds(); // Test that increasing the soft cap to 2 will reduce the number of batches - Config::modify()->set('SearchUpdateBatchedProcessor', 'batch_soft_cap', 2); + Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 2); $processor->batchData(); $data = $processor->getJobData(); //Debug::dump($data);die; $this->assertEquals(8, $data->totalSteps); // A soft cap of 1 should not fit in the hanging two items - Config::modify()->set('SearchUpdateBatchedProcessor', 'batch_soft_cap', 1); + Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 1); $processor->batchData(); $data = $processor->getJobData(); $this->assertEquals(9, $data->totalSteps); // Extra large soft cap should fit both items - Config::modify()->set('SearchUpdateBatchedProcessor', 'batch_soft_cap', 4); + Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 4); $processor->batchData(); $data = $processor->getJobData(); $this->assertEquals(8, $data->totalSteps); diff --git a/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php b/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php index 7116af1..c22ebf1 100644 --- a/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php +++ b/tests/BatchedProcessorTest/BatchedProcessorTest_Index.php @@ -9,7 +9,7 @@ class BatchedProcessorTest_Index extends SearchIndex_Recording implements TestOn { public function init() { - $this->addClass('BatchedProcessorTest_Object'); + $this->addClass(BatchedProcessorTest_Object::class); $this->addFilterField('TestText'); } } diff --git a/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php b/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php index b596a3a..3683208 100644 --- a/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php +++ b/tests/BatchedProcessorTest/BatchedProcessorTest_Object.php @@ -7,6 +7,8 @@ use SilverStripe\Dev\TestOnly; class BatchedProcessorTest_Object extends SiteTree implements TestOnly { + private static $table_name = 'BatchedProcessorTest_Object'; + private static $db = array( 'TestText' => 'Varchar' ); diff --git a/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php b/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php index 1cf5253..572347c 100644 --- a/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php +++ b/tests/BatchedProcessorTest/BatchedProcessor_QueuedJobService.php @@ -2,6 +2,8 @@ namespace SilverStripe\FullTextSearch\Tests\BatchedProcessorTest; +use SilverStripe\QueuedJobs\Services\QueuedJob; + class BatchedProcessor_QueuedJobService { protected $jobs = array(); diff --git a/tests/SearchUpdaterTest.php b/tests/SearchUpdaterTest.php index e786c2b..d62f33a 100644 --- a/tests/SearchUpdaterTest.php +++ b/tests/SearchUpdaterTest.php @@ -3,11 +3,14 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater; use SilverStripe\Core\Config\Config; +use SilverStripe\Core\Injector\Injector; use SilverStripe\FullTextSearch\Search\FullTextSearch; use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasOne; use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasMany; use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Index; +use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor; +use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateImmediateProcessor; class SearchUpdaterTest extends SapphireTest { @@ -27,8 +30,8 @@ class SearchUpdaterTest extends SapphireTest SearchUpdater::bind_manipulation_capture(); - Config::modify()->set('Injector', 'SearchUpdateProcessor', array( - 'class' => 'SearchUpdateImmediateProcessor' + Config::modify()->set(Injector::class, SearchUpdateProcessor::class, array( + 'class' => SearchUpdateImmediateProcessor::class )); FullTextSearch::force_index_list(self::$index); diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_Index.php b/tests/SearchUpdaterTest/SearchUpdaterTest_Index.php index 2142e0e..5a027c5 100644 --- a/tests/SearchUpdaterTest/SearchUpdaterTest_Index.php +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_Index.php @@ -8,7 +8,7 @@ class SearchUpdaterTest_Index extends SearchIndex_Recording { public function init() { - $this->addClass('SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container'); + $this->addClass(SearchUpdaterTest_Container::class); $this->addFilterField('Field1'); $this->addFilterField('HasOneObject.Field1'); diff --git a/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php index 38b5753..892619f 100644 --- a/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php +++ b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php @@ -3,23 +3,10 @@ use SilverStripe\CMS\Model\SiteTree; use SilverStripe\FullTextSearch\Search\Indexes\SearchIndex_Recording; use SilverStripe\Dev\SapphireTest; +use SilverStripe\FullTextSearch\Tests\SearchVariantSiteTreeSubsitesPolyhomeTest\SearchVariantSiteTreeSubsitesPolyhomeTest_Index; +use SilverStripe\FullTextSearch\Tests\SearchVariantSiteTreeSubsitesPolyhomeTest\SearchVariantSiteTreeSubsitesPolyhomeTest_Item; -class SearchVariantSiteTreeSubsitesPolyhomeTest_Item extends SiteTree -{ - // TODO: Currently theres a failure if you addClass a non-table class - private static $db = array( - 'TestText' => 'Varchar' - ); -} -class SearchVariantSiteTreeSubsitesPolyhomeTest_Index extends SearchIndex_Recording -{ - public function init() - { - $this->addClass('SearchVariantSiteTreeSubsitesPolyhomeTest_Item'); - $this->addFilterField('TestText'); - } -} class SearchVariantSiteTreeSubsitesPolyhomeTest extends SapphireTest { diff --git a/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Index.php b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Index.php new file mode 100644 index 0000000..4991e6c --- /dev/null +++ b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Index.php @@ -0,0 +1,14 @@ +addClass(SearchVariantSiteTreeSubsitesPolyhomeTest_Item::class); + $this->addFilterField('TestText'); + } +} diff --git a/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Item.php b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Item.php new file mode 100644 index 0000000..f037d77 --- /dev/null +++ b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest/SearchVariantSiteTreeSubsitesPolyhomeTest_Item.php @@ -0,0 +1,15 @@ + 'Varchar' + ); +} diff --git a/tests/SearchVariantVersionedTest.php b/tests/SearchVariantVersionedTest.php index bff85c7..7ef3a1d 100644 --- a/tests/SearchVariantVersionedTest.php +++ b/tests/SearchVariantVersionedTest.php @@ -1,9 +1,15 @@ markTestSkipped('The versioned decorator is not installed'); - } - if (self::$index === null) { - self::$index = singleton('SearchVariantVersionedTest_Index'); + self::$index = singleton(SearchVariantVersionedTest_Index::class); } SearchUpdater::bind_manipulation_capture(); - Config::modify()->set('Injector', 'SearchUpdateProcessor', array( - 'class' => 'SearchUpdateImmediateProcessor' + Config::modify()->set('Injector', SearchUpdateProcessor::class, array( + 'class' => SearchUpdateImmediateProcessor::class )); FullTextSearch::force_index_list(self::$index); @@ -47,20 +48,21 @@ class SearchVariantVersionedTest extends SapphireTest $item->write(); SearchUpdater::flush_dirty_indexes(); - $this->assertEquals(self::$index->getAdded(array('ID', '_versionedstage')), array( + $this->assertEquals(array( array('ID' => $item->ID, '_versionedstage' => 'Stage') - )); + ), self::$index->getAdded(array('ID', '_versionedstage'))); // Check that publish updates Live self::$index->reset(); - $item->publish("Stage", "Live"); + $item->copyVersionToStage('Stage', 'Live'); SearchUpdater::flush_dirty_indexes(); - $this->assertEquals(self::$index->getAdded(array('ID', '_versionedstage')), array( + $this->assertEquals(array( + array('ID' => $item->ID, '_versionedstage' => 'Stage'), array('ID' => $item->ID, '_versionedstage' => 'Live') - )); + ), self::$index->getAdded(array('ID', '_versionedstage'))); // Just update a SiteTree field, and check it updates Stage @@ -81,48 +83,23 @@ class SearchVariantVersionedTest extends SapphireTest public function testExcludeVariantState() { - $index = singleton('SearchVariantVersionedTest_IndexNoStage'); + $index = singleton(SearchVariantVersionedTest_IndexNoStage::class); FullTextSearch::force_index_list($index); // Check that write doesn't update stage $item = new SearchVariantVersionedTest_Item(array('TestText' => 'Foo')); $item->write(); SearchUpdater::flush_dirty_indexes(); - $this->assertEquals($index->getAdded(array('ID', '_versionedstage')), array()); + $this->assertEquals(array(), $index->getAdded(array('ID', '_versionedstage'))); // Check that publish updates Live $index->reset(); - $item->publish("Stage", "Live"); + + $item->copyVersionToStage('Stage', 'Live'); + SearchUpdater::flush_dirty_indexes(); - $this->assertEquals($index->getAdded(array('ID', '_versionedstage')), array( + $this->assertEquals(array( array('ID' => $item->ID, '_versionedstage' => 'Live') - )); - } -} - -class SearchVariantVersionedTest_Item extends SiteTree implements TestOnly -{ - // TODO: Currently theres a failure if you addClass a non-table class - private static $db = array( - 'TestText' => 'Varchar' - ); -} - -class SearchVariantVersionedTest_Index extends SearchIndex_Recording -{ - public function init() - { - $this->addClass('SearchVariantVersionedTest_Item'); - $this->addFilterField('TestText'); - } -} - -class SearchVariantVersionedTest_IndexNoStage extends SearchIndex_Recording -{ - public function init() - { - $this->addClass('SearchVariantVersionedTest_Item'); - $this->addFilterField('TestText'); - $this->excludeVariantState(array('SearchVariantVersioned' => 'Stage')); + ), $index->getAdded(array('ID', '_versionedstage'))); } } diff --git a/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Index.php b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Index.php new file mode 100644 index 0000000..eba01ec --- /dev/null +++ b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Index.php @@ -0,0 +1,14 @@ +addClass(SearchVariantVersionedTest_Item::class); + $this->addFilterField('TestText'); + } +} diff --git a/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_IndexNoStage.php b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_IndexNoStage.php new file mode 100644 index 0000000..8b66288 --- /dev/null +++ b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_IndexNoStage.php @@ -0,0 +1,16 @@ +addClass(SearchVariantVersionedTest_Item::class); + $this->addFilterField('TestText'); + $this->excludeVariantState(array(SearchVariantVersioned::class => 'Stage')); + } +} diff --git a/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Item.php b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Item.php new file mode 100644 index 0000000..d6538de --- /dev/null +++ b/tests/SearchVariantVersionedTest/SearchVariantVersionedTest_Item.php @@ -0,0 +1,16 @@ + 'Varchar' + ); +} diff --git a/tests/SolrIndexSubsitesTest.php b/tests/SolrIndexSubsitesTest.php index 1cd3889..9bd7bd1 100644 --- a/tests/SolrIndexSubsitesTest.php +++ b/tests/SolrIndexSubsitesTest.php @@ -3,8 +3,8 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\FullTextSearch\Tests\SolrIndexSubsitesTest\SolrIndexSubsitesTest_Index; -if (class_exists('Phockito')) { - Phockito::include_hamcrest(false); +if (class_exists('\Phockito')) { + \Phockito::include_hamcrest(false); } /** @@ -33,9 +33,9 @@ class SolrIndexSubsitesTest extends SapphireTest { $this->server = $_SERVER; - if (!class_exists('Phockito')) { + if (!class_exists('\Phockito')) { $this->skipTest = true; - $this->markTestSkipped("These tests need the Phockito module installed to run"); + $this->markTestSkipped("These tests need the \Phockito module installed to run"); return; } @@ -71,7 +71,7 @@ class SolrIndexSubsitesTest extends SapphireTest { protected function getServiceMock() { - return Phockito::mock('Solr4Service'); + return \Phockito::mock('Solr4Service'); } /** @@ -83,7 +83,7 @@ class SolrIndexSubsitesTest extends SapphireTest { protected function getExpectedDocumentId($object, $subsiteID, $stage = null) { $id = $object->ID; - $class = ClassInfo::baseDataClass($object); + $class = DataObject::getSchema()->baseDataClass($object); $variants = array(); // Check subsite @@ -109,7 +109,7 @@ class SolrIndexSubsitesTest extends SapphireTest { // Add records to first subsite Versioned::reading_stage('Stage'); $_SERVER['HTTP_HOST'] = 'www.subsite1.com'; - Phockito::reset($serviceMock); + \Phockito::reset($serviceMock); $file = new File(); $file->Title = 'My File'; $file->SubsiteID = $subsite1->ID; @@ -132,8 +132,8 @@ class SolrIndexSubsitesTest extends SapphireTest { 'File_Title' => 'My File', '_subsite' => $subsite1->ID )); - Phockito::verify($serviceMock)->addDocument($doc1); - Phockito::verify($serviceMock)->addDocument($doc2); + \Phockito::verify($serviceMock)->addDocument($doc1); + \Phockito::verify($serviceMock)->addDocument($doc2); } diff --git a/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php b/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php index 97e9dfb..620f632 100644 --- a/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php +++ b/tests/SolrIndexSubsitesTest/SolrIndexSubsitesTest_Index.php @@ -3,13 +3,15 @@ namespace SilverStripe\FullTextSearch\Tests\SolrIndexSubsitesTest; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\Assets\File; +use SilverStripe\CMS\Model\SiteTree; class SolrIndexSubsitesTest_Index extends SolrIndex { public function init() { - $this->addClass('File'); - $this->addClass('SiteTree'); + $this->addClass(File::class); + $this->addClass(SiteTree::class); $this->addAllFulltextFields(); } } diff --git a/tests/SolrIndexTest.php b/tests/SolrIndexTest.php index 154f960..b0ee54e 100644 --- a/tests/SolrIndexTest.php +++ b/tests/SolrIndexTest.php @@ -4,60 +4,50 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex; use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex2; use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_BoostedIndex; +use SilverStripe\FullTextSearch\Solr\Services\Solr3Service; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasOne; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasMany; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_ManyMany; +use SilverStripe\Core\Config\Config; +use SilverStripe\Control\Director; +use SilverStripe\FullTextSearch\Search\Queries\SearchQuery; class SolrIndexTest extends SapphireTest { - public function setUpOnce() - { - parent::setUpOnce(); - - if (class_exists('Phockito')) { - Phockito::include_hamcrest(false); - } - } - - public function setUp() - { - parent::setUp(); - - if (!class_exists('Phockito')) { - $this->markTestSkipped("These tests need the Phockito module installed to run"); - $this->skipTest = true; - } - } - public function testFieldDataHasOne() { $index = new SolrIndexTest_FakeIndex(); $data = $index->fieldData('HasOneObject.Field1'); - $data = $data['SearchUpdaterTest_Container_HasOneObject_Field1']; - $this->assertEquals('SearchUpdaterTest_Container', $data['origin']); - $this->assertEquals('SearchUpdaterTest_Container', $data['base']); - $this->assertEquals('SearchUpdaterTest_HasOne', $data['class']); + $data = $data[SearchUpdaterTest_Container::class . '_HasOneObject_Field1']; + + $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']); + $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']); + $this->assertEquals(SearchUpdaterTest_HasOne::class, $data['class']); } public function testFieldDataHasMany() { $index = new SolrIndexTest_FakeIndex(); $data = $index->fieldData('HasManyObjects.Field1'); - $data = $data['SearchUpdaterTest_Container_HasManyObjects_Field1']; + $data = $data[SearchUpdaterTest_Container::class . '_HasManyObjects_Field1']; - $this->assertEquals('SearchUpdaterTest_Container', $data['origin']); - $this->assertEquals('SearchUpdaterTest_Container', $data['base']); - $this->assertEquals('SearchUpdaterTest_HasMany', $data['class']); + $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']); + $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']); + $this->assertEquals(SearchUpdaterTest_HasMany::class, $data['class']); } public function testFieldDataManyMany() { $index = new SolrIndexTest_FakeIndex(); $data = $index->fieldData('ManyManyObjects.Field1'); - $data = $data['SearchUpdaterTest_Container_ManyManyObjects_Field1']; + $data = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1']; - $this->assertEquals('SearchUpdaterTest_Container', $data['origin']); - $this->assertEquals('SearchUpdaterTest_Container', $data['base']); - $this->assertEquals('SearchUpdaterTest_ManyMany', $data['class']); + $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']); + $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']); + $this->assertEquals(SearchUpdaterTest_ManyMany::class, $data['class']); } /** @@ -65,15 +55,19 @@ class SolrIndexTest extends SapphireTest */ public function testBoostedQuery() { - $serviceMock = $this->getServiceMock(); - Phockito::when($serviceMock) - ->search( - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything() - )->return($this->getFakeRawSolrResponse()); + /** @var Solr3Service|PHPUnit_Framework_MockObject_MockObject $serviceMock */ + $serviceMock = $this->getMockBuilder(Solr3Service::class) + ->setMethods(['search']) + ->getMock(); + + $serviceMock->expects($this->once()) + ->method('search') + ->with($this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + )->willReturn($this->getFakeRawSolrResponse()); $index = new SolrIndexTest_FakeIndex(); $index->setService($serviceMock); @@ -85,15 +79,6 @@ class SolrIndexTest extends SapphireTest array('Field1' => 1.5, 'HasOneObject_Field1' => 3) ); $index->search($query); - - Phockito::verify($serviceMock) - ->search( - '+(Field1:term^1.5 OR HasOneObject_Field1:term^3)', - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything() - ); } /** @@ -101,15 +86,20 @@ class SolrIndexTest extends SapphireTest */ public function testBoostedField() { - $serviceMock = $this->getServiceMock(); - Phockito::when($serviceMock) - ->search( - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything() - )->return($this->getFakeRawSolrResponse()); + /** @var Solr3Service|PHPUnit_Framework_MockObject_MockObject $serviceMock */ + $serviceMock = $this->getMockBuilder(Solr3Service::class) + ->setMethods(['search']) + ->getMock(); + + $serviceMock->expects($this->once()) + ->method('search') + ->with($this->equalTo('+term'), + $this->anything(), + $this->anything(), + $this->equalTo(['qf' => SearchUpdaterTest_Container::class . '_Field1^1.5 ' . SearchUpdaterTest_Container::class . '_Field2^2.1 _text', + 'fq' => '+(_versionedstage:"" (*:* -_versionedstage:[* TO *]))']), + $this->anything() + )->willReturn($this->getFakeRawSolrResponse()); $index = new SolrIndexTest_BoostedIndex(); $index->setService($serviceMock); @@ -117,32 +107,34 @@ class SolrIndexTest extends SapphireTest $query = new SearchQuery(); $query->search('term'); $index->search($query); - - // Ensure matcher contains correct boost in 'qf' parameter - $matcher = new Hamcrest_Array_IsArrayContainingKeyValuePair( - new Hamcrest_Core_IsEqual('qf'), - new Hamcrest_Core_IsEqual('SearchUpdaterTest_Container_Field1^1.5 SearchUpdaterTest_Container_Field2^2.1 _text') - ); - Phockito::verify($serviceMock) - ->search( - '+term', - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - $matcher, - \Hamcrest_Matchers::anything() - ); } public function testHighlightQueryOnBoost() { - $serviceMock = $this->getServiceMock(); - Phockito::when($serviceMock)->search( - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything() - )->return($this->getFakeRawSolrResponse()); + /** @var SilverStripe\FullTextSearch\Solr\Services\Solr3Service|ObjectProphecy $serviceMock */ + $serviceMock = $this->getMockBuilder(Solr3Service::class) + ->setMethods(['search']) + ->getMock(); + + $serviceMock->expects($this->exactly(2)) + ->method('search') + ->withConsecutive([ + $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'), + $this->anything(), + $this->anything(), + $this->logicalNot( + $this->arrayHasKey('hl.q') + ), + $this->anything() + ], + [ + $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'), + $this->anything(), + $this->anything(), + $this->arrayHasKey('hl.q'), + $this->anything() + ] + )->willReturn($this->getFakeRawSolrResponse()); $index = new SolrIndexTest_FakeIndex(); $index->setService($serviceMock); @@ -155,14 +147,6 @@ class SolrIndexTest extends SapphireTest array('Field1' => 1.5, 'HasOneObject_Field1' => 3) ); $index->search($query); - Phockito::verify( - $serviceMock)->search( - '+(Field1:term^1.5 OR HasOneObject_Field1:term^3)', - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::not(\Hamcrest_Matchers::hasKeyInArray('hl.q')), - \Hamcrest_Matchers::anything() - ); // Search with highlighting $query = new SearchQuery(); @@ -172,57 +156,50 @@ class SolrIndexTest extends SapphireTest array('Field1' => 1.5, 'HasOneObject_Field1' => 3) ); $index->search($query, -1, -1, array('hl' => true)); - Phockito::verify( - $serviceMock)->search( - '+(Field1:term^1.5 OR HasOneObject_Field1:term^3)', - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::anything(), - \Hamcrest_Matchers::hasKeyInArray('hl.q'), - \Hamcrest_Matchers::anything() - ); } public function testIndexExcludesNullValues() { - $serviceMock = $this->getServiceMock(); + /** @var Solr3Service|ObjectProphecy $serviceMock */ + $serviceMock = $this->createMock(Solr3Service::class); $index = new SolrIndexTest_FakeIndex(); $index->setService($serviceMock); - $obj = new Container(); + $obj = new SearchUpdaterTest_Container(); $obj->Field1 = 'Field1 val'; $obj->Field2 = null; $obj->MyDate = null; $docs = $index->add($obj); - $value = $docs[0]->getField('SearchUpdaterTest_Container_Field1'); + $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_Field1'); $this->assertEquals('Field1 val', $value['value'], 'Writes non-NULL string fields'); - $value = $docs[0]->getField('SearchUpdaterTest_Container_Field2'); + $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_Field2'); $this->assertFalse($value, 'Ignores string fields if they are NULL'); - $value = $docs[0]->getField('SearchUpdaterTest_Container_MyDate'); + $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_MyDate'); $this->assertFalse($value, 'Ignores date fields if they are NULL'); $obj->MyDate = '2010-12-30'; $docs = $index->add($obj); - $value = $docs[0]->getField('SearchUpdaterTest_Container_MyDate'); + $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_MyDate'); $this->assertEquals('2010-12-30T00:00:00Z', $value['value'], 'Writes non-NULL dates'); } public function testAddFieldExtraOptions() { - Config::inst()->nest(); - Config::modify()->set('Director', 'environment_type', 'live'); // dev mode sets stored=true for everything + Config::nest(); + Director::set_environment_type('live'); $index = new SolrIndexTest_FakeIndex(); $defs = simplexml_load_string('' . $index->getFieldDefinitions() . ''); - $defField1 = $defs->xpath('field[@name="SearchUpdaterTest_Container_Field1"]'); + $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]'); $this->assertEquals((string)$defField1[0]['stored'], 'false'); $index->addFilterField('Field1', null, array('stored' => 'true')); $defs = simplexml_load_string('' . $index->getFieldDefinitions() . ''); - $defField1 = $defs->xpath('field[@name="SearchUpdaterTest_Container_Field1"]'); + $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]'); $this->assertEquals((string)$defField1[0]['stored'], 'true'); - Config::inst()->unnest(); + Config::unnest(); } public function testAddAnalyzer() @@ -230,13 +207,13 @@ class SolrIndexTest extends SapphireTest $index = new SolrIndexTest_FakeIndex(); $defs = simplexml_load_string('' . $index->getFieldDefinitions() . ''); - $defField1 = $defs->xpath('field[@name="SearchUpdaterTest_Container_Field1"]'); + $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]'); $analyzers = $defField1[0]->analyzer; $this->assertFalse((bool)$analyzers); $index->addAnalyzer('Field1', 'charFilter', array('class' => 'solr.HTMLStripCharFilterFactory')); $defs = simplexml_load_string('' . $index->getFieldDefinitions() . ''); - $defField1 = $defs->xpath('field[@name="SearchUpdaterTest_Container_Field1"]'); + $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]'); $analyzers = $defField1[0]->analyzer; $this->assertTrue((bool)$analyzers); $this->assertEquals('solr.HTMLStripCharFilterFactory', $analyzers[0]->charFilter[0]['class']); @@ -265,11 +242,11 @@ class SolrIndexTest extends SapphireTest $index->addFulltextField('Field2'); $schema = $index->getFieldDefinitions(); $this->assertContains( - "assertContains( - "addStoredField('Field2'); $schema2 = $index2->getFieldDefinitions(); $this->assertContains( - "assertContains( - "_sendRawPost()->return($this->getFakeRawSolrResponse()); - - return $serviceSpy; - } - protected function getFakeRawSolrResponse() { - return new Apache_Solr_Response( - new Apache_Solr_HttpTransport_Response( + return new \Apache_Solr_Response( + new \Apache_Solr_HttpTransport_Response( null, null, '{}' diff --git a/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php b/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php index 65dae12..79027e7 100644 --- a/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php +++ b/tests/SolrIndexTest/SolrIndexTest_BoostedIndex.php @@ -3,6 +3,7 @@ namespace SilverStripe\FullTextSearch\Tests\SolrIndexTest; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; class SolrIndexTest_BoostedIndex extends SolrIndex { @@ -14,9 +15,9 @@ class SolrIndexTest_BoostedIndex extends SolrIndex public function init() { - $this->addClass('SearchUpdaterTest_Container'); + $this->addClass(SearchUpdaterTest_Container::class); $this->addAllFulltextFields(); - $this->setFieldBoosting('SearchUpdaterTest_Container_Field1', 1.5); + $this->setFieldBoosting(SearchUpdaterTest_Container::class . '_Field1', 1.5); $this->addBoostedField('Field2', null, array(), 2.1); } } diff --git a/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php b/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php index b04e6ce..b3da07f 100644 --- a/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php +++ b/tests/SolrIndexTest/SolrIndexTest_FakeIndex.php @@ -3,12 +3,13 @@ namespace SilverStripe\FullTextSearch\Tests\SolrIndexTest; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; class SolrIndexTest_FakeIndex extends SolrIndex { public function init() { - $this->addClass('SearchUpdaterTest_Container'); + $this->addClass(SearchUpdaterTest_Container::class); $this->addFilterField('Field1'); $this->addFilterField('MyDate', 'Date'); diff --git a/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php b/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php index a9b58ac..c209739 100644 --- a/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php +++ b/tests/SolrIndexTest/SolrIndexTest_FakeIndex2.php @@ -3,6 +3,7 @@ namespace SilverStripe\FullTextSearch\Tests\SolrIndexTest; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container; class SolrIndexTest_FakeIndex2 extends SolrIndex { @@ -14,7 +15,7 @@ class SolrIndexTest_FakeIndex2 extends SolrIndex public function init() { - $this->addClass('SearchUpdaterTest_Container'); + $this->addClass(SearchUpdaterTest_Container::class); $this->addFilterField('MyDate', 'Date'); $this->addFilterField('HasOneObject.Field1'); $this->addFilterField('HasManyObjects.Field1'); diff --git a/tests/SolrIndexVersionedTest.php b/tests/SolrIndexVersionedTest.php index a0f7013..70b83a7 100644 --- a/tests/SolrIndexVersionedTest.php +++ b/tests/SolrIndexVersionedTest.php @@ -1,58 +1,51 @@ skipTest = true; - $this->markTestSkipped("These tests need the Phockito module installed to run"); - return; - } - - // Check versioned available - if (!class_exists('Versioned')) { - $this->skipTest = true; - $this->markTestSkipped('The versioned decorator is not installed'); - return; - } - if (self::$index === null) { - self::$index = singleton('SolrVersionedTest_Index'); + self::$index = singleton(SolrVersionedTest_Index::class); } SearchUpdater::bind_manipulation_capture(); - Config::modify()->set('Injector', 'SearchUpdateProcessor', array( - 'class' => 'SearchUpdateImmediateProcessor' + Config::modify()->set('Injector', SearchUpdateProcessor::class, array( + 'class' => SearchUpdateImmediateProcessor::class )); FullTextSearch::force_index_list(self::$index); SearchUpdater::clear_dirty_indexes(); $this->oldMode = Versioned::get_reading_mode(); - Versioned::reading_stage('Stage'); + Versioned::set_stage('Stage'); } public function tearDown() @@ -61,9 +54,17 @@ class SolrIndexVersionedTest extends SapphireTest parent::tearDown(); } - protected function getServiceMock() + protected function getServiceMock($setMethods = array()) { - return Phockito::mock('Solr3Service'); + // Setup mock + /** @var SilverStripe\FullTextSearch\Solr\Services\Solr3Service|ObjectProphecy $serviceMock */ + $serviceMock = $this->getMockBuilder(Solr3Service::class) + ->setMethods($setMethods) + ->getMock(); + + self::$index->setService($serviceMock); + + return $serviceMock; } /** @@ -74,104 +75,164 @@ class SolrIndexVersionedTest extends SapphireTest protected function getExpectedDocumentId($object, $stage) { $id = $object->ID; - $class = ClassInfo::baseDataClass($object); + $class = DataObject::getSchema()->baseDataClass($object); // Prevent subsites from breaking tests + // TODO: Subsites currently isn't migrated. This needs to be fixed when subsites is fixed. $subsites = ''; if(class_exists('Subsite') && DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite')) { $subsites = '"SearchVariantSubsites":"0",'; } - return $id.'-'.$class.'-{'.$subsites.'"SearchVariantVersioned":"'.$stage.'"}'; + return $id.'-'.$class.'-{'.$subsites. json_encode(SearchVariantVersioned::class) . ':"'.$stage.'"}'; + } + + /** + * @param string $class + * @param DataObject $object Item being added + * @param string $value Value for class + * @param string $stage Stage updated + * @return Apache_Solr_Document + */ + protected function getSolrDocument($class, $object, $value, $stage) + { + $doc = new \Apache_Solr_Document(); + $doc->setField('_documentid', $this->getExpectedDocumentId($object, $stage)); + $doc->setField('ClassName', $class); + $doc->setField(DataObject::getSchema()->baseDataClass($class) . '_TestText', $value); + $doc->setField('_versionedstage', $stage); + $doc->setField('ID', $object->ID); + $doc->setField('ClassHierarchy', SearchIntrospection::hierarchy($class)); + $doc->setFieldBoost('ID', false); + $doc->setFieldBoost('ClassHierarchy', false); + + return $doc; } public function testPublishing() { - - // Setup mocks - $serviceMock = $this->getServiceMock(); - self::$index->setService($serviceMock); - // Check that write updates Stage - Versioned::reading_stage('Stage'); - Phockito::reset($serviceMock); + Versioned::set_stage('Stage'); + $item = new SearchVariantVersionedTest_Item(array('TestText' => 'Foo')); $item->write(); $object = new SolrIndexVersionedTest_Object(array('TestText' => 'Bar')); $object->write(); + + $doc1 = $this->getSolrDocument(SearchVariantVersionedTest_Item::class, $item, 'Foo', 'Stage'); + $doc2 = $this->getSolrDocument(SolrIndexVersionedTest_Object::class, $object, 'Bar', 'Stage'); + + // Ensure correct call is made to Solr + $this->getServiceMock(['addDocument', 'commit']) + ->expects($this->exactly(2)) + ->method('addDocument') + ->withConsecutive( + [ + $this->equalTo($doc1), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ], + [ + $this->equalTo($doc2), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ] + ); + SearchUpdater::flush_dirty_indexes(); - $doc1 = new SolrDocumentMatcher(array( - '_documentid' => $this->getExpectedDocumentId($item, 'Stage'), - 'ClassName' => 'SearchVariantVersionedTest_Item', - 'SearchVariantVersionedTest_Item_TestText' => 'Foo', - '_versionedstage' => 'Stage' - )); - $doc2 = new SolrDocumentMatcher(array( - '_documentid' => $this->getExpectedDocumentId($object, 'Stage'), - 'ClassName' => 'SolrIndexVersionedTest_Object', - 'SolrIndexVersionedTest_Object_TestText' => 'Bar', - '_versionedstage' => 'Stage' - )); - Phockito::verify($serviceMock)->addDocument($doc1); - Phockito::verify($serviceMock)->addDocument($doc2); + // Check that write updates Live - Versioned::reading_stage('Stage'); - Phockito::reset($serviceMock); + Versioned::set_stage('Stage'); + $item = new SearchVariantVersionedTest_Item(array('TestText' => 'Foo')); $item->write(); - $item->publish('Stage', 'Live'); + $item->copyVersionToStage('Stage', 'Live'); + $object = new SolrIndexVersionedTest_Object(array('TestText' => 'Bar')); $object->write(); - $object->publish('Stage', 'Live'); + $object->copyVersionToStage('Stage', 'Live'); + + $doc1 = $this->getSolrDocument(SearchVariantVersionedTest_Item::class, $item, 'Foo', 'Stage'); + $doc2 = $this->getSolrDocument(SearchVariantVersionedTest_Item::class, $item, 'Foo', 'Live'); + $doc3 = $this->getSolrDocument(SolrIndexVersionedTest_Object::class, $object, 'Bar', 'Stage'); + $doc4 = $this->getSolrDocument(SolrIndexVersionedTest_Object::class, $object, 'Bar', 'Live'); + + // Ensure correct call is made to Solr + $this->getServiceMock(['addDocument', 'commit']) + ->expects($this->exactly(4)) + ->method('addDocument') + ->withConsecutive( + [ + $this->equalTo($doc1), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ], + [ + $this->equalTo($doc2), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ], + [ + $this->equalTo($doc3), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ], + [ + $this->equalTo($doc4), + $this->anything(), + $this->anything(), + $this->anything(), + $this->anything() + ] + ); + SearchUpdater::flush_dirty_indexes(); - $doc = new SolrDocumentMatcher(array( - '_documentid' => $this->getExpectedDocumentId($item, 'Live'), - 'ClassName' => 'SearchVariantVersionedTest_Item', - 'SearchVariantVersionedTest_Item_TestText' => 'Foo', - '_versionedstage' => 'Live' - )); - $doc2 = new SolrDocumentMatcher(array( - '_documentid' => $this->getExpectedDocumentId($object, 'Live'), - 'ClassName' => 'SolrIndexVersionedTest_Object', - 'SolrIndexVersionedTest_Object_TestText' => 'Bar', - '_versionedstage' => 'Live' - )); - Phockito::verify($serviceMock)->addDocument($doc); - Phockito::verify($serviceMock)->addDocument($doc2); } public function testDelete() { - // Setup mocks - $serviceMock = $this->getServiceMock(); - self::$index->setService($serviceMock); - // Delete the live record (not the stage) - Versioned::reading_stage('Stage'); - Phockito::reset($serviceMock); + Versioned::set_stage('Stage'); + $item = new SearchVariantVersionedTest_Item(array('TestText' => 'Too')); $item->write(); - $item->publish('Stage', 'Live'); - Versioned::reading_stage('Live'); + $item->copyVersionToStage('Stage', 'Live'); + Versioned::set_stage('Live'); $id = clone $item; $item->delete(); + + // Check that only the 'Live' version is deleted + $this->getServiceMock(['addDocument', 'commit', 'deleteById']) + ->expects($this->exactly(1)) + ->method('deleteById') + ->with($this->equalTo($this->getExpectedDocumentId($id, 'Live'))); + SearchUpdater::flush_dirty_indexes(); - Phockito::verify($serviceMock, 1) - ->deleteById($this->getExpectedDocumentId($id, 'Live')); - Phockito::verify($serviceMock, 0) - ->deleteById($this->getExpectedDocumentId($id, 'Stage')); // Delete the stage record - Versioned::reading_stage('Stage'); - Phockito::reset($serviceMock); + Versioned::set_stage('Stage'); + $item = new SearchVariantVersionedTest_Item(array('TestText' => 'Too')); $item->write(); - $item->publish('Stage', 'Live'); + $item->copyVersionToStage('Stage', 'Live'); $id = clone $item; $item->delete(); + + // Check that only the 'Stage' version is deleted + $this->getServiceMock(['addDocument', 'commit', 'deleteById']) + ->expects($this->exactly(1)) + ->method('deleteById') + ->with($this->equalTo($this->getExpectedDocumentId($id, 'Stage'))); + SearchUpdater::flush_dirty_indexes(); - Phockito::verify($serviceMock, 1) - ->deleteById($this->getExpectedDocumentId($id, 'Stage')); - Phockito::verify($serviceMock, 0) - ->deleteById($this->getExpectedDocumentId($id, 'Live')); } } diff --git a/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php b/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php index 91eb810..f264010 100644 --- a/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php +++ b/tests/SolrIndexVersionedTest/SolrDocumentMatcher.php @@ -1,14 +1,14 @@ addClass('SearchVariantVersionedTest_Item'); - $this->addClass('SolrIndexVersionedTest_Object'); + $this->addClass(SearchVariantVersionedTest_Item::class); + $this->addClass(SolrIndexVersionedTest_Object::class); $this->addFilterField('TestText'); $this->addFulltextField('Content'); } diff --git a/tests/SolrReindexQueuedTest.php b/tests/SolrReindexQueuedTest.php index c048d5a..684aaa2 100644 --- a/tests/SolrReindexQueuedTest.php +++ b/tests/SolrReindexQueuedTest.php @@ -1,9 +1,23 @@ skipTest = true; - return $this->markTestSkipped("These tests need the Phockito module installed to run"); - } - - if (!interface_exists('QueuedJob')) { + if (!interface_exists('SilverStripe\QueuedJobs\Services\QueuedJob')) { $this->skipTest = true; return $this->markTestSkipped("These tests need the QueuedJobs module installed to run"); } // Set queued handler for reindex - Config::modify()->set('Injector', 'SolrReindexHandler', array( - 'class' => 'SolrReindexQueuedHandler' + Config::modify()->set(Injector::class, SolrReindexHandler::class, array( + 'class' => SolrReindexQueuedHandler::class )); - Injector::inst()->registerService(new SolrReindexQueuedHandler(), 'SolrReindexHandler'); + Injector::inst()->registerService(new SolrReindexQueuedHandler(), SolrReindexHandler::class); // Set test variant SolrReindexTest_Variant::enable(); // Set index list - $this->service = $this->getServiceMock(); - $this->index = singleton('SolrReindexTest_Index'); + $this->service = $this->serviceMock(); + $this->index = singleton(SolrReindexTest_Index::class); $this->index->setService($this->service); FullTextSearch::force_index_list($this->index); } @@ -68,7 +77,8 @@ class SolrReindexQueuedTest extends SapphireTest protected function createDummyData($number) { // Populate dataobjects. Use truncate to generate predictable IDs - DB::query('TRUNCATE "SolrReindexTest_Item"'); + $tableName = DataObject::getSchema()->tableName(SolrReindexTest_Item::class); + DB::get_conn()->clearTable($tableName); // Note that we don't create any records in variant = 2, to represent a variant // that should be cleared without any re-indexes performed @@ -87,9 +97,15 @@ class SolrReindexQueuedTest extends SapphireTest * * @return SolrService */ - protected function getServiceMock() + protected function serviceMock() { - return Phockito::mock('Solr4Service'); + // Setup mock + /** @var SilverStripe\FullTextSearch\Solr\Services\Solr4Service|ObjectProphecy $serviceMock */ + $serviceMock = $this->getMockBuilder(Solr4Service::class) + ->setMethods(['deleteByQuery', 'addDocument']) + ->getMock(); + + return $serviceMock; } public function tearDown() @@ -106,7 +122,7 @@ class SolrReindexQueuedTest extends SapphireTest */ protected function getHandler() { - return Injector::inst()->get('SolrReindexHandler'); + return Injector::inst()->get(SolrReindexHandler::class); } /** @@ -114,7 +130,7 @@ class SolrReindexQueuedTest extends SapphireTest */ protected function getQueuedJobService() { - return singleton('SolrReindexQueuedTest_Service'); + return Injector::inst()->get(SolrReindexQueuedTest_Service::class); } /** @@ -125,6 +141,20 @@ class SolrReindexQueuedTest extends SapphireTest { $this->createDummyData(18); + // Deletes are performed in the main task prior to individual groups being processed + // 18 records means 3 groups of 6 in each variant (6 total) + // Ensure correct call is made to Solr + $this->service->expects($this->exactly(2)) + ->method('deleteByQuery') + ->withConsecutive( + [ + $this->equalTo('-(ClassHierarchy:' . SolrReindexTest_Item::class . ')') + ], + [ + $this->equalTo('+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +(_testvariant:"2")') + ] + ); + // Create pre-existing jobs $this->getQueuedJobService()->queueJob(new SolrReindexQueuedJob()); $this->getQueuedJobService()->queueJob(new SolrReindexGroupQueuedJob()); @@ -140,7 +170,7 @@ class SolrReindexQueuedTest extends SapphireTest // Next job should be queue job $job = $this->getQueuedJobService()->getNextJob(); - $this->assertInstanceOf('SolrReindexQueuedJob', $job); + $this->assertInstanceOf(SolrReindexQueuedJob::class, $job); $this->assertEquals(6, $job->getBatchSize()); // Test that necessary items are created @@ -148,28 +178,19 @@ class SolrReindexQueuedTest extends SapphireTest $job->setLogger($logger); $job->process(); - // Deletes are performed in the main task prior to individual groups being processed - // 18 records means 3 groups of 6 in each variant (6 total) - Phockito::verify($this->service, 2) - ->deleteByQuery(\Hamcrest_Matchers::anything()); $this->assertEquals(1, $logger->countMessages('Beginning init of reindex')); $this->assertEquals(6, $logger->countMessages('Queued Solr Reindex Group ')); - $this->assertEquals(3, $logger->countMessages(' of SolrReindexTest_Item in {"SolrReindexTest_Variant":"0"}')); - $this->assertEquals(3, $logger->countMessages(' of SolrReindexTest_Item in {"SolrReindexTest_Variant":"1"}')); + $this->assertEquals(3, $logger->countMessages(' of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"0"}')); + $this->assertEquals(3, $logger->countMessages(' of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"1"}')); $this->assertEquals(1, $logger->countMessages('Completed init of reindex')); - // Test that invalid classes are removed $this->assertNotEmpty($logger->getMessages('Clearing obsolete classes from SolrReindexTest_Index')); - Phockito::verify($this->service, 1) - ->deleteByQuery('-(ClassHierarchy:SolrReindexTest_Item)'); // Test that valid classes in invalid variants are removed $this->assertNotEmpty($logger->getMessages( - 'Clearing all records of type SolrReindexTest_Item in the current state: {"SolrReindexTest_Variant":"2"}' + 'Clearing all records of type ' . SolrReindexTest_Item::class . ' in the current state: {"' . SolrReindexTest_Variant::class . '":"2"}' )); - Phockito::verify($this->service, 1) - ->deleteByQuery('+(ClassHierarchy:SolrReindexTest_Item) +(_testvariant:"2")'); } /** @@ -188,9 +209,9 @@ class SolrReindexQueuedTest extends SapphireTest // Check next job is a group queued job $job = $this->getQueuedJobService()->getNextJob(); - $this->assertInstanceOf('SolrReindexGroupQueuedJob', $job); + $this->assertInstanceOf(SolrReindexGroupQueuedJob::class, $job); $this->assertEquals( - 'Solr Reindex Group (1/3) of SolrReindexTest_Item in {"SolrReindexTest_Variant":"0"}', + 'Solr Reindex Group (1/3) of ' . SolrReindexTest_Item::class . ' in {' . json_encode(SolrReindexTest_Variant::class) . ':"0"}', $job->getTitle() ); @@ -201,7 +222,7 @@ class SolrReindexQueuedTest extends SapphireTest // Check tasks completed (as per non-queuedjob version) $this->assertEquals(1, $logger->countMessages('Beginning reindex group')); - $this->assertEquals(1, $logger->countMessages('Adding SolrReindexTest_Item')); + $this->assertEquals(1, $logger->countMessages('Adding ' . SolrReindexTest_Item::class . '')); $this->assertEquals(1, $logger->countMessages('Queuing commit on all changes')); $this->assertEquals(1, $logger->countMessages('Completed reindex group')); @@ -216,19 +237,3 @@ class SolrReindexQueuedTest extends SapphireTest } } } - -if (!class_exists('QueuedJobService')) { - return; -} - -class SolrReindexQueuedTest_Service extends QueuedJobService implements TestOnly -{ - /** - * @return QueuedJob - */ - public function getNextJob() - { - $job = $this->getNextPendingJob(); - return $this->initialiseJob($job); - } -} diff --git a/tests/SolrReindexQueuedTest/SolrReindexQueuedTest_Service.php b/tests/SolrReindexQueuedTest/SolrReindexQueuedTest_Service.php new file mode 100644 index 0000000..a5c0626 --- /dev/null +++ b/tests/SolrReindexQueuedTest/SolrReindexQueuedTest_Service.php @@ -0,0 +1,27 @@ + '%$QueueHandler' + ]; + + /** + * @return QueuedJob + */ + public function getNextJob() + { + $job = $this->getNextPendingJob(); + return $this->initialiseJob($job); + } +} diff --git a/tests/SolrReindexTest.php b/tests/SolrReindexTest.php index 340c135..e4faf02 100644 --- a/tests/SolrReindexTest.php +++ b/tests/SolrReindexTest.php @@ -1,20 +1,26 @@ skipTest = true; - return $this->markTestSkipped("These tests need the Phockito module installed to run"); - } - // Set test handler for reindex Config::modify()->set('Injector', 'SolrReindexHandler', array( - 'class' => 'SolrReindexTest_TestHandler' + 'class' => SolrReindexTest_TestHandler::class )); Injector::inst()->registerService(new SolrReindexTest_TestHandler(), 'SolrReindexHandler'); @@ -51,7 +52,7 @@ class SolrReindexTest extends SapphireTest // Set index list $this->service = $this->getServiceMock(); - $this->index = singleton('SolrReindexTest_Index'); + $this->index = singleton(SolrReindexTest_Index::class); $this->index->setService($this->service); FullTextSearch::force_index_list($this->index); } @@ -63,8 +64,7 @@ class SolrReindexTest extends SapphireTest */ protected function createDummyData($number) { - // Populate dataobjects. Use truncate to generate predictable IDs - DB::query('TRUNCATE "SolrReindexTest_Item"'); + self::resetDBSchema(); // Note that we don't create any records in variant = 2, to represent a variant // that should be cleared without any re-indexes performed @@ -85,7 +85,10 @@ class SolrReindexTest extends SapphireTest */ protected function getServiceMock() { - return Phockito::mock('Solr4Service'); + $serviceMock = $this->getMockBuilder(Solr4Service::class) + ->setMethods(['deleteByQuery', 'addDocument']); + + return $serviceMock->getMock(); } public function tearDown() @@ -114,7 +117,7 @@ class SolrReindexTest extends SapphireTest $variant = SearchVariant::current_state(); $this->assertEquals( array( - "SolrReindexTest_Variant" => "0" + SolrReindexTest_Variant::class => "0" ), $variant ); @@ -124,13 +127,13 @@ class SolrReindexTest extends SapphireTest $this->assertEquals( array( array( - "SolrReindexTest_Variant" => "0" + SolrReindexTest_Variant::class => "0" ), array( - "SolrReindexTest_Variant" => "1" + SolrReindexTest_Variant::class => "1" ), array( - "SolrReindexTest_Variant" => "2" + SolrReindexTest_Variant::class => "2" ) ), $allStates @@ -157,36 +160,36 @@ class SolrReindexTest extends SapphireTest */ public function testReindexSegmentsGroups() { + $this->service->method('deleteByQuery') + ->withConsecutive( + ['-(ClassHierarchy:' . SolrReindexTest_Item::class . ')'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +(_testvariant:"2")'] + ); + $this->createDummyData(120); // Initiate re-index $logger = new SolrReindexTest_RecordingLogger(); - $this->getHandler()->runReindex($logger, 21, 'Solr_Reindex'); + $this->getHandler()->runReindex($logger, 21, Solr_Reindex::class); // Test that invalid classes are removed - $this->assertNotEmpty($logger->getMessages('Clearing obsolete classes from SolrReindexTest_Index')); - Phockito::verify($this->service, 1) - ->deleteByQuery('-(ClassHierarchy:SolrReindexTest_Item)'); - + $this->assertContains('Clearing obsolete classes from ' . SolrReindexTest_Index::class, $logger->getMessages()); + //var_dump($logger->getMessages()); // Test that valid classes in invalid variants are removed - $this->assertNotEmpty($logger->getMessages( - 'Clearing all records of type SolrReindexTest_Item in the current state: {"SolrReindexTest_Variant":"2"}' - )); - Phockito::verify($this->service, 1) - ->deleteByQuery('+(ClassHierarchy:SolrReindexTest_Item) +(_testvariant:"2")'); + $this->assertContains('Clearing all records of type ' . SolrReindexTest_Item::class . ' in the current state: {' . json_encode(SolrReindexTest_Variant::class) . ':"2"}', $logger->getMessages()); // 120x2 grouped into groups of 21 results in 12 groups $this->assertEquals(12, $logger->countMessages('Called processGroup with ')); - $this->assertEquals(6, $logger->countMessages('{"SolrReindexTest_Variant":"0"}')); - $this->assertEquals(6, $logger->countMessages('{"SolrReindexTest_Variant":"1"}')); + $this->assertEquals(6, $logger->countMessages('{' . json_encode(SolrReindexTest_Variant::class) . ':"0"}')); + $this->assertEquals(6, $logger->countMessages('{' . json_encode(SolrReindexTest_Variant::class) . ':"1"}')); // Given that there are two variants, there should be two group ids of each number - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 0 of 6')); - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 1 of 6')); - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 2 of 6')); - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 3 of 6')); - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 4 of 6')); - $this->assertEquals(2, $logger->countMessages(' SolrReindexTest_Item, group 5 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 0 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 1 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 2 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 3 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 4 of 6')); + $this->assertEquals(2, $logger->countMessages(' ' . SolrReindexTest_Item::class . ', group 5 of 6')); // Check various group sizes $logger->clear(); @@ -208,25 +211,23 @@ class SolrReindexTest extends SapphireTest */ public function testRunGroup() { + $this->service->method('deleteByQuery') + ->with('+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=2 u=2}mod(ID, 6)" +(_testvariant:"1")'); + $this->createDummyData(120); $logger = new SolrReindexTest_RecordingLogger(); // Initiate re-index of third group (index 2 of 6) - $state = array('SolrReindexTest_Variant' => '1'); - $this->getHandler()->runGroup($logger, $this->index, $state, 'SolrReindexTest_Item', 6, 2); + $state = array(SolrReindexTest_Variant::class => '1'); + $this->getHandler()->runGroup($logger, $this->index, $state, SolrReindexTest_Item::class, 6, 2); $idMessage = $logger->filterMessages('Updated '); $this->assertNotEmpty(preg_match('/^Updated (?[,\d]+)/i', $idMessage[0], $matches)); $ids = array_unique(explode(',', $matches['ids'])); // Test successful - $this->assertNotEmpty($logger->getMessages('Adding SolrReindexTest_Item')); + $this->assertNotEmpty($logger->getMessages('Adding ' . SolrReindexTest_Item::class)); $this->assertNotEmpty($logger->getMessages('Done')); - // Test that items in this variant / group are cleared from solr - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=2 u=2}mod(ID, 6)" +(_testvariant:"1")' - ); - // Test that items in this variant / group are re-indexed // 120 divided into 6 groups should be 20 at least (max 21) $this->assertEquals(21, count($ids), 'Group size is about 20', 1); @@ -241,16 +242,27 @@ class SolrReindexTest extends SapphireTest */ public function testRunAllGroups() { + $this->service->method('deleteByQuery') + ->withConsecutive( + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=0 u=0}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=1 u=1}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=2 u=2}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=3 u=3}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=4 u=4}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=5 u=5}mod(ID, 6)" +(_testvariant:"1")'], + ['+(ClassHierarchy:' . SolrReindexTest_Item::class . ') +_query_:"{!frange l=6 u=6}mod(ID, 6)" +(_testvariant:"1")'] + ); + $this->createDummyData(120); $logger = new SolrReindexTest_RecordingLogger(); // Test that running all groups covers the complete set of ids - $state = array('SolrReindexTest_Variant' => '1'); + $state = array(SolrReindexTest_Variant::class => '1'); for ($i = 0; $i < 6; $i++) { // See testReindexSegmentsGroups for test that each of these states is invoked during a full reindex $this ->getHandler() - ->runGroup($logger, $this->index, $state, 'SolrReindexTest_Item', 6, $i); + ->runGroup($logger, $this->index, $state, SolrReindexTest_Item::class, 6, $i); } // Count all ids updated @@ -262,24 +274,5 @@ class SolrReindexTest extends SapphireTest // Check ids $this->assertEquals(120, count($ids)); - Phockito::verify($this->service, 6)->deleteByQuery(\Hamcrest_Matchers::anything()); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=0 u=0}mod(ID, 6)" +(_testvariant:"1")' - ); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=1 u=1}mod(ID, 6)" +(_testvariant:"1")' - ); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=2 u=2}mod(ID, 6)" +(_testvariant:"1")' - ); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=3 u=3}mod(ID, 6)" +(_testvariant:"1")' - ); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=4 u=4}mod(ID, 6)" +(_testvariant:"1")' - ); - Phockito::verify($this->service, 1)->deleteByQuery( - '+(ClassHierarchy:SolrReindexTest_Item) +_query_:"{!frange l=5 u=5}mod(ID, 6)" +(_testvariant:"1")' - ); } } diff --git a/tests/SolrReindexTest/SolrReindexTest_Index.php b/tests/SolrReindexTest/SolrReindexTest_Index.php index 64e85b2..b1fafec 100644 --- a/tests/SolrReindexTest/SolrReindexTest_Index.php +++ b/tests/SolrReindexTest/SolrReindexTest_Index.php @@ -9,7 +9,7 @@ class SolrReindexTest_Index extends SolrIndex implements TestOnly { public function init() { - $this->addClass('SolrReindexTest_Item'); + $this->addClass(SolrReindexTest_Item::class); $this->addAllFulltextFields(); } } diff --git a/tests/SolrReindexTest/SolrReindexTest_Item.php b/tests/SolrReindexTest/SolrReindexTest_Item.php index 6a08387..40258d2 100644 --- a/tests/SolrReindexTest/SolrReindexTest_Item.php +++ b/tests/SolrReindexTest/SolrReindexTest_Item.php @@ -9,8 +9,10 @@ use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_ItemExtens /** * Does not have any variant extensions */ -class SolrReindexTest_Item extends DataObject implements TestOnly +class SolrReindexTest_Item extends DataObject { + private static $table_name = 'SolrReindexTest_Item'; + private static $extensions = [ SolrReindexTest_ItemExtension::class ]; diff --git a/tests/SolrReindexTest/SolrReindexTest_Variant.php b/tests/SolrReindexTest/SolrReindexTest_Variant.php index dbb6115..94cef6d 100644 --- a/tests/SolrReindexTest/SolrReindexTest_Variant.php +++ b/tests/SolrReindexTest/SolrReindexTest_Variant.php @@ -4,6 +4,7 @@ namespace SilverStripe\FullTextSearch\Tests\SolrReindexTest; use SilverStripe\Dev\TestOnly; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; +use SilverStripe\ORM\DataObject; /** * Dummy variant that selects items with field Varient matching the current value @@ -28,7 +29,7 @@ class SolrReindexTest_Variant extends SearchVariant implements TestOnly self::$current = 0; self::$variants = array( - 'SolrReindexTest_Variant' => singleton('SolrReindexTest_Variant') + self::class => singleton(self::class) ); } @@ -79,7 +80,7 @@ class SolrReindexTest_Variant extends SearchVariant implements TestOnly 'name' => '_testvariant', 'field' => '_testvariant', 'fullfield' => '_testvariant', - 'base' => ClassInfo::baseDataClass($class), + 'base' => DataObject::getSchema()->baseDataClass($class), 'origin' => $class, 'type' => 'Int', 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) @@ -94,8 +95,8 @@ class SolrReindexTest_Variant extends SearchVariant implements TestOnly public function appliesTo($class, $includeSubclasses) { - return $class === 'SolrReindexTest_Item' || - ($includeSubclasses && is_subclass_of($class, 'SolrReindexTest_Item', true)); + return $class === SolrReindexTest_Item::class || + ($includeSubclasses && is_subclass_of($class, SolrReindexTest_Item::class, true)); } public function appliesToEnvironment() From 57f6a55994de4a1ce30947ca88fb8435bdad568e Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 22:53:44 +1200 Subject: [PATCH 32/63] SS 4.0 - Update config files to use full class names & update travis --- .travis.yml | 22 ++++++++++++++++++---- _config/binding.yml | 6 +++--- _config/config.yml | 7 ++----- _config/processor.yml | 36 ++++++++++++------------------------ 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/.travis.yml b/.travis.yml index 29a5d37..0ff92f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,18 +7,32 @@ sudo: false php: - 5.5 - 5.6 + - 7.0 + - 7.1 env: - - DB=MYSQL CORE_RELEASE=3.2 + - DB=MYSQL CORE_RELEASE=4 matrix: include: - php: 5.6 - env: DB=MYSQL CORE_RELEASE=3.2 + env: DB=MYSQL CORE_RELEASE=4 - php: 5.6 - env: DB=MYSQL CORE_RELEASE=3.3 SUBSITES=1 + env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 - php: 5.6 - env: DB=MYSQL CORE_RELEASE=3.3 QUEUEDJOBS=1 + env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 + - php: 7.0 + env: DB=MYSQL CORE_RELEASE=4 + - php: 7.0 + env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 + - php: 7.0 + env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 + - php: 7.1 + env: DB=MYSQL CORE_RELEASE=4 + - php: 7.1 + env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 + - php: 7.1 + env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 before_script: - composer self-update || true diff --git a/_config/binding.yml b/_config/binding.yml index 5f1cfd2..d179d1e 100644 --- a/_config/binding.yml +++ b/_config/binding.yml @@ -1,5 +1,5 @@ -Injector: - RequestProcessor: +SilverStripe\Core\Injector\Injector: + SilverStripe\Control\RequestProcessor: properties: filters: - - '%$SearchUpdater_BindManipulationCaptureFilter' + - '%$SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater_BindManipulationCaptureFilter' diff --git a/_config/config.yml b/_config/config.yml index 0c6c2ab..b54e0b3 100644 --- a/_config/config.yml +++ b/_config/config.yml @@ -1,6 +1,3 @@ -DataObject: +SilverStripe\ORM\DataObject: extensions: - - 'SearchUpdater_ObjectHandler' -Database: - extensions: - - 'SearchManipulateCaptureExtension' + - SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater_ObjectHandler diff --git a/_config/processor.yml b/_config/processor.yml index 430ec5e..ae99f46 100644 --- a/_config/processor.yml +++ b/_config/processor.yml @@ -1,34 +1,22 @@ --- Name: defaultprocessor --- -Injector: - SearchUpdateProcessor: - class: SearchUpdateImmediateProcessor - SolrReindexHandler: - class: SolrReindexImmediateHandler - SearchLogFactory: +SilverStripe\Core\Injector\Injector: + SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor: + class: SilverStripe\FullTextSearch\Search\Processors\SearchUpdateImmediateProcessor + SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler: + class: SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexImmediateHandler + SilverStripe\FullTextSearch\Utils\Logging\SearchLogFactory: class: 'MonologFactory' --- -Name: messagequeueprocessor -Only: - ModuleExists: messagequeue -Except: - Environment: 'dev' ---- -Injector: - SearchUpdateProcessor: - class: SearchUpdateMessageQueueProcessor - SolrReindexHandler: - class: SolrReindexMessageHandler ---- Name: queuedjobprocessor Only: - ModuleExists: queuedjobs + ModuleExists: silverstripe/queuedjobs Except: Environment: 'dev' --- -Injector: - SearchUpdateProcessor: - class: SearchUpdateQueuedJobProcessor - SolrReindexHandler: - class: SolrReindexQueuedHandler +SilverStripe\Core\Injector\Injector: + SilverStripe\FullTextSearch\Search\Processors\SearchUpdateProcessor: + class: SilverStripe\FullTextSearch\Search\Processors\SearchUpdateQueuedJobProcessor + SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler: + class: SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexQueuedHandler From 3c1ace867b6884920c7c133f6eacf504c08399e9 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 22:55:18 +1200 Subject: [PATCH 33/63] SS 4.0 - Disable SubSite installation as SubSite has yet to be upgraded --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0ff92f5..bdce2be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,19 +18,19 @@ matrix: - php: 5.6 env: DB=MYSQL CORE_RELEASE=4 - php: 5.6 - env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 + # env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 - php: 5.6 env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 - php: 7.0 env: DB=MYSQL CORE_RELEASE=4 - php: 7.0 - env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 + # env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 - php: 7.0 env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 - php: 7.1 env: DB=MYSQL CORE_RELEASE=4 - php: 7.1 - env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 + # env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 - php: 7.1 env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 @@ -38,7 +38,7 @@ before_script: - composer self-update || true - git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support - "if [ \"$SUBSITES\" = \"\" -a \"$QUEUEDJOBS\" = \"\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss; fi" - - "if [ \"$SUBSITES\" = \"1\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/subsites; fi" +# - "if [ \"$SUBSITES\" = \"1\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/subsites; fi" - "if [ \"$QUEUEDJOBS\" = \"1\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/queuedjobs; fi" - cd ~/builds/ss From 695b2d2fc3b33896b0215842bc8e8810aff326c9 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:06:30 +1200 Subject: [PATCH 34/63] SS 4.0 - Upgrade search indexes --- code/search/indexes/SearchIndex.php | 19 ++++++++++++------- code/search/indexes/SearchIndex_Null.php | 2 -- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/code/search/indexes/SearchIndex.php b/code/search/indexes/SearchIndex.php index fa9b962..ded3b04 100644 --- a/code/search/indexes/SearchIndex.php +++ b/code/search/indexes/SearchIndex.php @@ -11,6 +11,8 @@ use SilverStripe\FullTextSearch\Search\SearchIntrospection; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; use SilverStripe\FullTextSearch\Utils\MultipleArrayIterator; use SilverStripe\ORM\Queries\SQLSelect; +use SilverStripe\Core\Injector\Injector; + /** * SearchIndex is the base index class. Each connector will provide a subclass of this that * provides search engine specific behavior. @@ -75,7 +77,7 @@ abstract class SearchIndex extends ViewableData $sources = $this->getClasses(); foreach ($sources as $source => $options) { - $sources[$source]['base'] = ClassInfo::baseDataClass($source); + $sources[$source]['base'] = DataObject::getSchema()->baseDataClass($source); $sources[$source]['lookup_chain'] = array(); } @@ -223,7 +225,7 @@ abstract class SearchIndex extends ViewableData } if (!DataObject::getSchema()->classHasTable($class)) { - throw new InvalidArgumentException('Can\'t add classes which don\'t have data tables (no $db or $has_one set on the class)'); + throw new \InvalidArgumentException('Can\'t add classes which don\'t have data tables (no $db or $has_one set on the class)'); } $options = array_merge(array( @@ -300,13 +302,16 @@ abstract class SearchIndex extends ViewableData foreach ($this->getClasses() as $class => $options) { foreach (SearchIntrospection::hierarchy($class, $includeSubclasses, true) as $dataclass) { $fields = DataObject::getSchema()->databaseFields($class); - foreach ($fields as $field => $type) { if (preg_match('/^(\w+)\(/', $type, $match)) { $type = $match[1]; } list($type, $args) = Object::parse_class_spec($type); - if (is_subclass_of($type, 'StringField')) { + + // Get class from shortName + $object = Injector::inst()->get($type, false, ['Name' => 'test']); + + if (is_subclass_of(get_class($object), 'SilverStripe\ORM\FieldType\DBString')) { $this->addFulltextField($field); } } @@ -530,7 +535,7 @@ abstract class SearchIndex extends ViewableData // First, if this object is directly contained in the index, add it foreach ($this->classes as $searchclass => $options) { if ($searchclass == $class || ($options['include_children'] && is_subclass_of($class, $searchclass))) { - $base = ClassInfo::baseDataClass($searchclass); + $base = DataObject::getSchema()->baseDataClass($searchclass); $dirty[$base] = array(); foreach ($statefulids as $statefulid) { $key = serialize($statefulid); @@ -569,14 +574,14 @@ abstract class SearchIndex extends ViewableData } elseif ($step['through'] == 'has_many') { // Use TableName for queries $otherTableName = DataObject::getSchema()->tableName($step['otherclass']); - + $sql = new SQLSelect('"'.$tableName.'"."ID"', '"'.$tableName.'"', '"'.$otherTableName.'"."ID" IN ('.implode(',', $ids).')'); $sql->addInnerJoin($otherTableName, '"'.$tableName.'"."ID" = "'.$otherTableName.'"."'.$step['foreignkey'].'"'); singleton($step['class'])->extend('augmentSQL', $sql); $ids = $sql->execute()->column(); } - + if (empty($ids)) { break; } diff --git a/code/search/indexes/SearchIndex_Null.php b/code/search/indexes/SearchIndex_Null.php index b2a2896..6b92e5d 100644 --- a/code/search/indexes/SearchIndex_Null.php +++ b/code/search/indexes/SearchIndex_Null.php @@ -2,8 +2,6 @@ namespace SilverStripe\FullTextSearch\Search\Indexes; -use SilverStripe\FullTextSearch\Search\Indexes\SearchIndex; - /** * A search index that does nothing. Useful for testing */ From 8e07d4a5c667c8ae1eeed46f84f377068db67396 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:09:47 +1200 Subject: [PATCH 35/63] SS 4.0 - Upgrade search processors and remove MessageQueue as not maintained --- .../SearchUpdateBatchedProcessor.php | 4 ++++ .../SearchUpdateCommitJobProcessor.php | 19 ++++++++++++++++--- .../SearchUpdateMessageQueueProcessor.php | 19 ------------------- .../SearchUpdateQueuedJobProcessor.php | 12 ++++++++++-- 4 files changed, 30 insertions(+), 24 deletions(-) delete mode 100644 code/search/processors/SearchUpdateMessageQueueProcessor.php diff --git a/code/search/processors/SearchUpdateBatchedProcessor.php b/code/search/processors/SearchUpdateBatchedProcessor.php index eaf2fd4..78166da 100644 --- a/code/search/processors/SearchUpdateBatchedProcessor.php +++ b/code/search/processors/SearchUpdateBatchedProcessor.php @@ -1,5 +1,9 @@ create(__CLASS__); - $id = singleton('QueuedJobService')->queueJob($commit, $startAfter); + $id = singleton(QueuedJobService::class)->queueJob($commit, $startAfter); if ($dirty) { $indexes = FullTextSearch::get_indexes(); @@ -159,7 +172,7 @@ class SearchUpdateCommitJobProcessor implements QueuedJob // This could occur if we completed a searchupdate job in a prior request, as well as in // the current request $cooldown = Config::inst()->get(__CLASS__, 'cooldown'); - $now = new DateTime(SS_Datetime::now()->getValue()); + $now = new DateTime(DBDatetime::now()->getValue()); $now->add(new DateInterval('PT'.$cooldown.'S')); $runat = $now->Format('Y-m-d H:i:s'); diff --git a/code/search/processors/SearchUpdateMessageQueueProcessor.php b/code/search/processors/SearchUpdateMessageQueueProcessor.php deleted file mode 100644 index 085a4ca..0000000 --- a/code/search/processors/SearchUpdateMessageQueueProcessor.php +++ /dev/null @@ -1,19 +0,0 @@ -get('SearchMessageQueueUpdater', 'reindex_queue'), - new MethodInvocationMessage($this, "process") - ); - } -} diff --git a/code/search/processors/SearchUpdateQueuedJobProcessor.php b/code/search/processors/SearchUpdateQueuedJobProcessor.php index 17dc750..27eedd4 100644 --- a/code/search/processors/SearchUpdateQueuedJobProcessor.php +++ b/code/search/processors/SearchUpdateQueuedJobProcessor.php @@ -1,9 +1,17 @@ queueJob($this); + singleton(QueuedJobService::class)->queueJob($this); } public function getTitle() From 590ac4cb25a2caf23a99e5cbcf0f93cd2d8b32bf Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:12:33 +1200 Subject: [PATCH 36/63] Update manyMany array index as SS4.0 as an additional class in history. --- code/search/indexes/SearchIndex.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/search/indexes/SearchIndex.php b/code/search/indexes/SearchIndex.php index ded3b04..4e96e74 100644 --- a/code/search/indexes/SearchIndex.php +++ b/code/search/indexes/SearchIndex.php @@ -112,7 +112,7 @@ abstract class SearchIndex extends ViewableData 'through' => 'has_many', 'class' => $dataclass, 'otherclass' => $class, 'foreignkey' => $schema->getRemoteJoinField($className, $lookup, 'has_many') ); } elseif ($manyMany = $schema->manyManyComponent($className, $lookup)) { - $class = $manyMany[1]; + $class = $manyMany[2]; $options['multi_valued'] = true; $options['lookup_chain'][] = array( 'call' => 'method', 'method' => $lookup, From 022575fadb2d7a7ebc46b4b9094ee1b5e91f9e4a Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:13:26 +1200 Subject: [PATCH 37/63] SS 4.0 - Upgrade FullTextSearch, queries and updaters --- code/search/FullTextSearch.php | 3 +++ code/search/queries/SearchQuery.php | 8 ++++++-- code/search/updaters/SearchUpdater.php | 7 ++----- code/search/updaters/SearchUpdater_ObjectHandler.php | 7 +++++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/code/search/FullTextSearch.php b/code/search/FullTextSearch.php index b419d25..bd32511 100644 --- a/code/search/FullTextSearch.php +++ b/code/search/FullTextSearch.php @@ -3,7 +3,10 @@ namespace SilverStripe\FullTextSearch\Search; use SilverStripe\Core\Config\Config; +use SilverStripe\ORM\DataObject; use SilverStripe\Core\ClassInfo; +use ReflectionClass; + /** * Base class to manage active search indexes. */ diff --git a/code/search/queries/SearchQuery.php b/code/search/queries/SearchQuery.php index d40fea4..8fe5f88 100644 --- a/code/search/queries/SearchQuery.php +++ b/code/search/queries/SearchQuery.php @@ -1,11 +1,15 @@ owner->ID; $class = $this->owner->ClassName; $state = SearchVariant::current_state($class); - $base = ClassInfo::baseDataClass($class); + $base = DataObject::getSchema()->baseDataClass($class); $key = "$id:$base:".serialize($state); $statefulids = array(array( @@ -63,4 +66,4 @@ class SearchUpdater_ObjectHandler extends DataExtension SearchUpdater::process_writes($writes); } -} \ No newline at end of file +} From 59c3ad2ded4738594856161f433103034ff122dc Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:16:32 +1200 Subject: [PATCH 38/63] SS 4.0 - Upgrade search variants --- code/search/variants/SearchVariant.php | 6 +++++- .../SearchVariantSiteTreeSubsitesPolyhome.php | 7 ++++++- code/search/variants/SearchVariantSubsites.php | 10 +++++++++- code/search/variants/SearchVariantVersioned.php | 15 +++++++++++---- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/code/search/variants/SearchVariant.php b/code/search/variants/SearchVariant.php index cb03fbb..153ec17 100644 --- a/code/search/variants/SearchVariant.php +++ b/code/search/variants/SearchVariant.php @@ -2,7 +2,11 @@ namespace SilverStripe\FullTextSearch\Search\Variants; +use SilverStripe\ORM\DataObject; use SilverStripe\Core\ClassInfo; +use SilverStripe\FullTextSearch\Utils\CombinationsArrayIterator; +use ReflectionClass; + /** * A Search Variant handles decorators and other situations where the items to reindex or search through are modified * from the default state - for instance, dealing with Versioned or Subsite @@ -79,7 +83,7 @@ abstract class SearchVariant { if (!$class) { if (self::$variants === null) { - $classes = ClassInfo::subclassesFor('SearchVariant'); + $classes = ClassInfo::subclassesFor(static::class); $concrete = array(); foreach ($classes as $variantclass) { diff --git a/code/search/variants/SearchVariantSiteTreeSubsitesPolyhome.php b/code/search/variants/SearchVariantSiteTreeSubsitesPolyhome.php index 58d5c81..54604cc 100644 --- a/code/search/variants/SearchVariantSiteTreeSubsitesPolyhome.php +++ b/code/search/variants/SearchVariantSiteTreeSubsitesPolyhome.php @@ -2,6 +2,11 @@ namespace SilverStripe\FullTextSearch\Search\Variants; use SilverStripe\ORM\Queries\SQLSelect; +use SilverStripe\FullTextSearch\Search\SearchIntrospection; + +if (!class_exists('Subsite') || !class_exists('SubsitePolyhome')) { + return; +} class SearchVariantSiteTreeSubsitesPolyhome extends SearchVariant { @@ -51,7 +56,7 @@ class SearchVariantSiteTreeSubsitesPolyhome extends SearchVariant 'name' => '_subsite', 'field' => '_subsite', 'fullfield' => '_subsite', - 'base' => ClassInfo::baseDataClass($class), + 'base' => DataObject::getSchema()->baseDataClass($class), 'origin' => $class, 'type' => 'Int', 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) diff --git a/code/search/variants/SearchVariantSubsites.php b/code/search/variants/SearchVariantSubsites.php index f331407..5102584 100644 --- a/code/search/variants/SearchVariantSubsites.php +++ b/code/search/variants/SearchVariantSubsites.php @@ -3,6 +3,14 @@ namespace SilverStripe\FullTextSearch\Search\Variants; use SilverStripe\ORM\Queries\SQLSelect; +use SilverStripe\ORM\DataObject; +use SilverStripe\Security\Permission; +use SilverStripe\FullTextSearch\Search\SearchIntrospection; +use SilverStripe\FullTextSearch\Search\Queries\SearchQuery; + +if (!class_exists('Subsite')) { + return; +} class SearchVariantSubsites extends SearchVariant { @@ -57,7 +65,7 @@ class SearchVariantSubsites extends SearchVariant 'name' => '_subsite', 'field' => '_subsite', 'fullfield' => '_subsite', - 'base' => ClassInfo::baseDataClass($class), + 'base' => DataObject::getSchema()->baseDataClass($class), 'origin' => $class, 'type' => 'Int', 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) diff --git a/code/search/variants/SearchVariantVersioned.php b/code/search/variants/SearchVariantVersioned.php index e155d96..af0a419 100644 --- a/code/search/variants/SearchVariantVersioned.php +++ b/code/search/variants/SearchVariantVersioned.php @@ -1,6 +1,13 @@ '_versionedstage', 'field' => '_versionedstage', 'fullfield' => '_versionedstage', - 'base' => ClassInfo::baseDataClass($class), + 'base' => DataObject::getSchema()->baseDataClass($class), 'origin' => $class, 'type' => 'String', 'lookup_chain' => array(array('call' => 'variant', 'variant' => $self, 'method' => 'currentState')) @@ -38,7 +45,7 @@ class SearchVariantVersioned extends SearchVariant public function alterQuery($query, $index) { - $stage = Versioned::current_stage(); + $stage = $this->currentState(); $query->filter('_versionedstage', array($stage, SearchQuery::$missing)); } From 7baf7d57580a95d63645b52f21240dd335611fc8 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:17:12 +1200 Subject: [PATCH 39/63] Use actual classname in SearchVariantVersioned --- code/search/variants/SearchVariantVersioned.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/search/variants/SearchVariantVersioned.php b/code/search/variants/SearchVariantVersioned.php index af0a419..6c73b77 100644 --- a/code/search/variants/SearchVariantVersioned.php +++ b/code/search/variants/SearchVariantVersioned.php @@ -58,7 +58,7 @@ class SearchVariantVersioned extends SearchVariant $stage = 'Stage'; if (preg_match('/^(.*)_Live$/', $table, $matches)) { - $class = $matches[1]; + $class = DataObject::getSchema()->tableClass($matches[1]); $stage = 'Live'; } From 4530fb21fe532a88aa2cd57a4f0f7d4a6e7835f5 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:19:25 +1200 Subject: [PATCH 40/63] SS 4.0 - Upgrade Solr & Solr Index --- code/solr/Solr.php | 12 ++++++++---- code/solr/SolrIndex.php | 17 ++++++++++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/code/solr/Solr.php b/code/solr/Solr.php index 98d3972..72a1305 100644 --- a/code/solr/Solr.php +++ b/code/solr/Solr.php @@ -1,8 +1,12 @@ =')) { $versionDefaults = array( - 'service' => 'Solr4Service', + 'service' => Solr4Service::class, 'extraspath' => Director::baseFolder().'/fulltextsearch/conf/solr/4/extras/', 'templatespath' => Director::baseFolder().'/fulltextsearch/conf/solr/4/templates/', ); } else { $versionDefaults = array( - 'service' => 'Solr3Service', + 'service' => Solr3Service::class, 'extraspath' => Director::baseFolder().'/fulltextsearch/conf/solr/3/extras/', 'templatespath' => Director::baseFolder().'/fulltextsearch/conf/solr/3/templates/', ); @@ -136,7 +140,7 @@ class Solr public static function get_indexes() { - return FullTextSearch::get_indexes('SolrIndex'); + return FullTextSearch::get_indexes(SolrIndex::class); } /** @@ -156,4 +160,4 @@ class Solr $included = true; } } -} \ No newline at end of file +} diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index 8884a4a..b9714fd 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -1,9 +1,20 @@ fulltextFields[$field])) { - throw new InvalidArgumentException("No fulltext field $field exists on ".$this->getIndexName()); + throw new \InvalidArgumentException("No fulltext field $field exists on ".$this->getIndexName()); } if ($level === null) { unset($this->boostedFields[$field]); @@ -578,7 +589,7 @@ abstract class SolrIndex extends SearchIndex foreach ($this->getClasses() as $searchclass => $options) { if ($searchclass == $class || ($options['include_children'] && is_subclass_of($class, $searchclass))) { - $base = ClassInfo::baseDataClass($searchclass); + $base = DataObject::getSchema()->baseDataClass($searchclass); $docs[] = $this->_addAs($object, $base, $options); } } @@ -743,7 +754,7 @@ abstract class SolrIndex extends SearchIndex $offset, $limit, $params, - Apache_Solr_Service::METHOD_POST + \Apache_Solr_Service::METHOD_POST ); $results = new ArrayList(); From ea944373bd433c64507ecb2b90a0004d47936fd1 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:19:44 +1200 Subject: [PATCH 41/63] Only commit non-null values to Solr --- code/solr/SolrIndex.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index b9714fd..379d8d6 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -544,7 +544,10 @@ abstract class SolrIndex extends SearchIndex return; } - $doc->setField($field['name'], $value); + // Only index fields that are not null + if ($value !== null) { + $doc->setField($field['name'], $value); + } } } From 4143850786594c680f935bec58132618b5d116dc Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:21:30 +1200 Subject: [PATCH 42/63] SS 4.0 - Remove MessageHandler Solr integration --- .../handlers/SolrReindexMessageHandler.php | 44 ------------------- 1 file changed, 44 deletions(-) delete mode 100644 code/solr/reindex/handlers/SolrReindexMessageHandler.php diff --git a/code/solr/reindex/handlers/SolrReindexMessageHandler.php b/code/solr/reindex/handlers/SolrReindexMessageHandler.php deleted file mode 100644 index 71e6fba..0000000 --- a/code/solr/reindex/handlers/SolrReindexMessageHandler.php +++ /dev/null @@ -1,44 +0,0 @@ -get(__CLASS__, 'reindex_queue'); - - $logger->info('Queuing message'); - MessageQueue::send( - $queue, - new MethodInvocationMessage('SolrReindexMessageHandler', 'run_reindex', $batchSize, $taskName, $classes) - ); - } - - /** - * Entry point for message queue - * - * @param int $batchSize - * @param string $taskName - * @param array|string|null $classes - */ - public static function run_reindex($batchSize, $taskName, $classes = null) - { - // @todo Logger for message queue? - $logger = Injector::inst()->createWithArgs('Monolog\Logger', array(strtolower(get_class()))); - - $inst = Injector::inst()->get(get_class()); - $inst->runReindex($logger, $batchSize, $taskName, $classes); - } -} From 5fae52374fea11359ca5b12fee4b30452c619092 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:22:28 +1200 Subject: [PATCH 43/63] SS 4.0 - Upgrade Solr reindex components --- .../solr/reindex/handlers/SolrReindexBase.php | 13 +++++--- .../handlers/SolrReindexImmediateHandler.php | 3 ++ .../handlers/SolrReindexQueuedHandler.php | 32 +++++++++++++------ .../jobs/SolrReindexGroupQueuedJob.php | 4 ++- .../reindex/jobs/SolrReindexQueuedJob.php | 4 ++- .../reindex/jobs/SolrReindexQueuedJobBase.php | 14 ++++++-- 6 files changed, 51 insertions(+), 19 deletions(-) diff --git a/code/solr/reindex/handlers/SolrReindexBase.php b/code/solr/reindex/handlers/SolrReindexBase.php index f127537..50822ac 100644 --- a/code/solr/reindex/handlers/SolrReindexBase.php +++ b/code/solr/reindex/handlers/SolrReindexBase.php @@ -5,6 +5,11 @@ namespace SilverStripe\FullTextSearch\Solr\Reindex\Handlers; use Psr\Log\LoggerInterface; use SilverStripe\FullTextSearch\Solr\Solr; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; +use SilverStripe\FullTextSearch\Search\Queries\SearchQuery; +use SilverStripe\ORM\DataObject; +use SilverStripe\ORM\DataList; +use SilverStripe\ORM\DB; /** * Base class for re-indexing of solr content @@ -17,7 +22,7 @@ abstract class SolrReindexBase implements SolrReindexHandler $this->processIndex($logger, $indexInstance, $batchSize, $taskName, $classes); } } - + /** * Process index for a single SolrIndex instance * @@ -163,7 +168,7 @@ abstract class SolrReindexBase implements SolrReindexHandler // This will slow down things a tiny bit, but it is done so that we don't timeout to the database during a reindex DB::query('SELECT 1'); - + $logger->info("Done"); } @@ -181,11 +186,11 @@ abstract class SolrReindexBase implements SolrReindexHandler protected function getRecordsInGroup(SolrIndex $indexInstance, $class, $groups, $group) { // Generate filtered list of local records - $baseClass = ClassInfo::baseDataClass($class); + $baseClass = DataObject::getSchema()->baseDataClass($class); $items = DataList::create($class) ->where(sprintf( '"%s"."ID" %% \'%d\' = \'%d\'', - $baseClass, + DataObject::getSchema()->tableName($baseClass), intval($groups), intval($group) )) diff --git a/code/solr/reindex/handlers/SolrReindexImmediateHandler.php b/code/solr/reindex/handlers/SolrReindexImmediateHandler.php index c0c48bb..e576045 100644 --- a/code/solr/reindex/handlers/SolrReindexImmediateHandler.php +++ b/code/solr/reindex/handlers/SolrReindexImmediateHandler.php @@ -4,6 +4,9 @@ namespace SilverStripe\FullTextSearch\Solr\Reindex\Handlers; use Psr\Log\LoggerInterface; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\FullTextSearch\Solr\Solr; +use SilverStripe\ORM\DB; +use SilverStripe\Control\Director; /** * Invokes an immediate reindex diff --git a/code/solr/reindex/handlers/SolrReindexQueuedHandler.php b/code/solr/reindex/handlers/SolrReindexQueuedHandler.php index 504f328..bda7024 100644 --- a/code/solr/reindex/handlers/SolrReindexQueuedHandler.php +++ b/code/solr/reindex/handlers/SolrReindexQueuedHandler.php @@ -4,11 +4,22 @@ namespace SilverStripe\FullTextSearch\Solr\Reindex\Handlers; use Psr\Log\LoggerInterface; use SilverStripe\FullTextSearch\Solr\SolrIndex; +use SilverStripe\ORM\DataObject; +use SilverStripe\ORM\DB; +use SilverStripe\Core\Convert; +use SilverStripe\Core\Injector\Injector; +use SilverStripe\FullTextSearch\Solr\Reindex\Jobs\SolrReindexQueuedJob; +use SilverStripe\FullTextSearch\Solr\Reindex\Jobs\SolrReindexGroupQueuedJob; +use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateCommitJobProcessor; -if (!interface_exists('QueuedJob')) { +if (!interface_exists('SilverStripe\QueuedJobs\Services\QueuedJob')) { return; } +use SilverStripe\QueuedJobs\Services\QueuedJob; +use SilverStripe\QueuedJobs\Services\QueuedJobService; +use SilverStripe\QueuedJobs\DataObjects\QueuedJobDescriptor; + /** * Represents a queued task to start the reindex job */ @@ -19,7 +30,7 @@ class SolrReindexQueuedHandler extends SolrReindexBase */ protected function getQueuedJobService() { - return singleton('QueuedJobService'); + return singleton(QueuedJobService::class); } /** @@ -33,7 +44,7 @@ class SolrReindexQueuedHandler extends SolrReindexBase $clearable = array( // Paused jobs need to be discarded QueuedJob::STATUS_PAUSED, - + // These types would be automatically started QueuedJob::STATUS_NEW, QueuedJob::STATUS_WAIT, @@ -43,27 +54,28 @@ class SolrReindexQueuedHandler extends SolrReindexBase QueuedJob::STATUS_RUN ); DB::query(sprintf( - 'UPDATE "QueuedJobDescriptor" ' + 'UPDATE "%s" ' . ' SET "JobStatus" = \'%s\'' . ' WHERE "JobStatus" IN (\'%s\')' . ' AND "Implementation" = \'%s\'', + Convert::raw2sql(DataObject::getSchema()->tableName(QueuedJobDescriptor::class)), Convert::raw2sql(QueuedJob::STATUS_CANCELLED), implode("','", Convert::raw2sql($clearable)), Convert::raw2sql($type) )); - return DB::affectedRows(); + return DB::affected_rows(); } public function triggerReindex(LoggerInterface $logger, $batchSize, $taskName, $classes = null) { // Cancel existing jobs - $queues = $this->cancelExistingJobs('SolrReindexQueuedJob'); - $groups = $this->cancelExistingJobs('SolrReindexGroupQueuedJob'); + $queues = $this->cancelExistingJobs(SolrReindexQueuedJob::class); + $groups = $this->cancelExistingJobs(SolrReindexGroupQueuedJob::class); $logger->info("Cancelled {$queues} re-index tasks and {$groups} re-index groups"); // Although this class is used as a service (singleton) it may also be instantiated // as a queuedjob - $job = Injector::inst()->create('SolrReindexQueuedJob', $batchSize, $taskName, $classes); + $job = Injector::inst()->create(SolrReindexQueuedJob::class, $batchSize, $taskName, $classes); $this ->getQueuedJobService() ->queueJob($job); @@ -77,13 +89,13 @@ class SolrReindexQueuedHandler extends SolrReindexBase ) { // Trigger another job for this group $job = Injector::inst()->create( - 'SolrReindexGroupQueuedJob', + SolrReindexGroupQueuedJob::class, get_class($indexInstance), $state, $class, $groups, $group ); $this ->getQueuedJobService() ->queueJob($job); - + $title = $job->getTitle(); $logger->info("Queued {$title}"); } diff --git a/code/solr/reindex/jobs/SolrReindexGroupQueuedJob.php b/code/solr/reindex/jobs/SolrReindexGroupQueuedJob.php index 5f32355..0425eee 100644 --- a/code/solr/reindex/jobs/SolrReindexGroupQueuedJob.php +++ b/code/solr/reindex/jobs/SolrReindexGroupQueuedJob.php @@ -1,6 +1,8 @@ get('SearchLogFactory'); + return Injector::inst()->get(SearchLogFactory::class); } /** @@ -103,7 +111,7 @@ abstract class SolrReindexQueuedJobBase implements QueuedJob */ protected function getHandler() { - return Injector::inst()->get('SolrReindexHandler'); + return Injector::inst()->get(SolrReindexHandler::class); } public function jobFinished() From 6fb5736ef328810a46414563ac4ade34177ab2d6 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:23:37 +1200 Subject: [PATCH 44/63] SS 4.0 - Upgrade Solr services and stores --- code/solr/services/Solr3Service.php | 2 +- code/solr/services/Solr4Service.php | 2 +- code/solr/services/SolrService.php | 2 +- code/solr/stores/SolrConfigStore_File.php | 2 +- code/solr/stores/SolrConfigStore_WebDAV.php | 3 +++ 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/solr/services/Solr3Service.php b/code/solr/services/Solr3Service.php index f2546a6..6afac4d 100644 --- a/code/solr/services/Solr3Service.php +++ b/code/solr/services/Solr3Service.php @@ -3,5 +3,5 @@ namespace SilverStripe\FullTextSearch\Solr\Services; class Solr3Service extends SolrService { - private static $core_class = 'Solr3Service_Core'; + private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\Solr3Service_Core'; } diff --git a/code/solr/services/Solr4Service.php b/code/solr/services/Solr4Service.php index ea69e77..578517b 100644 --- a/code/solr/services/Solr4Service.php +++ b/code/solr/services/Solr4Service.php @@ -3,5 +3,5 @@ namespace SilverStripe\FullTextSearch\Solr\Services; class Solr4Service extends SolrService { - private static $core_class = 'Solr4Service_Core'; + private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\Solr4Service_Core'; } diff --git a/code/solr/services/SolrService.php b/code/solr/services/SolrService.php index 6aae39b..2786605 100644 --- a/code/solr/services/SolrService.php +++ b/code/solr/services/SolrService.php @@ -10,7 +10,7 @@ Solr::include_client_api(); */ class SolrService extends SolrService_Core { - private static $core_class = 'SolrService_Core'; + private static $core_class = 'SilverStripe\FullTextSearch\Solr\Services\SolrService_Core'; /** * Handle encoding the GET parameters and making the HTTP call to execute a core command diff --git a/code/solr/stores/SolrConfigStore_File.php b/code/solr/stores/SolrConfigStore_File.php index 013020a..c221826 100644 --- a/code/solr/stores/SolrConfigStore_File.php +++ b/code/solr/stores/SolrConfigStore_File.php @@ -25,7 +25,7 @@ class SolrConfigStore_File implements SolrConfigStore $worked = @mkdir($targetDir, 0770, true); if (!$worked) { - throw new RuntimeException( + throw new \RuntimeException( sprintf('Failed creating target directory %s, please check permissions', $targetDir) ); } diff --git a/code/solr/stores/SolrConfigStore_WebDAV.php b/code/solr/stores/SolrConfigStore_WebDAV.php index 96259cb..05451f4 100644 --- a/code/solr/stores/SolrConfigStore_WebDAV.php +++ b/code/solr/stores/SolrConfigStore_WebDAV.php @@ -2,6 +2,9 @@ namespace SilverStripe\FullTextSearch\Solr\Stores; +use SilverStripe\FullTextSearch\Utils\WebDAV; +use SilverStripe\FullTextSearch\Solr\Solr; + /** * Class SolrConfigStore_WebDAV * From fa7a23a6d26feecd8fa195017a9fbbdf9afcb3a8 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Wed, 26 Apr 2017 23:24:51 +1200 Subject: [PATCH 45/63] SS 4.0 - Upgrade Combinations array and Logging --- code/utils/CombinationsArrayIterator.php | 3 +++ code/utils/logging/MonologFactory.php | 6 +++++- code/utils/logging/QueuedJobLogHandler.php | 6 +++++- code/utils/logging/SearchLogFactory.php | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/code/utils/CombinationsArrayIterator.php b/code/utils/CombinationsArrayIterator.php index 0e873a8..25c0531 100644 --- a/code/utils/CombinationsArrayIterator.php +++ b/code/utils/CombinationsArrayIterator.php @@ -1,6 +1,9 @@ createWithArgs( - 'QueuedJobLogHandler', + 'SilverStripe\FullTextSearch\Utils\Logging\QueuedJobLogHandler', array($job, Logger::INFO) ); } diff --git a/code/utils/logging/QueuedJobLogHandler.php b/code/utils/logging/QueuedJobLogHandler.php index 1d4337c..bc54bf0 100644 --- a/code/utils/logging/QueuedJobLogHandler.php +++ b/code/utils/logging/QueuedJobLogHandler.php @@ -1,12 +1,16 @@ Date: Fri, 28 Apr 2017 21:50:55 +1200 Subject: [PATCH 46/63] Add FieldDefinitions and CopyFieldDefinitions to casting property in order to render them as HTMLText --- code/solr/SolrIndex.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index 76842a2..bac125b 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -35,6 +35,11 @@ abstract class SolrIndex extends SearchIndex protected $templatesPath = null; + private static $casting = [ + 'FieldDefinitions' => 'HTMLText', + 'CopyFieldDefinitions' => 'HTMLText' + ]; + /** * List of boosted fields * From 8bc6f5982c3db276742a7ba05a5f1aa655f31167 Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Sat, 29 Apr 2017 01:27:57 +1200 Subject: [PATCH 47/63] Replace deprecated code with DataObject::getSchema()->classHasTable() --- code/search/SearchIntrospection.php | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/code/search/SearchIntrospection.php b/code/search/SearchIntrospection.php index a214bc9..e7694b0 100644 --- a/code/search/SearchIntrospection.php +++ b/code/search/SearchIntrospection.php @@ -36,7 +36,7 @@ class SearchIntrospection public static function hierarchy($class, $includeSubclasses = true, $dataOnly = false) { $key = "$class!" . ($includeSubclasses ? 'sc' : 'an') . '!' . ($dataOnly ? 'do' : 'al'); - + if (!isset(self::$hierarchy[$key])) { $classes = array_values(ClassInfo::ancestry($class)); if ($includeSubclasses) { @@ -48,14 +48,13 @@ class SearchIntrospection array_splice($classes, 0, $idx+1); } -//@todo find another way to determine if a dataobject does not have a table -// if ($dataOnly) { -// foreach ($classes as $i => $class) { -// if (!DataObject::has_own_table($class)) { -// unset($classes[$i]); -// } -// } -// } + if ($dataOnly) { + foreach ($classes as $i => $class) { + if (!DataObject::getSchema()->classHasTable($class)) { + unset($classes[$i]); + } + } + } self::$hierarchy[$key] = $classes; } From b4d1e45f3c87ab6323a876ca3ed115f25df99a91 Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Sat, 29 Apr 2017 01:29:59 +1200 Subject: [PATCH 48/63] Add extra slashes to namespaced class passed as variable to shell commands --- code/solr/reindex/handlers/SolrReindexImmediateHandler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/code/solr/reindex/handlers/SolrReindexImmediateHandler.php b/code/solr/reindex/handlers/SolrReindexImmediateHandler.php index b67a33f..de3d02c 100644 --- a/code/solr/reindex/handlers/SolrReindexImmediateHandler.php +++ b/code/solr/reindex/handlers/SolrReindexImmediateHandler.php @@ -59,6 +59,7 @@ class SolrReindexImmediateHandler extends SolrReindexBase // Build script $indexName = $indexInstance->getIndexName(); $indexClass = get_class($indexInstance); + $class = addslashes($class); $scriptPath = sprintf("%s%sframework%scli-script.php", BASE_PATH, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR); $scriptTask = "php {$scriptPath} dev/tasks/{$taskName}"; $cmd = "{$scriptTask} index={$indexClass} class={$class} group={$group} groups={$groups} variantstate={$statevar}"; From 2932ae94cacafcb1f3c5f877d14a6b7a80b2ea40 Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Sat, 29 Apr 2017 01:30:29 +1200 Subject: [PATCH 49/63] Change segments for configure and reindex tasks --- code/solr/tasks/Solr_Configure.php | 4 +--- code/solr/tasks/Solr_Reindex.php | 7 +------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/code/solr/tasks/Solr_Configure.php b/code/solr/tasks/Solr_Configure.php index 3973bb5..2d64a83 100644 --- a/code/solr/tasks/Solr_Configure.php +++ b/code/solr/tasks/Solr_Configure.php @@ -9,7 +9,7 @@ use SilverStripe\FullTextSearch\Solr\Stores\SolrConfigStore; class Solr_Configure extends Solr_BuildTask { - private static $segment = 'Solr_Configure'; + private static $segment = 'SilverStripeFullTextSearchSolrTasksSolr_Configure'; protected $enabled = true; public function run($request) @@ -80,8 +80,6 @@ class Solr_Configure extends Solr_BuildTask return new SolrConfigStore_File($indexstore); } elseif ($mode == 'webdav') { return new SolrConfigStore_WebDAV($indexstore); - //@todo left commented after confusing merge conflict. Revisit if further testing is required - //} elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, 'SolrConfigStore')) { } elseif (ClassInfo::exists($mode) && ClassInfo::classImplements($mode, SolrConfigStore::class)) { return new $mode($indexstore); } else { diff --git a/code/solr/tasks/Solr_Reindex.php b/code/solr/tasks/Solr_Reindex.php index 81af67d..1e828e3 100644 --- a/code/solr/tasks/Solr_Reindex.php +++ b/code/solr/tasks/Solr_Reindex.php @@ -25,7 +25,7 @@ use SilverStripe\FullTextSearch\Solr\SolrIndex; */ class Solr_Reindex extends Solr_BuildTask { - private static $segment = 'Solr_Reindex'; + private static $segment = 'SilverStripeFullTextSearchSolrTasksSolr_Reindex'; protected $enabled = true; @@ -44,11 +44,6 @@ class Solr_Reindex extends Solr_BuildTask */ protected function getHandler() { - - //@todo: this needs to determine the best class from a Factory implementation - //@todo: it was 'SolrReindexHandler' but that doesn't work on 4.0 - //@todo left commented after a confusing merge conflict. Revisit if further investigation /testing is needed - //return Injector::inst()->get('SolrReindexImmediateHandler'); return Injector::inst()->get(SolrReindexHandler::class); } From 7c0ff89adf24ca41ad2555f40f7b6887dec18f37 Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Sat, 29 Apr 2017 01:31:53 +1200 Subject: [PATCH 50/63] Removed @todo as SearchLogFactory interface is injected via Yaml config --- code/solr/tasks/Solr_BuildTask.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/code/solr/tasks/Solr_BuildTask.php b/code/solr/tasks/Solr_BuildTask.php index 7107137..9e4e3c9 100644 --- a/code/solr/tasks/Solr_BuildTask.php +++ b/code/solr/tasks/Solr_BuildTask.php @@ -25,8 +25,6 @@ class Solr_BuildTask extends BuildTask */ public function getLogger() { - //@todo left commented after a confusing merge conflict. Revisit if further testing is required - //return Injector::inst()->get('Logger'); return Injector::inst()->get(LoggerInterface::class); } @@ -45,8 +43,6 @@ class Solr_BuildTask extends BuildTask */ protected function getLoggerFactory() { - //@todo left commented after a confusing merge conflict. Revisit if further testing is required - //return Injector::inst()->get('SearchLogFactory'); return Injector::inst()->get(SearchLogFactory::class); } From 815d619013e3f8a997ec0b1aa7261f3f669546f0 Mon Sep 17 00:00:00 2001 From: elliot sawyer Date: Thu, 27 Apr 2017 22:18:39 +1200 Subject: [PATCH 51/63] SS 4.0 - Strip namespaces from core name since backslashes are not acceptable Solr core names --- code/solr/services/SolrService.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/solr/services/SolrService.php b/code/solr/services/SolrService.php index a521f34..c28b9e1 100644 --- a/code/solr/services/SolrService.php +++ b/code/solr/services/SolrService.php @@ -4,6 +4,7 @@ namespace SilverStripe\FullTextSearch\Solr\Services; use SilverStripe\Core\Config\Config; use SilverStripe\FullTextSearch\Solr\Solr; +use Silverstripe\Core\ClassInfo; Solr::include_client_api(); /** @@ -21,7 +22,8 @@ class SolrService extends SolrService_Core protected function coreCommand($command, $core, $params = array()) { $command = strtoupper($command); - + //get the non-namespaced name of the Solr core, since backslashes not valid characters + $core = ClassInfo::shortName($core); $params = array_merge($params, array('action' => $command, 'wt' => 'json')); $params[$command == 'CREATE' ? 'name' : 'core'] = $core; From e6cd3f4cd2c32fadd1cae89eaad175f25ebe4967 Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Mon, 1 May 2017 12:12:43 +1200 Subject: [PATCH 52/63] Use to make backwards compatible with existing code --- code/solr/tasks/Solr_Configure.php | 2 +- code/solr/tasks/Solr_Reindex.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/solr/tasks/Solr_Configure.php b/code/solr/tasks/Solr_Configure.php index 2d64a83..77c60d6 100644 --- a/code/solr/tasks/Solr_Configure.php +++ b/code/solr/tasks/Solr_Configure.php @@ -9,7 +9,7 @@ use SilverStripe\FullTextSearch\Solr\Stores\SolrConfigStore; class Solr_Configure extends Solr_BuildTask { - private static $segment = 'SilverStripeFullTextSearchSolrTasksSolr_Configure'; + private static $segment = 'Solr_Configure'; protected $enabled = true; public function run($request) diff --git a/code/solr/tasks/Solr_Reindex.php b/code/solr/tasks/Solr_Reindex.php index 1e828e3..39051e9 100644 --- a/code/solr/tasks/Solr_Reindex.php +++ b/code/solr/tasks/Solr_Reindex.php @@ -25,7 +25,7 @@ use SilverStripe\FullTextSearch\Solr\SolrIndex; */ class Solr_Reindex extends Solr_BuildTask { - private static $segment = 'SilverStripeFullTextSearchSolrTasksSolr_Reindex'; + private static $segment = 'Solr_Reindex'; protected $enabled = true; @@ -115,8 +115,8 @@ class Solr_Reindex extends Solr_BuildTask } // If run at the top level, delegate to appropriate handler - $self = get_class($this); - $handler->triggerReindex($this->getLogger(), $this->config()->recordsPerRequest, $self, $class); + $taskName = $this::$segment ?: get_class($this); + $handler->triggerReindex($this->getLogger(), $this->config()->recordsPerRequest, $taskName, $class); } /** From 6478a13425949f3da53ddcb8ca5f0c743812947b Mon Sep 17 00:00:00 2001 From: Marco Hermo Date: Mon, 1 May 2017 12:26:07 +1200 Subject: [PATCH 53/63] Use ->config()->segment instead. It's possible for somebody to change the value of using the Config API --- code/solr/tasks/Solr_Reindex.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/solr/tasks/Solr_Reindex.php b/code/solr/tasks/Solr_Reindex.php index 39051e9..17be26d 100644 --- a/code/solr/tasks/Solr_Reindex.php +++ b/code/solr/tasks/Solr_Reindex.php @@ -115,7 +115,7 @@ class Solr_Reindex extends Solr_BuildTask } // If run at the top level, delegate to appropriate handler - $taskName = $this::$segment ?: get_class($this); + $taskName = $this->config()->segment ?: get_class($this); $handler->triggerReindex($this->getLogger(), $this->config()->recordsPerRequest, $taskName, $class); } From 4c44d1c29e6b50da420b6fe592fdc18838babfeb Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Mon, 1 May 2017 20:18:59 +1200 Subject: [PATCH 54/63] FIX: Broken merge as files have been moved + Fixed additional tests --- ...hUpdater_BindManipulationCaptureFilter.php | 15 ---- code/search/SearchUpdater_ObjectHandler.php | 71 ------------------- .../updaters/SearchUpdater_ObjectHandler.php | 24 +++++-- tests/SearchVariantVersionedTest.php | 6 +- 4 files changed, 23 insertions(+), 93 deletions(-) delete mode 100644 code/search/SearchUpdater_BindManipulationCaptureFilter.php delete mode 100644 code/search/SearchUpdater_ObjectHandler.php diff --git a/code/search/SearchUpdater_BindManipulationCaptureFilter.php b/code/search/SearchUpdater_BindManipulationCaptureFilter.php deleted file mode 100644 index 24cef93..0000000 --- a/code/search/SearchUpdater_BindManipulationCaptureFilter.php +++ /dev/null @@ -1,15 +0,0 @@ -owner->ID) { - return; - } - - // Force SearchUpdater to mark this record as dirty - // Note: Some extensions require entire hierarchy passed to augmentWrite() - $manipulation = array(); - foreach (ClassInfo::ancestry($this->owner) as $class) { - if (!is_subclass_of($class, 'DataObject')) { - continue; - } - $manipulation[$class] = array( - 'fields' => array(), - 'id' => $this->owner->ID, - // Note: 'delete' command not actually handled by manipulations, - // but added so that SearchUpdater can detect the deletion - 'command' => 'delete' - ); - } - $this->owner->extend('augmentWrite', $manipulation); - SearchUpdater::handle_manipulation($manipulation); - } - - /** - * Forces this object to trigger a re-index in the current state - */ - public function triggerReindex() - { - if (!$this->owner->ID) { - return; - } - - $id = $this->owner->ID; - $class = $this->owner->ClassName; - $state = SearchVariant::current_state($class); - $base = ClassInfo::baseDataClass($class); - $key = "$id:$base:" . serialize($state); - - $statefulids = array( - array( - 'id' => $id, - 'state' => $state - ) - ); - - $writes = array( - $key => array( - 'base' => $base, - 'class' => $class, - 'id' => $id, - 'statefulids' => $statefulids, - 'fields' => array() - ) - ); - - SearchUpdater::process_writes($writes); - } -} diff --git a/code/search/updaters/SearchUpdater_ObjectHandler.php b/code/search/updaters/SearchUpdater_ObjectHandler.php index f469584..c75b8df 100644 --- a/code/search/updaters/SearchUpdater_ObjectHandler.php +++ b/code/search/updaters/SearchUpdater_ObjectHandler.php @@ -4,7 +4,9 @@ namespace SilverStripe\FullTextSearch\Search\Updaters; use SilverStripe\ORM\DataExtension; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; +use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater; use SilverStripe\ORM\DataObject; +use SilverStripe\Core\ClassInfo; /** * Delete operations do not use database manipulations. @@ -23,14 +25,26 @@ class SearchUpdater_ObjectHandler extends DataExtension } // Force SearchUpdater to mark this record as dirty - $manipulation = array( - $this->owner->ClassName => array( + // Note: Some extensions require entire hierarchy passed to augmentWrite() + $manipulation = array(); + foreach (ClassInfo::ancestry($this->owner) as $class) { + if (!is_subclass_of($class, DataObject::class)) { + continue; + } + + $tableName = DataObject::getSchema()->tableName($class); + $manipulation[$tableName] = array( 'fields' => array(), 'id' => $this->owner->ID, - 'command' => 'update' - ) - ); + 'class' => $class, + // Note: 'delete' command not actually handled by manipulations, + // but added so that SearchUpdater can detect the deletion + 'command' => 'delete' + ); + } + $this->owner->extend('augmentWrite', $manipulation); + SearchUpdater::handle_manipulation($manipulation); } diff --git a/tests/SearchVariantVersionedTest.php b/tests/SearchVariantVersionedTest.php index bd6a97e..f0a7695 100644 --- a/tests/SearchVariantVersionedTest.php +++ b/tests/SearchVariantVersionedTest.php @@ -2,8 +2,10 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\Core\Config\Config; +use SilverStripe\CMS\Model\SiteTree; use SilverStripe\FullTextSearch\Search\FullTextSearch; use SilverStripe\FullTextSearch\Search\Indexes\SearchIndex_Recording; +use SilverStripe\FullTextSearch\Search\Variants\SearchVariantVersioned; use SilverStripe\FullTextSearch\Tests\SearchVariantVersionedTest\SearchVariantVersionedTest_Index; use SilverStripe\FullTextSearch\Tests\SearchVariantVersionedTest\SearchVariantVersionedTest_Item; use SilverStripe\FullTextSearch\Tests\SearchVariantVersionedTest\SearchVariantVersionedTest_IndexNoStage; @@ -90,7 +92,7 @@ class SearchVariantVersionedTest extends SapphireTest $this->assertCount(1, self::$index->deleted); $this->assertEquals( - 'SiteTree', + SiteTree::class, self::$index->deleted[0]['base'] ); $this->assertEquals( @@ -99,7 +101,7 @@ class SearchVariantVersionedTest extends SapphireTest ); $this->assertEquals( 'Live', - self::$index->deleted[0]['state']['SearchVariantVersioned'] + self::$index->deleted[0]['state'][SearchVariantVersioned::class] ); } From 8adb3171f05814f1c59db641750c1fa6719f26d8 Mon Sep 17 00:00:00 2001 From: Brett Tasker Date: Mon, 1 May 2017 20:46:19 +1200 Subject: [PATCH 55/63] FIX: Update travis to remove php 5.5 + Fix SearchVariantSubsiteTest reference to SapphireTest --- .travis.yml | 1 - tests/SearchVariantSubsitesTest.php | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index bdce2be..10647a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ language: php sudo: false php: - - 5.5 - 5.6 - 7.0 - 7.1 diff --git a/tests/SearchVariantSubsitesTest.php b/tests/SearchVariantSubsitesTest.php index eb29375..f5bee06 100644 --- a/tests/SearchVariantSubsitesTest.php +++ b/tests/SearchVariantSubsitesTest.php @@ -1,5 +1,7 @@ Date: Mon, 1 May 2017 21:19:22 +1200 Subject: [PATCH 56/63] SS 4.0 - Include PHPUnit in composer.json --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b2b4fd3..bb19a82 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ "monolog/monolog": "~1.15" }, "require-dev": { - "silverstripe/cms": "4.0.x-dev" + "silverstripe/cms": "4.0.x-dev", + "phpunit/phpunit": "*@stable" }, "extra": { "branch-alias": { From d7805f46abd23b32fdb74af98a54085d3c10f507 Mon Sep 17 00:00:00 2001 From: elliot sawyer Date: Fri, 19 May 2017 11:23:12 +1200 Subject: [PATCH 57/63] fixes to allow namespacing in index class --- code/solr/reindex/handlers/SolrReindexImmediateHandler.php | 4 +++- code/solr/services/SolrService.php | 3 ++- code/solr/tasks/Solr_Reindex.php | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/code/solr/reindex/handlers/SolrReindexImmediateHandler.php b/code/solr/reindex/handlers/SolrReindexImmediateHandler.php index de3d02c..9f29c98 100644 --- a/code/solr/reindex/handlers/SolrReindexImmediateHandler.php +++ b/code/solr/reindex/handlers/SolrReindexImmediateHandler.php @@ -59,10 +59,12 @@ class SolrReindexImmediateHandler extends SolrReindexBase // Build script $indexName = $indexInstance->getIndexName(); $indexClass = get_class($indexInstance); + $indexClassEscaped = addslashes($indexClass); $class = addslashes($class); $scriptPath = sprintf("%s%sframework%scli-script.php", BASE_PATH, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR); $scriptTask = "php {$scriptPath} dev/tasks/{$taskName}"; - $cmd = "{$scriptTask} index={$indexClass} class={$class} group={$group} groups={$groups} variantstate={$statevar}"; + + $cmd = "{$scriptTask} index={$indexClassEscaped} class={$class} group={$group} groups={$groups} variantstate={$statevar}"; $cmd .= " verbose=1 2>&1"; $logger->info("Running '$cmd'"); diff --git a/code/solr/services/SolrService.php b/code/solr/services/SolrService.php index c28b9e1..75f5c7e 100644 --- a/code/solr/services/SolrService.php +++ b/code/solr/services/SolrService.php @@ -84,6 +84,7 @@ class SolrService extends SolrService_Core public function serviceForCore($core) { $klass = Config::inst()->get(get_called_class(), 'core_class'); - return new $klass($this->_host, $this->_port, $this->_path.$core, $this->_httpTransport); + $coreName = ClassInfo::shortName($core); + return new $klass($this->_host, $this->_port, $this->_path . $coreName, $this->_httpTransport); } } diff --git a/code/solr/tasks/Solr_Reindex.php b/code/solr/tasks/Solr_Reindex.php index 17be26d..dc64616 100644 --- a/code/solr/tasks/Solr_Reindex.php +++ b/code/solr/tasks/Solr_Reindex.php @@ -3,6 +3,7 @@ namespace SilverStripe\FullTextSearch\Solr\Tasks; use ReflectionClass; use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Injector\Injector; +use SilverStripe\Dev\Debug; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; use SilverStripe\ORM\DataList; use SilverStripe\FullTextSearch\Solr\Reindex\Handlers\SolrReindexHandler; From b996f689bcb9c18cc4180e5077d1686476407097 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Tue, 14 Nov 2017 16:08:28 +1300 Subject: [PATCH 58/63] API Remove Object inheritance and update method signatures in CaptureFilter request filter --- code/search/updaters/SearchUpdater.php | 2 +- .../SearchUpdater_BindManipulationCaptureFilter.php | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/code/search/updaters/SearchUpdater.php b/code/search/updaters/SearchUpdater.php index 0f52c46..3a5d278 100644 --- a/code/search/updaters/SearchUpdater.php +++ b/code/search/updaters/SearchUpdater.php @@ -26,7 +26,7 @@ use ReflectionClass; * TODO: The way we bind in is awful hacky. */ -class SearchUpdater extends Object +class SearchUpdater { /** * Replace the database object with a subclass that captures all manipulations and passes them to us diff --git a/code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php b/code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php index e6b4e05..4262e8c 100644 --- a/code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php +++ b/code/search/updaters/SearchUpdater_BindManipulationCaptureFilter.php @@ -4,20 +4,18 @@ namespace SilverStripe\FullTextSearch\Search\Updaters; use SilverStripe\Control\RequestFilter; use SilverStripe\Control\HTTPRequest; -use SilverStripe\Control\Session; -use SilverStripe\ORM\DataModel; use SilverStripe\Control\HTTPResponse; class SearchUpdater_BindManipulationCaptureFilter implements RequestFilter { - public function preRequest(HTTPRequest $request, Session $session, DataModel $model) + public function preRequest(HTTPRequest $request) { SearchUpdater::bind_manipulation_capture(); } - public function postRequest(HTTPRequest $request, HTTPResponse $response, DataModel $model) + public function postRequest(HTTPRequest $request, HTTPResponse $response) { /* NOP */ } -} \ No newline at end of file +} From b448bfcd203d84b1732ca5ae56336480ec97ce74 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Tue, 14 Nov 2017 17:05:30 +1300 Subject: [PATCH 59/63] NEW Add config for shutdown flush, remove references to Object and update tests --- code/search/indexes/SearchIndex.php | 14 +++++--- code/search/updaters/SearchUpdater.php | 18 ++++++---- .../solr/reindex/handlers/SolrReindexBase.php | 3 +- tests/SearchUpdaterTest.php | 4 ++- .../SearchUpdaterTest_ExtendedContainer.php | 6 ++-- .../SearchUpdaterTest_OtherContainer.php | 2 ++ tests/SearchVariantVersionedTest.php | 6 ++-- tests/SolrIndexSubsitesTest.php | 21 ++++------- tests/SolrIndexTest.php | 35 +++++++++---------- tests/SolrIndexVersionedTest.php | 6 ++-- tests/SolrReindexTest.php | 9 +++-- 11 files changed, 70 insertions(+), 54 deletions(-) diff --git a/code/search/indexes/SearchIndex.php b/code/search/indexes/SearchIndex.php index eb08855..3cf687f 100644 --- a/code/search/indexes/SearchIndex.php +++ b/code/search/indexes/SearchIndex.php @@ -6,8 +6,8 @@ use Exception; use InvalidArgumentException; use SilverStripe\View\ViewableData; use SilverStripe\ORM\DataObject; -use SilverStripe\Core\Object; use SilverStripe\Core\ClassInfo; +use SilverStripe\Core\Config\Config; use SilverStripe\FullTextSearch\Search\SearchIntrospection; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; use SilverStripe\FullTextSearch\Utils\MultipleArrayIterator; @@ -160,11 +160,15 @@ abstract class SearchIndex extends ViewableData continue; } - $class = $manyMany[2]; + $class = $manyMany['childClass']; $options['multi_valued'] = true; $options['lookup_chain'][] = array( - 'call' => 'method', 'method' => $lookup, - 'through' => 'many_many', 'class' => $dataclass, 'otherclass' => $class, 'details' => $manyMany + 'call' => 'method', + 'method' => $lookup, + 'through' => 'many_many', + 'class' => $dataclass, + 'otherclass' => $class, + 'details' => $manyMany, ); } @@ -357,7 +361,7 @@ abstract class SearchIndex extends ViewableData if (preg_match('/^(\w+)\(/', $type, $match)) { $type = $match[1]; } - list($type, $args) = Object::parse_class_spec($type); + list($type, $args) = ClassInfo::parse_class_spec($type); // Get class from shortName $object = Injector::inst()->get($type, false, ['Name' => 'test']); diff --git a/code/search/updaters/SearchUpdater.php b/code/search/updaters/SearchUpdater.php index 3a5d278..4a36d1f 100644 --- a/code/search/updaters/SearchUpdater.php +++ b/code/search/updaters/SearchUpdater.php @@ -2,8 +2,8 @@ namespace SilverStripe\FullTextSearch\Search\Updaters; +use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Injector\Injector; -use SilverStripe\Core\Object; use SilverStripe\Dev\SapphireTest; use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DB; @@ -28,6 +28,16 @@ use ReflectionClass; class SearchUpdater { + use Configurable; + + /** + * Whether to register the shutdown function to flush. Can be disabled for example in unit testing. + * + * @config + * @var bool + */ + private static $flush_on_shutdown = true; + /** * Replace the database object with a subclass that captures all manipulations and passes them to us */ @@ -174,11 +184,7 @@ class SearchUpdater } // If we do have some work to do register the shutdown function to actually do the work - - // Don't do it if we're testing - there's no database connection outside the test methods, so we'd - // just get errors - - if (self::$processor && !self::$registered && !SapphireTest::is_running_test()) { + if (self::$processor && !self::$registered && self::config()->get('flush_on_shutdown')) { register_shutdown_function(array(SearchUpdater::class, "flush_dirty_indexes")); self::$registered = true; } diff --git a/code/solr/reindex/handlers/SolrReindexBase.php b/code/solr/reindex/handlers/SolrReindexBase.php index 50822ac..747fb36 100644 --- a/code/solr/reindex/handlers/SolrReindexBase.php +++ b/code/solr/reindex/handlers/SolrReindexBase.php @@ -3,6 +3,7 @@ namespace SilverStripe\FullTextSearch\Solr\Reindex\Handlers; use Psr\Log\LoggerInterface; +use SilverStripe\Core\Environment; use SilverStripe\FullTextSearch\Solr\Solr; use SilverStripe\FullTextSearch\Solr\SolrIndex; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; @@ -146,7 +147,7 @@ abstract class SolrReindexBase implements SolrReindexHandler LoggerInterface $logger, SolrIndex $indexInstance, $state, $class, $groups, $group ) { // Set time limit and state - increase_time_limit_to(); + Environment::increaseTimeLimitTo(); SearchVariant::activate_state($state); $logger->info("Adding $class"); diff --git a/tests/SearchUpdaterTest.php b/tests/SearchUpdaterTest.php index d62f33a..c56764f 100644 --- a/tests/SearchUpdaterTest.php +++ b/tests/SearchUpdaterTest.php @@ -18,8 +18,10 @@ class SearchUpdaterTest extends SapphireTest private static $index = null; - public function setUp() + protected function setUp() { + Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false); + parent::setUp(); if (self::$index === null) { diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_ExtendedContainer.php b/tests/SearchUpdaterTest/SearchUpdaterTest_ExtendedContainer.php index f1e46fc..9daae7b 100644 --- a/tests/SearchUpdaterTest/SearchUpdaterTest_ExtendedContainer.php +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_ExtendedContainer.php @@ -7,7 +7,9 @@ namespace SilverStripe\FullTextSearch\Tests\SearchUpdaterTest; */ class SearchUpdaterTest_ExtendedContainer extends SearchUpdaterTest_OtherContainer { - private static $db = array( + private static $table_name = 'SearchUpdaterTest_ExtendedContainer'; + + private static $db = [ 'SomeField' => 'Varchar', - ); + ]; } diff --git a/tests/SearchUpdaterTest/SearchUpdaterTest_OtherContainer.php b/tests/SearchUpdaterTest/SearchUpdaterTest_OtherContainer.php index 3ab461f..78f105a 100644 --- a/tests/SearchUpdaterTest/SearchUpdaterTest_OtherContainer.php +++ b/tests/SearchUpdaterTest/SearchUpdaterTest_OtherContainer.php @@ -9,6 +9,8 @@ use SilverStripe\ORM\DataObject; */ class SearchUpdaterTest_OtherContainer extends DataObject { + private static $table_name = 'SearchUpdaterTest_OtherContainer'; + private static $has_many = [ 'HasManyObjects' => SearchUpdaterTest_HasMany::class, ]; diff --git a/tests/SearchVariantVersionedTest.php b/tests/SearchVariantVersionedTest.php index f0a7695..37c28c9 100644 --- a/tests/SearchVariantVersionedTest.php +++ b/tests/SearchVariantVersionedTest.php @@ -24,8 +24,10 @@ class SearchVariantVersionedTest extends SapphireTest SearchVariantVersionedTest_Item::class ); - public function setUp() + protected function setUp() { + Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false); + parent::setUp(); if (self::$index === null) { @@ -34,7 +36,7 @@ class SearchVariantVersionedTest extends SapphireTest SearchUpdater::bind_manipulation_capture(); - Config::modify()->set('Injector', SearchUpdateProcessor::class, array( + Config::modify()->set(Injector::class, SearchUpdateProcessor::class, array( 'class' => SearchUpdateImmediateProcessor::class )); diff --git a/tests/SolrIndexSubsitesTest.php b/tests/SolrIndexSubsitesTest.php index 9bd7bd1..0fdd82f 100644 --- a/tests/SolrIndexSubsitesTest.php +++ b/tests/SolrIndexSubsitesTest.php @@ -11,8 +11,8 @@ if (class_exists('\Phockito')) { * Subsite specific solr testing */ class SolrIndexSubsitesTest extends SapphireTest { - - public static $fixture_file = 'SolrIndexSubsitesTest/SolrIndexSubsitesTest.yml'; + // @todo + // protected static $fixture_file = 'SolrIndexSubsitesTest/SolrIndexSubsitesTest.yml'; /** * @var SolrIndexSubsitesTest_Index @@ -21,16 +21,16 @@ class SolrIndexSubsitesTest extends SapphireTest { protected $server = null; - public function setUp() + protected function setUp() { + parent::setUp(); + // Prevent parent::setUp() crashing on db build if (!class_exists('Subsite')) { $this->skipTest = true; $this->markTestSkipped("These tests need the Subsite module installed to run"); } - parent::setUp(); - $this->server = $_SERVER; if (!class_exists('\Phockito')) { @@ -39,13 +39,6 @@ class SolrIndexSubsitesTest extends SapphireTest { return; } - // Check versioned available - if (!class_exists('Subsite')) { - $this->skipTest = true; - $this->markTestSkipped('The subsite module is not installed'); - return; - } - if (self::$index === null) { self::$index = singleton('SolrIndexSubsitesTest_Index'); } @@ -60,9 +53,9 @@ class SolrIndexSubsitesTest extends SapphireTest { SearchUpdater::clear_dirty_indexes(); } - public function tearDown() + protected function tearDown() { - if($this->server) { + if ($this->server) { $_SERVER = $this->server; $this->server = null; } diff --git a/tests/SolrIndexTest.php b/tests/SolrIndexTest.php index 16c26fe..24cb994 100644 --- a/tests/SolrIndexTest.php +++ b/tests/SolrIndexTest.php @@ -1,5 +1,7 @@ fieldData('HasManyObjects.Field1'); - $this->assertArrayHasKey('SearchUpdaterTest_Container_HasManyObjects_Field1', $data); - $this->assertArrayHasKey('SearchUpdaterTest_OtherContainer_HasManyObjects_Field1', $data); + $this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_HasManyObjects_Field1', $data); + $this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_HasManyObjects_Field1', $data); - $dataContainer = $data['SearchUpdaterTest_Container_HasManyObjects_Field1']; + $dataContainer = $data[SearchUpdaterTest_Container::class . '_HasManyObjects_Field1']; $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']); $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']); $this->assertEquals(SearchUpdaterTest_HasMany::class, $dataContainer['class']); - $dataOtherContainer = $data['SearchUpdaterTest_OtherContainer_HasManyObjects_Field1']; + $dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_HasManyObjects_Field1']; $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']); $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']); $this->assertEquals(SearchUpdaterTest_HasMany::class, $dataOtherContainer['class']); @@ -77,15 +77,15 @@ class SolrIndexTest extends SapphireTest $index = new SolrIndexTest_AmbiguousRelationIndex(); $data = $index->fieldData('ManyManyObjects.Field1'); - $this->assertArrayHasKey('SearchUpdaterTest_Container_ManyManyObjects_Field1', $data); - $this->assertArrayHasKey('SearchUpdaterTest_OtherContainer_ManyManyObjects_Field1', $data); + $this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1', $data); + $this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1', $data); - $dataContainer = $data['SearchUpdaterTest_Container_ManyManyObjects_Field1']; + $dataContainer = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1']; $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']); $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']); $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataContainer['class']); - $dataOtherContainer = $data['SearchUpdaterTest_OtherContainer_ManyManyObjects_Field1']; + $dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1']; $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']); $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']); $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataOtherContainer['class']); @@ -96,16 +96,16 @@ class SolrIndexTest extends SapphireTest $index = new SolrIndexTest_AmbiguousRelationInheritedIndex(); $data = $index->fieldData('ManyManyObjects.Field1'); - $this->assertArrayHasKey('SearchUpdaterTest_Container_ManyManyObjects_Field1', $data); - $this->assertArrayHasKey('SearchUpdaterTest_OtherContainer_ManyManyObjects_Field1', $data); - $this->assertArrayNotHasKey('SearchUpdaterTest_ExtendedContainer_ManyManyObjects_Field1', $data); + $this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1', $data); + $this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1', $data); + $this->assertArrayNotHasKey(SearchUpdaterTest_ExtendedContainer::class . '_ManyManyObjects_Field1', $data); - $dataContainer = $data['SearchUpdaterTest_Container_ManyManyObjects_Field1']; + $dataContainer = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1']; $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']); $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']); $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataContainer['class']); - $dataOtherContainer = $data['SearchUpdaterTest_OtherContainer_ManyManyObjects_Field1']; + $dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1']; $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']); $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']); $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataOtherContainer['class']); @@ -248,8 +248,7 @@ class SolrIndexTest extends SapphireTest public function testAddFieldExtraOptions() { - Config::nest(); - Director::set_environment_type('live'); + Injector::inst()->get(Kernel::class)->setEnvironment('live'); $index = new SolrIndexTest_FakeIndex(); @@ -261,8 +260,6 @@ class SolrIndexTest extends SapphireTest $defs = simplexml_load_string('' . $index->getFieldDefinitions() . ''); $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]'); $this->assertEquals((string)$defField1[0]['stored'], 'true'); - - Config::unnest(); } public function testAddAnalyzer() diff --git a/tests/SolrIndexVersionedTest.php b/tests/SolrIndexVersionedTest.php index 70b83a7..35ba3b2 100644 --- a/tests/SolrIndexVersionedTest.php +++ b/tests/SolrIndexVersionedTest.php @@ -27,8 +27,10 @@ class SolrIndexVersionedTest extends SapphireTest SolrIndexVersionedTest_Object::class ); - public function setUp() + protected function setUp() { + Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false); + parent::setUp(); if (self::$index === null) { @@ -37,7 +39,7 @@ class SolrIndexVersionedTest extends SapphireTest SearchUpdater::bind_manipulation_capture(); - Config::modify()->set('Injector', SearchUpdateProcessor::class, array( + Config::modify()->set(Injector::class, SearchUpdateProcessor::class, array( 'class' => SearchUpdateImmediateProcessor::class )); diff --git a/tests/SolrReindexTest.php b/tests/SolrReindexTest.php index 7f2dd85..6a3a069 100644 --- a/tests/SolrReindexTest.php +++ b/tests/SolrReindexTest.php @@ -2,6 +2,7 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\FullTextSearch\Search\FullTextSearch; +use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater; use SilverStripe\FullTextSearch\Search\Variants\SearchVariant; use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Variant; use SilverStripe\FullTextSearch\Tests\SolrReindexTest\SolrReindexTest_Index; @@ -38,14 +39,17 @@ class SolrReindexTest extends SapphireTest */ protected $service = null; - public function setUp() + protected function setUp() { + Config::modify()->set(SearchUpdater::class, 'flush_on_shutdown', false); + parent::setUp(); // Set test handler for reindex - Config::modify()->set('Injector', SolrReindexHandler::class, array( + Config::modify()->set(Injector::class, SolrReindexHandler::class, array( 'class' => SolrReindexTest_TestHandler::class )); + Injector::inst()->registerService(new SolrReindexTest_TestHandler(), SolrReindexHandler::class); // Set test variant @@ -55,6 +59,7 @@ class SolrReindexTest extends SapphireTest $this->service = $this->getServiceMock(); $this->index = singleton(SolrReindexTest_Index::class); $this->index->setService($this->service); + FullTextSearch::force_index_list($this->index); } From 1080d6444a32895fa103ecf974d0cc39cf6e8ddc Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Wed, 15 Nov 2017 09:43:36 +1300 Subject: [PATCH 60/63] FIX Update Travis configuration for SS4, add phpunit config and necessary composer updates --- .travis.yml | 51 ++++++++++++++++++++---------------------------- _config.php | 7 +++++-- codecov.yml | 1 + composer.json | 12 +++++++----- phpunit.xml.dist | 14 +++++++++++++ 5 files changed, 48 insertions(+), 37 deletions(-) create mode 100644 codecov.yml create mode 100644 phpunit.xml.dist diff --git a/.travis.yml b/.travis.yml index 8fd2de7..e16aa32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,43 +1,34 @@ -# See https://github.com/silverstripe/silverstripe-travis-support for setup details - language: php -sudo: false - -php: - - 5.6 - - 7.0 - - 7.1 - env: - - DB=MYSQL CORE_RELEASE=4 + global: + - COMPOSER_ROOT_VERSION="3.0.x-dev" matrix: include: - php: 5.6 - env: DB=MYSQL CORE_RELEASE=4 - - php: 5.6 - env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 + env: DB=MYSQL PHPCS_TEST=1 PHPUNIT_TEST=1 - php: 7.0 - env: DB=MYSQL CORE_RELEASE=4 - - php: 7.0 - # env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 - - php: 7.0 - env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 + env: DB=MYSQL PHPUNIT_TEST=1 - php: 7.1 - env: DB=MYSQL CORE_RELEASE=4 - - php: 7.1 - # env: DB=MYSQL CORE_RELEASE=4 SUBSITES=1 - - php: 7.1 - env: DB=MYSQL CORE_RELEASE=4 QUEUEDJOBS=1 + env: DB=MYSQL PHPUNIT_COVERAGE_TEST=1 + - php: 7.2 + env: DB=MYSQL PHPUNIT_TEST=1 before_script: - - composer self-update || true - - git clone git://github.com/silverstripe/silverstripe-travis-support.git ~/travis-support - - "if [ \"$SUBSITES\" = \"\" -a \"$QUEUEDJOBS\" = \"\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss; fi" -# - "if [ \"$SUBSITES\" = \"1\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/subsites; fi" - - "if [ \"$QUEUEDJOBS\" = \"1\" ]; then php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require silverstripe/queuedjobs; fi" - - cd ~/builds/ss + - phpenv rehash + - phpenv config-rm xdebug.ini + + - composer validate + - composer require --no-update symbiote/silverstripe-queuedjobs ^4.0 + # todo: Add Subsites in + - composer require --no-update silverstripe/installer 4.0.x-dev + - composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile script: - - vendor/bin/phpunit fulltextsearch/tests/ + - if [[ $PHPUNIT_TEST ]]; then vendor/bin/phpunit; fi + - if [[ $PHPUNIT_COVERAGE_TEST ]]; then phpdbg -qrr vendor/bin/phpunit --coverage-clover=coverage.xml; fi + - if [[ $PHPCS_TEST ]]; then vendor/bin/phpcs --standard=vendor/silverstripe/framework/phpcs.xml.dist code tests; fi + +after_success: + - if [[ $PHPUNIT_COVERAGE_TEST ]]; then bash <(curl -s https://codecov.io/bash) -f coverage.xml; fi diff --git a/_config.php b/_config.php index a1de033..118255b 100644 --- a/_config.php +++ b/_config.php @@ -1,4 +1,7 @@ + + tests/ + + + + + code/ + + tests/ + + + + From e590132967e8174364f9190138ff89cede9e0711 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Wed, 15 Nov 2017 09:48:52 +1300 Subject: [PATCH 61/63] FIX Run phpcbf automated linting to fix PSR-2 code styles, add PSR-4 autoloader --- code/search/SearchIntrospection.php | 16 +++++----- .../SearchManipulateCapture_MySQLDatabase.php | 6 ++-- ...chManipulateCapture_PostgreSQLDatabase.php | 6 ++-- ...earchManipulateCapture_SQLite3Database.php | 6 ++-- .../SearchUpdateBatchedProcessor.php | 10 +++---- .../SearchUpdateCommitJobProcessor.php | 2 +- .../processors/SearchUpdateProcessor.php | 10 +++---- .../SearchUpdateQueuedJobProcessor.php | 2 +- code/search/queries/SearchQuery.php | 8 ++--- code/search/queries/SearchQuery_Range.php | 2 +- code/search/updaters/SearchUpdater.php | 3 +- code/search/variants/SearchVariant.php | 17 ++++++----- .../search/variants/SearchVariantSubsites.php | 6 ++-- code/search/variants/SearchVariant_Caller.php | 4 +-- code/solr/Solr.php | 5 +++- code/solr/SolrIndex.php | 16 +++++----- .../solr/reindex/handlers/SolrReindexBase.php | 30 +++++++++++++++---- .../handlers/SolrReindexImmediateHandler.php | 14 +++++++-- .../handlers/SolrReindexQueuedHandler.php | 21 +++++++++++-- code/solr/services/Solr3Service_Core.php | 1 - code/solr/services/Solr4Service_Core.php | 16 +++++++--- code/solr/stores/SolrConfigStore.php | 5 +--- code/solr/stores/SolrConfigStore_File.php | 3 +- code/solr/tasks/Solr_BuildTask.php | 2 ++ code/solr/tasks/Solr_Configure.php | 1 + code/solr/tasks/Solr_Reindex.php | 3 +- code/utils/MultipleArrayIterator.php | 2 ++ code/utils/WebDAV.php | 1 + composer.json | 8 ++++- .../BatchedProcessorTest_Object.php | 2 +- tests/SearchUpdaterTest.php | 18 +++++++---- ...rchVariantSiteTreeSubsitesPolyhomeTest.php | 6 ++-- tests/SearchVariantSubsitesTest.php | 4 +-- tests/SearchVariantVersionedTest.php | 4 ++- tests/Solr4ServiceTest.php | 2 +- .../Solr4ServiceTest_RecordingService.php | 1 - tests/SolrIndexSubsitesTest.php | 27 +++++++++-------- tests/SolrIndexTest.php | 9 ++++-- tests/SolrIndexVersionedTest.php | 4 ++- .../SolrIndexVersionedTest_Object.php | 3 +- tests/SolrReindexQueuedTest.php | 2 ++ tests/SolrReindexTest.php | 2 ++ .../SolrReindexTest_ItemExtension.php | 2 +- .../SolrReindexTest_TestHandler.php | 8 ++++- 44 files changed, 208 insertions(+), 112 deletions(-) diff --git a/code/search/SearchIntrospection.php b/code/search/SearchIntrospection.php index e7694b0..8f061d0 100644 --- a/code/search/SearchIntrospection.php +++ b/code/search/SearchIntrospection.php @@ -1,7 +1,9 @@ $class) { - if (!DataObject::getSchema()->classHasTable($class)) { - unset($classes[$i]); - } - } - } + if ($dataOnly) { + foreach ($classes as $i => $class) { + if (!DataObject::getSchema()->classHasTable($class)) { + unset($classes[$i]); + } + } + } self::$hierarchy[$key] = $classes; } diff --git a/code/search/captures/SearchManipulateCapture_MySQLDatabase.php b/code/search/captures/SearchManipulateCapture_MySQLDatabase.php index f1b9296..5cc666e 100644 --- a/code/search/captures/SearchManipulateCapture_MySQLDatabase.php +++ b/code/search/captures/SearchManipulateCapture_MySQLDatabase.php @@ -5,11 +5,13 @@ namespace SilverStripe\FullTextSearch\Captures; use SilverStripe\ORM\Connect\MySQLDatabase; use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater; -class SearchManipulateCapture_MySQLDatabase extends MySQLDatabase { +class SearchManipulateCapture_MySQLDatabase extends MySQLDatabase +{ public $isManipulationCapture = true; - public function manipulate($manipulation) { + public function manipulate($manipulation) + { $res = parent::manipulate($manipulation); SearchUpdater::handle_manipulation($manipulation); return $res; diff --git a/code/search/captures/SearchManipulateCapture_PostgreSQLDatabase.php b/code/search/captures/SearchManipulateCapture_PostgreSQLDatabase.php index 12906b3..562b1cd 100644 --- a/code/search/captures/SearchManipulateCapture_PostgreSQLDatabase.php +++ b/code/search/captures/SearchManipulateCapture_PostgreSQLDatabase.php @@ -9,11 +9,13 @@ if (!class_exists('PostgreSQLDatabase')) { return; } -class SearchManipulateCapture_PostgreSQLDatabase extends PostgreSQLDatabase { +class SearchManipulateCapture_PostgreSQLDatabase extends PostgreSQLDatabase +{ public $isManipulationCapture = true; - public function manipulate($manipulation) { + public function manipulate($manipulation) + { $res = parent::manipulate($manipulation); SearchUpdater::handle_manipulation($manipulation); return $res; diff --git a/code/search/captures/SearchManipulateCapture_SQLite3Database.php b/code/search/captures/SearchManipulateCapture_SQLite3Database.php index 989b526..a3e4be0 100644 --- a/code/search/captures/SearchManipulateCapture_SQLite3Database.php +++ b/code/search/captures/SearchManipulateCapture_SQLite3Database.php @@ -9,11 +9,13 @@ if (!class_exists('SQLite3Database')) { return; } -class SearchManipulateCapture_SQLite3Database extends SQLite3Database { +class SearchManipulateCapture_SQLite3Database extends SQLite3Database +{ public $isManipulationCapture = true; - public function manipulate($manipulation) { + public function manipulate($manipulation) + { $res = parent::manipulate($manipulation); SearchUpdater::handle_manipulation($manipulation); return $res; diff --git a/code/search/processors/SearchUpdateBatchedProcessor.php b/code/search/processors/SearchUpdateBatchedProcessor.php index 78166da..7eca39f 100644 --- a/code/search/processors/SearchUpdateBatchedProcessor.php +++ b/code/search/processors/SearchUpdateBatchedProcessor.php @@ -26,7 +26,7 @@ abstract class SearchUpdateBatchedProcessor extends SearchUpdateProcessor /** * List of indexes successfully comitted in the current batch - * + * * @var array */ protected $completedIndexes; @@ -43,7 +43,7 @@ abstract class SearchUpdateBatchedProcessor extends SearchUpdateProcessor /** * Up to this number of additional ids can be added to any batch in order to reduce the number * of batches - * + * * @config * @var int */ @@ -59,7 +59,7 @@ abstract class SearchUpdateBatchedProcessor extends SearchUpdateProcessor /** * Set the current batch index - * + * * @param int $batch Index of the batch */ protected function setBatch($batch) @@ -76,7 +76,7 @@ abstract class SearchUpdateBatchedProcessor extends SearchUpdateProcessor /** * Process the current queue - * + * * @return boolean */ public function process() @@ -101,7 +101,7 @@ abstract class SearchUpdateBatchedProcessor extends SearchUpdateProcessor /** * Segments batches acording to the specified rules - * + * * @param array $source Source input * @return array Batches */ diff --git a/code/search/processors/SearchUpdateCommitJobProcessor.php b/code/search/processors/SearchUpdateCommitJobProcessor.php index 122245f..09a96e7 100644 --- a/code/search/processors/SearchUpdateCommitJobProcessor.php +++ b/code/search/processors/SearchUpdateCommitJobProcessor.php @@ -266,7 +266,7 @@ class SearchUpdateCommitJobProcessor implements QueuedJob $this->indexes = $jobData->indexes; } - public function addMessage($message, $severity='INFO') + public function addMessage($message, $severity = 'INFO') { $severity = strtoupper($severity); $this->messages[] = '[' . date('Y-m-d H:i:s') . "][$severity] $message"; diff --git a/code/search/processors/SearchUpdateProcessor.php b/code/search/processors/SearchUpdateProcessor.php index b437f7b..6c27f1d 100644 --- a/code/search/processors/SearchUpdateProcessor.php +++ b/code/search/processors/SearchUpdateProcessor.php @@ -10,7 +10,7 @@ abstract class SearchUpdateProcessor { /** * List of dirty records to process in format - * + * * array( * '$BaseClass' => array( * '$State Key' => array( @@ -62,7 +62,7 @@ abstract class SearchUpdateProcessor /** * Generates the list of indexes to process for the dirty items - * + * * @return array */ protected function prepareIndexes() @@ -112,7 +112,7 @@ abstract class SearchUpdateProcessor /** * Commits the specified index to the Solr service - * + * * @param SolrIndex $index Index object * @return bool Flag indicating success */ @@ -123,7 +123,7 @@ abstract class SearchUpdateProcessor /** * Gets the record data source to process - * + * * @return array */ protected function getSource() @@ -133,7 +133,7 @@ abstract class SearchUpdateProcessor /** * Process all indexes, returning true if successful - * + * * @return bool Flag indicating success */ public function process() diff --git a/code/search/processors/SearchUpdateQueuedJobProcessor.php b/code/search/processors/SearchUpdateQueuedJobProcessor.php index 27eedd4..19a2a06 100644 --- a/code/search/processors/SearchUpdateQueuedJobProcessor.php +++ b/code/search/processors/SearchUpdateQueuedJobProcessor.php @@ -90,7 +90,7 @@ class SearchUpdateQueuedJobProcessor extends SearchUpdateBatchedProcessor implem $this->currentBatch = $jobData->currentBatch; } - public function addMessage($message, $severity='INFO') + public function addMessage($message, $severity = 'INFO') { $severity = strtoupper($severity); $this->messages[] = '[' . date('Y-m-d H:i:s') . "][$severity] $message"; diff --git a/code/search/queries/SearchQuery.php b/code/search/queries/SearchQuery.php index 8fe5f88..8986128 100644 --- a/code/search/queries/SearchQuery.php +++ b/code/search/queries/SearchQuery.php @@ -56,7 +56,7 @@ class SearchQuery extends ViewableData * Similar to {@link search()}, but uses stemming and other similarity algorithms * to find the searched terms. For example, a term "fishing" would also likely find results * containing "fish" or "fisher". Depends on search implementation. - * + * * @param String $text See {@link search()} * @param array $fields See {@link search()} * @param array $boost See {@link search()} @@ -74,7 +74,7 @@ class SearchQuery extends ViewableData /** * Similar to {@link search()}, but typically used to further narrow down * based on other facets which don't influence the field relevancy. - * + * * @param String $field Composite name of the field * @param Mixed $values Scalar value, array of values, or an instance of SearchQuery_Range */ @@ -87,7 +87,7 @@ class SearchQuery extends ViewableData /** * Excludes results which match these criteria, inverse of {@link filter()}. - * + * * @param String $field * @param mixed $values */ @@ -124,5 +124,3 @@ class SearchQuery extends ViewableData return "Search Query\n"; } } - - diff --git a/code/search/queries/SearchQuery_Range.php b/code/search/queries/SearchQuery_Range.php index 33b35e5..6d3b8c3 100644 --- a/code/search/queries/SearchQuery_Range.php +++ b/code/search/queries/SearchQuery_Range.php @@ -31,4 +31,4 @@ class SearchQuery_Range { return $this->start !== null || $this->end !== null; } -} \ No newline at end of file +} diff --git a/code/search/updaters/SearchUpdater.php b/code/search/updaters/SearchUpdater.php index 4a36d1f..2098db3 100644 --- a/code/search/updaters/SearchUpdater.php +++ b/code/search/updaters/SearchUpdater.php @@ -127,8 +127,7 @@ class SearchUpdater 'command' => $command, 'fields' => array() ); - } - // Otherwise update the class label if it's more specific than the currently recorded one + } // Otherwise update the class label if it's more specific than the currently recorded one elseif (is_subclass_of($class, $writes[$key]['class'])) { $writes[$key]['class'] = $class; } diff --git a/code/search/variants/SearchVariant.php b/code/search/variants/SearchVariant.php index 153ec17..b294096 100644 --- a/code/search/variants/SearchVariant.php +++ b/code/search/variants/SearchVariant.php @@ -152,7 +152,7 @@ abstract class SearchVariant * * SearchVariant::call(...) ==== SearchVariant::with()->call(...); */ - public static function call($method, &$a1=null, &$a2=null, &$a3=null, &$a4=null, &$a5=null, &$a6=null, &$a7=null) + public static function call($method, &$a1 = null, &$a2 = null, &$a3 = null, &$a4 = null, &$a5 = null, &$a6 = null, &$a7 = null) { return self::with()->call($method, $a1, $a2, $a3, $a4, $a5, $a6, $a7); } @@ -219,9 +219,10 @@ abstract class SearchVariant * @param string $name Field name * @param array $field Field spec */ - protected function addFilterField($index, $name, $field) { + protected function addFilterField($index, $name, $field) + { // If field already exists, make sure to merge origin / base fields - if(isset($index->filterFields[$name])) { + if (isset($index->filterFields[$name])) { $field['base'] = $this->mergeClasses( $index->filterFields[$name]['base'], $field['base'] @@ -244,21 +245,21 @@ abstract class SearchVariant * @param array|string $right Right class(es) * @return array|string List of classes, or single class */ - protected function mergeClasses($left, $right) { + protected function mergeClasses($left, $right) + { // Merge together and remove dupes - if(!is_array($left)) { + if (!is_array($left)) { $left = array($left); } - if(!is_array($right)) { + if (!is_array($right)) { $right = array($right); } $merged = array_values(array_unique(array_merge($left, $right))); // If there is only one item, return it as a single string - if(count($merged) === 1) { + if (count($merged) === 1) { return reset($merged); } return $merged; } } - diff --git a/code/search/variants/SearchVariantSubsites.php b/code/search/variants/SearchVariantSubsites.php index 0239dbf..5c96ed4 100644 --- a/code/search/variants/SearchVariantSubsites.php +++ b/code/search/variants/SearchVariantSubsites.php @@ -109,12 +109,10 @@ class SearchVariantSubsites extends SearchVariant if (isset($write['fields']['SiteTree:SubsiteID'])) { $subsitesForWrite = array($write['fields']['SiteTree:SubsiteID']); - } - // files in subsite 0 should be in all subsites as they are global + } // files in subsite 0 should be in all subsites as they are global elseif (isset($write['fields']['File:SubsiteID']) && intval($write['fields']['File:SubsiteID']) !== 0) { $subsitesForWrite = array($write['fields']['File:SubsiteID']); - } - else { + } else { $subsitesForWrite = $subsites; } diff --git a/code/search/variants/SearchVariant_Caller.php b/code/search/variants/SearchVariant_Caller.php index b037129..1f0f5d7 100644 --- a/code/search/variants/SearchVariant_Caller.php +++ b/code/search/variants/SearchVariant_Caller.php @@ -14,7 +14,7 @@ class SearchVariant_Caller $this->variants = $variants; } - public function call($method, &$a1=null, &$a2=null, &$a3=null, &$a4=null, &$a5=null, &$a6=null, &$a7=null) + public function call($method, &$a1 = null, &$a2 = null, &$a3 = null, &$a4 = null, &$a5 = null, &$a6 = null, &$a7 = null) { $values = array(); @@ -29,4 +29,4 @@ class SearchVariant_Caller return $values; } -} \ No newline at end of file +} diff --git a/code/solr/Solr.php b/code/solr/Solr.php index 72a1305..f413bb7 100644 --- a/code/solr/Solr.php +++ b/code/solr/Solr.php @@ -121,7 +121,10 @@ class Solr if (!self::$service_singleton) { self::$service_singleton = Object::create( - $options['service'], $options['host'], $options['port'], $options['path'] + $options['service'], + $options['host'], + $options['port'], + $options['path'] ); } diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index 68ca165..c23cb06 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -1,6 +1,7 @@ classIs($class, $nextBase)) { + protected function classIs($class, $base) + { + if (is_array($base)) { + foreach ($base as $nextBase) { + if ($this->classIs($class, $nextBase)) { return true; } } @@ -510,7 +512,7 @@ abstract class SolrIndex extends SearchIndex protected function _addField($doc, $object, $field) { $class = get_class($object); - if(!$this->classIs($class, $field['origin'])) { + if (!$this->classIs($class, $field['origin'])) { return; } diff --git a/code/solr/reindex/handlers/SolrReindexBase.php b/code/solr/reindex/handlers/SolrReindexBase.php index 747fb36..6db01c1 100644 --- a/code/solr/reindex/handlers/SolrReindexBase.php +++ b/code/solr/reindex/handlers/SolrReindexBase.php @@ -34,7 +34,11 @@ abstract class SolrReindexBase implements SolrReindexHandler * @param string $classes */ protected function processIndex( - LoggerInterface $logger, SolrIndex $indexInstance, $batchSize, $taskName, $classes = null + LoggerInterface $logger, + SolrIndex $indexInstance, + $batchSize, + $taskName, + $classes = null ) { // Filter classes for this index $indexClasses = $this->getClassesForIndex($indexInstance, $classes); @@ -87,8 +91,13 @@ abstract class SolrReindexBase implements SolrReindexHandler * @param string $taskName */ protected function processVariant( - LoggerInterface $logger, SolrIndex $indexInstance, $state, - $class, $includeSubclasses, $batchSize, $taskName + LoggerInterface $logger, + SolrIndex $indexInstance, + $state, + $class, + $includeSubclasses, + $batchSize, + $taskName ) { // Set state SearchVariant::activate_state($state); @@ -127,7 +136,13 @@ abstract class SolrReindexBase implements SolrReindexHandler * @param string $taskName Name of task script to run */ abstract protected function processGroup( - LoggerInterface $logger, SolrIndex $indexInstance, $state, $class, $groups, $group, $taskName + LoggerInterface $logger, + SolrIndex $indexInstance, + $state, + $class, + $groups, + $group, + $taskName ); /** @@ -144,7 +159,12 @@ abstract class SolrReindexBase implements SolrReindexHandler * @param int $group */ public function runGroup( - LoggerInterface $logger, SolrIndex $indexInstance, $state, $class, $groups, $group + LoggerInterface $logger, + SolrIndex $indexInstance, + $state, + $class, + $groups, + $group ) { // Set time limit and state Environment::increaseTimeLimitTo(); diff --git a/code/solr/reindex/handlers/SolrReindexImmediateHandler.php b/code/solr/reindex/handlers/SolrReindexImmediateHandler.php index 9f29c98..06e1980 100644 --- a/code/solr/reindex/handlers/SolrReindexImmediateHandler.php +++ b/code/solr/reindex/handlers/SolrReindexImmediateHandler.php @@ -21,7 +21,11 @@ class SolrReindexImmediateHandler extends SolrReindexBase } protected function processIndex( - LoggerInterface $logger, SolrIndex $indexInstance, $batchSize, $taskName, $classes = null + LoggerInterface $logger, + SolrIndex $indexInstance, + $batchSize, + $taskName, + $classes = null ) { parent::processIndex($logger, $indexInstance, $batchSize, $taskName, $classes); @@ -46,7 +50,13 @@ class SolrReindexImmediateHandler extends SolrReindexBase * @param string $taskName Name of task script to run */ protected function processGroup( - LoggerInterface $logger, SolrIndex $indexInstance, $state, $class, $groups, $group, $taskName + LoggerInterface $logger, + SolrIndex $indexInstance, + $state, + $class, + $groups, + $group, + $taskName ) { // Build state $statevar = json_encode($state); diff --git a/code/solr/reindex/handlers/SolrReindexQueuedHandler.php b/code/solr/reindex/handlers/SolrReindexQueuedHandler.php index bda7024..d7b9d43 100644 --- a/code/solr/reindex/handlers/SolrReindexQueuedHandler.php +++ b/code/solr/reindex/handlers/SolrReindexQueuedHandler.php @@ -85,12 +85,22 @@ class SolrReindexQueuedHandler extends SolrReindexBase } protected function processGroup( - LoggerInterface $logger, SolrIndex $indexInstance, $state, $class, $groups, $group, $taskName + LoggerInterface $logger, + SolrIndex $indexInstance, + $state, + $class, + $groups, + $group, + $taskName ) { // Trigger another job for this group $job = Injector::inst()->create( SolrReindexGroupQueuedJob::class, - get_class($indexInstance), $state, $class, $groups, $group + get_class($indexInstance), + $state, + $class, + $groups, + $group ); $this ->getQueuedJobService() @@ -101,7 +111,12 @@ class SolrReindexQueuedHandler extends SolrReindexBase } public function runGroup( - LoggerInterface $logger, SolrIndex $indexInstance, $state, $class, $groups, $group + LoggerInterface $logger, + SolrIndex $indexInstance, + $state, + $class, + $groups, + $group ) { parent::runGroup($logger, $indexInstance, $state, $class, $groups, $group); diff --git a/code/solr/services/Solr3Service_Core.php b/code/solr/services/Solr3Service_Core.php index 15638dc..c2875e0 100644 --- a/code/solr/services/Solr3Service_Core.php +++ b/code/solr/services/Solr3Service_Core.php @@ -2,7 +2,6 @@ namespace SilverStripe\FullTextSearch\Solr\Services; - class Solr3Service_Core extends SolrService_Core { } diff --git a/code/solr/services/Solr4Service_Core.php b/code/solr/services/Solr4Service_Core.php index 056c658..729369e 100644 --- a/code/solr/services/Solr4Service_Core.php +++ b/code/solr/services/Solr4Service_Core.php @@ -25,8 +25,12 @@ class Solr4Service_Core extends SolrService_Core * @inheritdoc * @see Solr4Service_Core::addDocuments */ - public function addDocument(\Apache_Solr_Document $document, $allowDups = false, - $overwritePending = true, $overwriteCommitted = true, $commitWithin = 0 + public function addDocument( + \Apache_Solr_Document $document, + $allowDups = false, + $overwritePending = true, + $overwriteCommitted = true, + $commitWithin = 0 ) { return $this->addDocuments(array($document), $allowDups, $overwritePending, $overwriteCommitted, $commitWithin); } @@ -35,8 +39,12 @@ class Solr4Service_Core extends SolrService_Core * Solr 4.0 compat http://wiki.apache.org/solr/UpdateXmlMessages#Optional_attributes_for_.22add.22 * Remove allowDups, overwritePending and overwriteComitted */ - public function addDocuments($documents, $allowDups = false, $overwritePending = true, - $overwriteCommitted = true, $commitWithin = 0 + public function addDocuments( + $documents, + $allowDups = false, + $overwritePending = true, + $overwriteCommitted = true, + $commitWithin = 0 ) { $overwriteVal = $allowDups ? 'false' : 'true'; $commitWithin = (int) $commitWithin; diff --git a/code/solr/stores/SolrConfigStore.php b/code/solr/stores/SolrConfigStore.php index 7e2e025..a153f2e 100644 --- a/code/solr/stores/SolrConfigStore.php +++ b/code/solr/stores/SolrConfigStore.php @@ -1,5 +1,6 @@ remote.'/'.$index; } -} \ No newline at end of file +} diff --git a/code/solr/tasks/Solr_BuildTask.php b/code/solr/tasks/Solr_BuildTask.php index 9e4e3c9..578f1e0 100644 --- a/code/solr/tasks/Solr_BuildTask.php +++ b/code/solr/tasks/Solr_BuildTask.php @@ -1,9 +1,11 @@ isInstantiable()) { diff --git a/code/utils/MultipleArrayIterator.php b/code/utils/MultipleArrayIterator.php index d7d1185..7b4a530 100644 --- a/code/utils/MultipleArrayIterator.php +++ b/code/utils/MultipleArrayIterator.php @@ -1,6 +1,8 @@ 'Varchar' diff --git a/tests/SearchUpdaterTest.php b/tests/SearchUpdaterTest.php index c56764f..a89077f 100644 --- a/tests/SearchUpdaterTest.php +++ b/tests/SearchUpdaterTest.php @@ -1,16 +1,18 @@ getAdded(array('ID')); // Some databases don't output $added in a consistent order; that's okay - usort($added, function ($a, $b) {return $a['ID']-$b['ID']; }); + usort($added, function ($a, $b) { + return $a['ID']-$b['ID']; + }); $this->assertEquals($added, array( array('ID' => $container1->ID), @@ -93,7 +97,9 @@ class SearchUpdaterTest extends SapphireTest $added = self::$index->getAdded(array('ID')); // Some databases don't output $added in a consistent order; that's okay - usort($added, function ($a, $b) {return $a['ID']-$b['ID']; }); + usort($added, function ($a, $b) { + return $a['ID']-$b['ID']; + }); $this->assertEquals($added, array( array('ID' => $container1->ID), diff --git a/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php index 892619f..49cd4ce 100644 --- a/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php +++ b/tests/SearchVariantSiteTreeSubsitesPolyhomeTest.php @@ -1,13 +1,13 @@ assertEquals(2, $query->require['_subsite'][0]); - } - } diff --git a/tests/SearchVariantVersionedTest.php b/tests/SearchVariantVersionedTest.php index 37c28c9..133d01b 100644 --- a/tests/SearchVariantVersionedTest.php +++ b/tests/SearchVariantVersionedTest.php @@ -1,8 +1,10 @@ hasOneComponent($object->getClassName(), 'Subsite')) { + if (class_exists('Subsite') && DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite')) { $variants[] = '"SearchVariantSubsites":"' . $subsiteID. '"'; } // Check versioned - if($stage) { + if ($stage) { $variants[] = '"SearchVariantVersioned":"' . $stage . '"'; } - return $id.'-'.$class.'-{'.implode(',',$variants).'}'; + return $id.'-'.$class.'-{'.implode(',', $variants).'}'; } public function testPublishing() @@ -127,10 +130,10 @@ class SolrIndexSubsitesTest extends SapphireTest { )); \Phockito::verify($serviceMock)->addDocument($doc1); \Phockito::verify($serviceMock)->addDocument($doc2); - } - public function testCorrectSubsiteIDOnPageWrite() { + public function testCorrectSubsiteIDOnPageWrite() + { $mockWrites = array( '3367:SiteTree:a:1:{s:22:"SearchVariantVersioned";s:4:"Live";}' => array( 'base' => 'SiteTree', @@ -169,7 +172,7 @@ class SolrIndexSubsitesTest extends SapphireTest { $variant = new SearchVariantSubsites(); $tmpMockWrites = $mockWrites; $variant->extractManipulationWriteState($tmpMockWrites); - foreach($tmpMockWrites as $mockWrite) { + foreach ($tmpMockWrites as $mockWrite) { $this->assertCount(1, $mockWrite['statefulids']); $statefulIDs = array_shift($mockWrite['statefulids']); $this->assertEquals(0, $statefulIDs['state']['SearchVariantSubsites']); @@ -180,14 +183,15 @@ class SolrIndexSubsitesTest extends SapphireTest { $tmpMockWrites['3367:SiteTree:a:1:{s:22:"SearchVariantVersioned";s:4:"Live";}']['fields']['SiteTree:SubsiteID'] = $subsite->ID; $variant->extractManipulationWriteState($tmpMockWrites); - foreach($tmpMockWrites as $mockWrite) { + foreach ($tmpMockWrites as $mockWrite) { $this->assertCount(1, $mockWrite['statefulids']); $statefulIDs = array_shift($mockWrite['statefulids']); $this->assertEquals($subsite->ID, $statefulIDs['state']['SearchVariantSubsites']); } } - public function testCorrectSubsiteIDOnFileWrite() { + public function testCorrectSubsiteIDOnFileWrite() + { $subsiteIDs = array('0') + $this->allFixtureIDs('Subsite'); $mockWrites = array( '35910:File:a:0:{}' => array( @@ -217,7 +221,7 @@ class SolrIndexSubsitesTest extends SapphireTest { $variant = new SearchVariantSubsites(); $tmpMockWrites = $mockWrites; $variant->extractManipulationWriteState($tmpMockWrites); - foreach($tmpMockWrites as $mockWrite) { + foreach ($tmpMockWrites as $mockWrite) { $this->assertCount(count($subsiteIDs), $mockWrite['statefulids']); foreach ($mockWrite['statefulids'] as $statefulIDs) { $this->assertTrue( @@ -232,11 +236,10 @@ class SolrIndexSubsitesTest extends SapphireTest { $tmpMockWrites['35910:File:a:0:{}']['fields']['File:SubsiteID'] = $subsite->ID; $variant->extractManipulationWriteState($tmpMockWrites); - foreach($tmpMockWrites as $mockWrite) { + foreach ($tmpMockWrites as $mockWrite) { $this->assertCount(1, $mockWrite['statefulids']); $statefulIDs = array_shift($mockWrite['statefulids']); $this->assertEquals($subsite->ID, $statefulIDs['state']['SearchVariantSubsites']); } } - } diff --git a/tests/SolrIndexTest.php b/tests/SolrIndexTest.php index 24cb994..50c276d 100644 --- a/tests/SolrIndexTest.php +++ b/tests/SolrIndexTest.php @@ -1,5 +1,8 @@ expects($this->exactly(2)) ->method('search') - ->withConsecutive([ + ->withConsecutive( + [ $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'), $this->anything(), $this->anything(), diff --git a/tests/SolrIndexVersionedTest.php b/tests/SolrIndexVersionedTest.php index 35ba3b2..50c004c 100644 --- a/tests/SolrIndexVersionedTest.php +++ b/tests/SolrIndexVersionedTest.php @@ -1,5 +1,7 @@ hasOneComponent($object->getClassName(), 'Subsite')) { + if (class_exists('Subsite') && DataObject::getSchema()->hasOneComponent($object->getClassName(), 'Subsite')) { $subsites = '"SearchVariantSubsites":"0",'; } return $id.'-'.$class.'-{'.$subsites. json_encode(SearchVariantVersioned::class) . ':"'.$stage.'"}'; diff --git a/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php b/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php index dfa0268..5390c0e 100644 --- a/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php +++ b/tests/SolrIndexVersionedTest/SolrIndexVersionedTest_Object.php @@ -9,7 +9,8 @@ use SilverStripe\Versioned\Versioned; /** * Non-sitetree versioned dataobject */ -class SolrIndexVersionedTest_Object extends DataObject implements TestOnly { +class SolrIndexVersionedTest_Object extends DataObject implements TestOnly +{ private static $table_name = 'SolrIndexVersionedTest_Object'; diff --git a/tests/SolrReindexQueuedTest.php b/tests/SolrReindexQueuedTest.php index 42ce09c..243ddd7 100644 --- a/tests/SolrReindexQueuedTest.php +++ b/tests/SolrReindexQueuedTest.php @@ -1,5 +1,7 @@ filtersOnID()) { diff --git a/tests/SolrReindexTest/SolrReindexTest_TestHandler.php b/tests/SolrReindexTest/SolrReindexTest_TestHandler.php index fd86b88..7cf22b7 100644 --- a/tests/SolrReindexTest/SolrReindexTest_TestHandler.php +++ b/tests/SolrReindexTest/SolrReindexTest_TestHandler.php @@ -12,7 +12,13 @@ use SilverStripe\FullTextSearch\Solr\SolrIndex; class SolrReindexTest_TestHandler extends SolrReindexBase { public function processGroup( - LoggerInterface $logger, SolrIndex $indexInstance, $state, $class, $groups, $group, $taskName + LoggerInterface $logger, + SolrIndex $indexInstance, + $state, + $class, + $groups, + $group, + $taskName ) { $indexName = $indexInstance->getIndexName(); $stateName = json_encode($state); From e001b68232014795b6dff201fc4638d433c82612 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Wed, 15 Nov 2017 09:56:14 +1300 Subject: [PATCH 62/63] FIX Remove obsolete Object reference in Solr --- code/solr/Solr.php | 1 - 1 file changed, 1 deletion(-) diff --git a/code/solr/Solr.php b/code/solr/Solr.php index f413bb7..2ccb21f 100644 --- a/code/solr/Solr.php +++ b/code/solr/Solr.php @@ -3,7 +3,6 @@ namespace SilverStripe\FullTextSearch\Solr; use SilverStripe\Control\Director; -use SilverStripe\Core\Object; use SilverStripe\FullTextSearch\Search\FullTextSearch; use SilverStripe\FullTextSearch\Solr\Services\Solr4Service; use SilverStripe\FullTextSearch\Solr\Services\Solr3Service; From 9106371f306b460ec584201284284dd8017c40be Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Wed, 15 Nov 2017 10:58:49 +1300 Subject: [PATCH 63/63] FIX Replace deprecated create_function with closure --- code/search/indexes/SearchIndex.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/search/indexes/SearchIndex.php b/code/search/indexes/SearchIndex.php index 3cf687f..70ba1ac 100644 --- a/code/search/indexes/SearchIndex.php +++ b/code/search/indexes/SearchIndex.php @@ -499,7 +499,10 @@ abstract class SearchIndex extends ViewableData */ protected function _getFieldValue($object, $field) { - set_error_handler(create_function('$no, $str', 'throw new Exception("HTML Parse Error: ".$str);'), E_ALL); + $errorHandler = function ($no, $str) { + throw new Exception('HTML Parse Error: ' . $str); + }; + set_error_handler($errorHandler, E_ALL); try { foreach ($field['lookup_chain'] as $step) {