Localisation updates from https://translatewiki.net.
[mediawiki.git] / includes / api / SearchApi.php
blob1a626087fda885f87015a4a7e6bf55fc559e0713
1 <?php
3 /**
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 * http://www.gnu.org/copyleft/gpl.html
19 * @file
20 * @since 1.28
23 namespace MediaWiki\Api;
25 use LogicException;
26 use MediaWiki\Context\IContextSource;
27 use SearchEngine;
28 use SearchEngineConfig;
29 use SearchEngineFactory;
30 use Wikimedia\ParamValidator\ParamValidator;
31 use Wikimedia\ParamValidator\TypeDef\IntegerDef;
33 /**
34 * Traits for API components that use a SearchEngine.
35 * @ingroup API
37 trait SearchApi {
39 private ?SearchEngineConfig $searchEngineConfig = null;
40 private ?SearchEngineFactory $searchEngineFactory = null;
42 private function checkDependenciesSet() {
43 // Since this is a trait, we can't have a constructor where the services
44 // that we need are injected. Instead, the api modules that use this trait
45 // are responsible for setting them (since api modules *can* have services
46 // injected). Double check that the api module did indeed set them
47 if ( $this->searchEngineConfig === null || $this->searchEngineFactory === null ) {
48 throw new LogicException(
49 'SearchApi requires both a SearchEngineConfig and SearchEngineFactory to be set'
54 /**
55 * When $wgSearchType is null, $wgSearchAlternatives[0] is null. Null isn't
56 * a valid option for an array for PARAM_TYPE, so we'll use a fake name
57 * that can't possibly be a class name and describes what the null behavior
58 * does
59 * @var string
61 private static $BACKEND_NULL_PARAM = 'database-backed';
63 /**
64 * The set of api parameters that are shared between api calls that
65 * call the SearchEngine. Primarily this defines parameters that
66 * are utilized by self::buildSearchEngine().
68 * @param bool $isScrollable True if the api offers scrolling
69 * @return array
71 public function buildCommonApiParams( $isScrollable = true ) {
72 $this->checkDependenciesSet();
74 $params = [
75 'search' => [
76 ParamValidator::PARAM_TYPE => 'string',
77 ParamValidator::PARAM_REQUIRED => true,
79 'namespace' => [
80 ParamValidator::PARAM_DEFAULT => NS_MAIN,
81 ParamValidator::PARAM_TYPE => 'namespace',
82 ParamValidator::PARAM_ISMULTI => true,
84 'limit' => [
85 ParamValidator::PARAM_DEFAULT => 10,
86 ParamValidator::PARAM_TYPE => 'limit',
87 IntegerDef::PARAM_MIN => 1,
88 IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
89 IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2,
92 if ( $isScrollable ) {
93 $params['offset'] = [
94 ParamValidator::PARAM_DEFAULT => 0,
95 IntegerDef::PARAM_MIN => 0,
96 ParamValidator::PARAM_TYPE => 'integer',
97 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
101 $alternatives = $this->searchEngineConfig->getSearchTypes();
102 if ( count( $alternatives ) > 1 ) {
103 $alternatives[0] ??= self::$BACKEND_NULL_PARAM;
104 $params['backend'] = [
105 ParamValidator::PARAM_DEFAULT => $this->searchEngineConfig->getSearchType(),
106 ParamValidator::PARAM_TYPE => $alternatives,
108 // @todo: support profile selection when multiple
109 // backends are available. The solution could be to
110 // merge all possible profiles and let ApiBase
111 // subclasses do the check. Making ApiHelp and ApiSandbox
112 // comprehensive might be more difficult.
113 } else {
114 $params += $this->buildProfileApiParam();
117 return $params;
121 * Build the profile api param definitions. Makes bold assumption only one search
122 * engine is available, ensure that is true before calling.
124 * @return array array containing available additional api param definitions.
125 * Empty if profiles are not supported by the searchEngine implementation.
126 * @suppress PhanTypeMismatchDimFetch
128 private function buildProfileApiParam() {
129 $this->checkDependenciesSet();
131 $configs = $this->getSearchProfileParams();
132 $searchEngine = $this->searchEngineFactory->create();
133 $params = [];
134 foreach ( $configs as $paramName => $paramConfig ) {
135 $profiles = $searchEngine->getProfiles(
136 $paramConfig['profile-type'],
137 $this->getContext()->getUser()
139 if ( !$profiles ) {
140 continue;
143 $types = [];
144 $helpMessages = [];
145 $defaultProfile = null;
146 foreach ( $profiles as $profile ) {
147 $types[] = $profile['name'];
148 if ( isset( $profile['desc-message'] ) ) {
149 $helpMessages[$profile['name']] = $profile['desc-message'];
152 if ( !empty( $profile['default'] ) ) {
153 $defaultProfile = $profile['name'];
157 $params[$paramName] = [
158 ParamValidator::PARAM_TYPE => $types,
159 ApiBase::PARAM_HELP_MSG => $paramConfig['help-message'],
160 ApiBase::PARAM_HELP_MSG_PER_VALUE => $helpMessages,
161 ParamValidator::PARAM_DEFAULT => $defaultProfile,
165 return $params;
169 * Build the search engine to use.
170 * If $params is provided then the following searchEngine options
171 * will be set:
172 * - backend: which search backend to use
173 * - limit: mandatory
174 * - offset: optional
175 * - namespace: mandatory
176 * - search engine profiles defined by SearchApi::getSearchProfileParams()
177 * @param array|null $params API request params (must be sanitized by
178 * ApiBase::extractRequestParams() before)
179 * @return SearchEngine
181 public function buildSearchEngine( ?array $params = null ) {
182 $this->checkDependenciesSet();
184 if ( $params == null ) {
185 return $this->searchEngineFactory->create();
188 $type = $params['backend'] ?? null;
189 if ( $type === self::$BACKEND_NULL_PARAM ) {
190 $type = null;
192 $searchEngine = $this->searchEngineFactory->create( $type );
193 $searchEngine->setNamespaces( $params['namespace'] );
194 $searchEngine->setLimitOffset( $params['limit'], $params['offset'] ?? 0 );
196 // Initialize requested search profiles.
197 $configs = $this->getSearchProfileParams();
198 foreach ( $configs as $paramName => $paramConfig ) {
199 if ( isset( $params[$paramName] ) ) {
200 $searchEngine->setFeatureData(
201 $paramConfig['profile-type'],
202 $params[$paramName]
206 return $searchEngine;
210 * @return array[] array of arrays mapping from parameter name to a two value map
211 * containing 'help-message' and 'profile-type' keys.
213 abstract public function getSearchProfileParams();
216 * @return IContextSource
218 abstract public function getContext();
221 /** @deprecated class alias since 1.43 */
222 class_alias( SearchApi::class, 'SearchApi' );