aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReedy <reedy@wikimedia.org>2020-04-27 13:44:55 +0100
committerKrinkle <krinklemail@gmail.com>2020-04-30 04:29:17 +0000
commiteeb8cb1342760ff75112b679a7aa425d3ea669ca (patch)
treeabba024babe3695d6ffc4f2fa3ca33a04fb4841c
parent6870c216e33d709eda74db8e1220ae84f0856a40 (diff)
downloadmediawikicore-eeb8cb1342760ff75112b679a7aa425d3ea669ca.tar.gz
mediawikicore-eeb8cb1342760ff75112b679a7aa425d3ea669ca.zip
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
-rw-r--r--docs/extension.schema.v1.json4
-rw-r--r--docs/extension.schema.v2.json4
-rw-r--r--includes/DefaultSettings.php10
-rw-r--r--includes/ServiceWiring.php7
-rw-r--r--includes/registration/ExtensionProcessor.php1
-rw-r--r--includes/search/SearchEngineConfig.php37
-rw-r--r--includes/search/SearchEngineFactory.php19
-rw-r--r--tests/phpunit/unit/includes/Rest/Handler/SearchHandlerTest.php2
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;
}
/**
@@ -100,6 +111,30 @@ class SearchEngineConfig {
}
/**
+ * 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 @@
<?php
use MediaWiki\MediaWikiServices;
+use Wikimedia\ObjectFactory;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\ILoadBalancer;
@@ -21,6 +22,7 @@ class SearchEngineFactory {
/**
* Create SearchEngine of the given type.
+ *
* @param string|null $type
* @return SearchEngine
*/
@@ -37,11 +39,22 @@ class SearchEngineFactory {
$class = self::getSearchEngineClass( $lb );
}
- if ( is_subclass_of( $class, SearchDatabase::class ) ) {
- return new $class( $lb );
+ $mappings = $this->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(