MediaWiki  master
SearchApi.php
Go to the documentation of this file.
1 <?php
2 
25 
30 trait SearchApi {
31 
32  private SearchEngineConfig $searchEngineConfig;
33  private SearchEngineFactory $searchEngineFactory;
34 
35  private function checkDependenciesSet() {
36  // Since this is a trait, we can't have a constructor where the services
37  // that we need are injected. Instead, the api modules that use this trait
38  // are responsible for setting them (since api modules *can* have services
39  // injected). Double check that the api module did indeed set them
40  // @phan-suppress-next-line PhanRedundantCondition Phan trusts the type hints too much
41  if ( !isset( $this->searchEngineConfig ) || !isset( $this->searchEngineFactory ) ) {
42  throw new LogicException(
43  'SearchApi requires both a SearchEngineConfig and SearchEngineFactory to be set'
44  );
45  }
46  }
47 
54  private static $BACKEND_NULL_PARAM = 'database-backed';
55 
64  public function buildCommonApiParams( $isScrollable = true ) {
65  $this->checkDependenciesSet();
66 
67  $params = [
68  'search' => [
69  ParamValidator::PARAM_TYPE => 'string',
70  ParamValidator::PARAM_REQUIRED => true,
71  ],
72  'namespace' => [
73  ParamValidator::PARAM_DEFAULT => NS_MAIN,
74  ParamValidator::PARAM_TYPE => 'namespace',
75  ParamValidator::PARAM_ISMULTI => true,
76  ],
77  'limit' => [
78  ParamValidator::PARAM_DEFAULT => 10,
79  ParamValidator::PARAM_TYPE => 'limit',
80  IntegerDef::PARAM_MIN => 1,
81  IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
82  IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2,
83  ],
84  ];
85  if ( $isScrollable ) {
86  $params['offset'] = [
87  ParamValidator::PARAM_DEFAULT => 0,
88  IntegerDef::PARAM_MIN => 0,
89  ParamValidator::PARAM_TYPE => 'integer',
90  ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
91  ];
92  }
93 
94  $alternatives = $this->searchEngineConfig->getSearchTypes();
95  if ( count( $alternatives ) > 1 ) {
96  $alternatives[0] ??= self::$BACKEND_NULL_PARAM;
97  $params['backend'] = [
98  ParamValidator::PARAM_DEFAULT => $this->searchEngineConfig->getSearchType(),
99  ParamValidator::PARAM_TYPE => $alternatives,
100  ];
101  // @todo: support profile selection when multiple
102  // backends are available. The solution could be to
103  // merge all possible profiles and let ApiBase
104  // subclasses do the check. Making ApiHelp and ApiSandbox
105  // comprehensive might be more difficult.
106  } else {
107  $params += $this->buildProfileApiParam();
108  }
109 
110  return $params;
111  }
112 
121  private function buildProfileApiParam() {
122  $this->checkDependenciesSet();
123 
124  $configs = $this->getSearchProfileParams();
125  $searchEngine = $this->searchEngineFactory->create();
126  $params = [];
127  foreach ( $configs as $paramName => $paramConfig ) {
128  $profiles = $searchEngine->getProfiles(
129  $paramConfig['profile-type'],
130  $this->getContext()->getUser()
131  );
132  if ( !$profiles ) {
133  continue;
134  }
135 
136  $types = [];
137  $helpMessages = [];
138  $defaultProfile = null;
139  foreach ( $profiles as $profile ) {
140  $types[] = $profile['name'];
141  if ( isset( $profile['desc-message'] ) ) {
142  $helpMessages[$profile['name']] = $profile['desc-message'];
143  }
144 
145  if ( !empty( $profile['default'] ) ) {
146  $defaultProfile = $profile['name'];
147  }
148  }
149 
150  $params[$paramName] = [
151  ParamValidator::PARAM_TYPE => $types,
152  ApiBase::PARAM_HELP_MSG => $paramConfig['help-message'],
153  ApiBase::PARAM_HELP_MSG_PER_VALUE => $helpMessages,
154  ParamValidator::PARAM_DEFAULT => $defaultProfile,
155  ];
156  }
157 
158  return $params;
159  }
160 
174  public function buildSearchEngine( array $params = null ) {
175  $this->checkDependenciesSet();
176 
177  if ( $params == null ) {
178  return $this->searchEngineFactory->create();
179  }
180 
181  $type = $params['backend'] ?? null;
182  if ( $type === self::$BACKEND_NULL_PARAM ) {
183  $type = null;
184  }
185  $searchEngine = $this->searchEngineFactory->create( $type );
186  $searchEngine->setNamespaces( $params['namespace'] );
187  $searchEngine->setLimitOffset( $params['limit'], $params['offset'] ?? 0 );
188 
189  // Initialize requested search profiles.
190  $configs = $this->getSearchProfileParams();
191  foreach ( $configs as $paramName => $paramConfig ) {
192  if ( isset( $params[$paramName] ) ) {
193  $searchEngine->setFeatureData(
194  $paramConfig['profile-type'],
195  $params[$paramName]
196  );
197  }
198  }
199  return $searchEngine;
200  }
201 
206  abstract public function getSearchProfileParams();
207 
211  abstract public function getContext();
212 }
getUser()
const NS_MAIN
Definition: Defines.php:64
getSearchProfileParams()
buildSearchEngine(array $params=null)
Build the search engine to use.
Definition: SearchApi.php:174
buildCommonApiParams( $isScrollable=true)
The set of api parameters that are shared between api calls that call the SearchEngine.
Definition: SearchApi.php:64
getContext()
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition: ApiBase.php:210
const LIMIT_BIG1
Fast query, standard limit.
Definition: ApiBase.php:235
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:170
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition: ApiBase.php:237
Configuration handling class for SearchEngine.
Factory class for SearchEngine.
Service for formatting and validating API parameters.
Type definition for integer types.
Definition: IntegerDef.php:23
trait SearchApi
Traits for API components that use a SearchEngine.
Definition: SearchApi.php:30