From eeb8cb1342760ff75112b679a7aa425d3ea669ca Mon Sep 17 00:00:00 2001 From: Reedy Date: Mon, 27 Apr 2020 13:44:55 +0100 Subject: search: Add 'SearchMappings' attribute to map canonical name to PHP class This allows indirection between the values in $wgSearchType and $wgSearchTypeAlternatives where the underlying class name doesn't match the actual class name that subclasses SearchEngine. Bug: T250977 Change-Id: Ib9634128f07d428276e80a6f2f492b850eef17e8 --- docs/extension.schema.v1.json | 4 +++ docs/extension.schema.v2.json | 4 +++ includes/DefaultSettings.php | 10 ++++++ includes/ServiceWiring.php | 7 ++-- includes/registration/ExtensionProcessor.php | 1 + includes/search/SearchEngineConfig.php | 37 +++++++++++++++++++++- includes/search/SearchEngineFactory.php | 19 +++++++++-- .../includes/Rest/Handler/SearchHandlerTest.php | 2 +- 8 files changed, 77 insertions(+), 7 deletions(-) diff --git a/docs/extension.schema.v1.json b/docs/extension.schema.v1.json index e23f0ac7bc08..6730e6da6162 100644 --- a/docs/extension.schema.v1.json +++ b/docs/extension.schema.v1.json @@ -843,6 +843,10 @@ "type": "array", "description": "DEPRECATED: Parser test suite files to be run by parserTests.php when no specific filename is passed to it" }, + "SearchMappings": { + "type": "object", + "description": "Mapping of search canonical names (used in $wgSearchType and $wgSearchTypeAlternatives) using the Object Factory specification" + }, "ServiceWiringFiles": { "type": "array", "description": "List of service wiring files to be loaded by the default instance of MediaWikiServices" diff --git a/docs/extension.schema.v2.json b/docs/extension.schema.v2.json index a1163c3bc232..78e1fabb3572 100644 --- a/docs/extension.schema.v2.json +++ b/docs/extension.schema.v2.json @@ -972,6 +972,10 @@ "type": "array", "description": "DEPRECATED: Parser test suite files to be run by parserTests.php when no specific filename is passed to it" }, + "SearchMappings": { + "type": "object", + "description": "Mapping of search canonical names (used in $wgSearchType and $wgSearchTypeAlternatives) using the Object Factory specification" + }, "ServiceWiringFiles": { "type": "array", "description": "List of service wiring files to be loaded by the default instance of MediaWikiServices" diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index b16280948022..6cc56dad76d1 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -2030,18 +2030,28 @@ $wgDBadminpassword = null; /** * Search type. + * * Leave as null to select the default search engine for the * selected database type (eg SearchMySQL), or set to a class * name to override to a custom search engine. + * + * If the canonical name for the search engine doesn't match the class name + * (because it's namespaced for example), you can add a mapping for this in + * SearchMappings in extension.json. */ $wgSearchType = null; /** * Alternative search types + * * Sometimes you want to support multiple search engines for testing. This * allows users to select their search engine of choice via url parameters * to Special:Search and the action=search API. If using this, there's no * need to add $wgSearchType to it, that is handled automatically. + * + * If the canonical name for the search engine doesn't match the class name + * (because it's namespaced for example), you can add a mapping for this in + * SearchMappings in extension.json. */ $wgSearchTypeAlternatives = null; diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index 9071418e1817..62998d395c5c 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -969,8 +969,11 @@ return [ 'SearchEngineConfig' => function ( MediaWikiServices $services ) : SearchEngineConfig { // @todo This should not take a Config object, but it's not so easy to remove because it // exposes it in a getter, which is actually used. - return new SearchEngineConfig( $services->getMainConfig(), - $services->getContentLanguage() ); + return new SearchEngineConfig( + $services->getMainConfig(), + $services->getContentLanguage(), + ExtensionRegistry::getInstance()->getAttribute( 'SearchMappings' ) + ); }, 'SearchEngineFactory' => function ( MediaWikiServices $services ) : SearchEngineFactory { diff --git a/includes/registration/ExtensionProcessor.php b/includes/registration/ExtensionProcessor.php index ea8ea216fef2..36dc32806084 100644 --- a/includes/registration/ExtensionProcessor.php +++ b/includes/registration/ExtensionProcessor.php @@ -131,6 +131,7 @@ class ExtensionProcessor implements Processor { 'type', 'config', 'config_prefix', + 'SearchMappings', 'ServiceWiringFiles', 'ParserTestFiles', 'AutoloadClasses', diff --git a/includes/search/SearchEngineConfig.php b/includes/search/SearchEngineConfig.php index d79028c7b997..507006288a81 100644 --- a/includes/search/SearchEngineConfig.php +++ b/includes/search/SearchEngineConfig.php @@ -20,9 +20,20 @@ class SearchEngineConfig { */ private $language; - public function __construct( Config $config, Language $lang ) { + /** + * Search Engine Mappings + * + * Key is the canonical name (used in $wgSearchType and $wgSearchTypeAlternatives). + * Value is a specification for ObjectFactory. + * + * @var array + */ + private $engineMappings; + + public function __construct( Config $config, Language $lang, array $mappings ) { $this->config = $config; $this->language = $lang; + $this->engineMappings = $mappings; } /** @@ -99,6 +110,30 @@ class SearchEngineConfig { return $this->config->get( 'SearchType' ); } + /** + * Returns the mappings between canonical search name and underlying PHP class + * + * Key is the canonical name (used in $wgSearchType and $wgSearchTypeAlternatives). + * Value is a specification for ObjectFactory. + * + * For example to be able to use 'foobarsearch' in $wgSearchType and + * $wgSearchTypeAlternatives but the PHP class for 'foobarsearch' + * is 'MediaWiki\Extensions\FoobarSearch\FoobarSearch' set: + * + * @par extension.json Example: + * @code + * 'SearchMappings': { + * 'foobarsearch': { 'class': 'MediaWiki\\Extensions\\FoobarSearch\\FoobarSearch' } + * } + * @endcode + * + * @since 1.35 + * @return array + */ + public function getSearchMappings() { + return $this->engineMappings; + } + /** * Get a list of namespace names useful for showing in tooltips * and preferences. diff --git a/includes/search/SearchEngineFactory.php b/includes/search/SearchEngineFactory.php index bd53fc6b1e21..2e3223809313 100644 --- a/includes/search/SearchEngineFactory.php +++ b/includes/search/SearchEngineFactory.php @@ -1,6 +1,7 @@ config->getSearchMappings(); + + if ( isset( $mappings[$class] ) ) { + $spec = $mappings[$class]; } else { - return new $class(); + // Convert non mapped classes to ObjectFactory spec + $spec = [ 'class' => $class ]; } + + $args = []; + + if ( isset( $spec['class'] ) && is_subclass_of( $spec['class'], SearchDatabase::class ) ) { + $args['extraArgs'][] = $lb; + } + + return ObjectFactory::getObjectFromSpec( $spec, $args ); } /** diff --git a/tests/phpunit/unit/includes/Rest/Handler/SearchHandlerTest.php b/tests/phpunit/unit/includes/Rest/Handler/SearchHandlerTest.php index cc690e6ef810..865e7b63bda5 100644 --- a/tests/phpunit/unit/includes/Rest/Handler/SearchHandlerTest.php +++ b/tests/phpunit/unit/includes/Rest/Handler/SearchHandlerTest.php @@ -56,7 +56,7 @@ class SearchHandlerTest extends \MediaWikiUnitTestCase { /** @var Language|MockObject $language */ $language = $this->createNoOpMock( Language::class ); - $searchEngineConfig = new \SearchEngineConfig( $config, $language ); + $searchEngineConfig = new \SearchEngineConfig( $config, $language, [] ); /** @var PermissionManager|MockObject $permissionManager */ $permissionManager = $this->createNoOpMock( -- cgit v1.2.3