Completed
Branch master (939199)
by
unknown
39:35
created

includes/api/SearchApi.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
use MediaWiki\MediaWikiServices;
3
4
/**
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 * http://www.gnu.org/copyleft/gpl.html
19
 *
20
 * @file
21
 * @since 1.28
22
 */
23
24
/**
25
 * Traits for API components that use a SearchEngine.
26
 * @ingroup API
27
 */
28
trait SearchApi {
29
30
	/**
31
	 * When $wgSearchType is null, $wgSearchAlternatives[0] is null. Null isn't
32
	 * a valid option for an array for PARAM_TYPE, so we'll use a fake name
33
	 * that can't possibly be a class name and describes what the null behavior
34
	 * does
35
	 */
36
	private static $BACKEND_NULL_PARAM = 'database-backed';
37
38
	/**
39
	 * The set of api parameters that are shared between api calls that
40
	 * call the SearchEngine. Primarily this defines parameters that
41
	 * are utilized by self::buildSearchEngine().
42
	 *
43
	 * @param bool $isScrollable True if the api offers scrolling
44
	 * @return array
45
	 */
46
	public function buildCommonApiParams( $isScrollable = true ) {
47
		$params = [
48
			'search' => [
49
				ApiBase::PARAM_TYPE => 'string',
50
				ApiBase::PARAM_REQUIRED => true,
51
			],
52
			'namespace' => [
53
				ApiBase::PARAM_DFLT => NS_MAIN,
54
				ApiBase::PARAM_TYPE => 'namespace',
55
				ApiBase::PARAM_ISMULTI => true,
56
			],
57
			'limit' => [
58
				ApiBase::PARAM_DFLT => 10,
59
				ApiBase::PARAM_TYPE => 'limit',
60
				ApiBase::PARAM_MIN => 1,
61
				ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
62
				ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2,
63
			],
64
		];
65
		if ( $isScrollable ) {
66
			$params['offset'] = [
67
				ApiBase::PARAM_DFLT => 0,
68
				ApiBase::PARAM_TYPE => 'integer',
69
				ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
70
			];
71
		}
72
73
		$searchConfig = MediaWikiServices::getInstance()->getSearchEngineConfig();
74
		$alternatives = $searchConfig->getSearchTypes();
75
		if ( count( $alternatives ) > 1 ) {
76
			if ( $alternatives[0] === null ) {
77
				$alternatives[0] = self::$BACKEND_NULL_PARAM;
78
			}
79
			$this->allowedParams['backend'] = [
0 ignored issues
show
The property allowedParams does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
80
				ApiBase::PARAM_DFLT => $searchConfig->getSearchType(),
81
				ApiBase::PARAM_TYPE => $alternatives,
82
			];
83
			// @todo: support profile selection when multiple
84
			// backends are available. The solution could be to
85
			// merge all possible profiles and let ApiBase
86
			// subclasses do the check. Making ApiHelp and ApiSandbox
87
			// comprehensive might be more difficult.
88
		} else {
89
			$params += $this->buildProfileApiParam();
90
		}
91
92
		return $params;
93
	}
94
95
	/**
96
	 * Build the profile api param definitions. Makes bold assumption only one search
97
	 * engine is available, ensure that is true before calling.
98
	 *
99
	 * @return array array containing available additional api param definitions.
100
	 *  Empty if profiles are not supported by the searchEngine implementation.
101
	 */
102
	private function buildProfileApiParam() {
103
		$configs = $this->getSearchProfileParams();
104
		$searchEngine = MediaWikiServices::getInstance()->newSearchEngine();
105
		$params = [];
106
		foreach ( $configs as $paramName => $paramConfig ) {
107
			$profiles = $searchEngine->getProfiles( $paramConfig['profile-type'],
108
				$this->getContext()->getUser() );
109
			if ( !$profiles ) {
110
				continue;
111
			}
112
113
			$types = [];
114
			$helpMessages = [];
115
			$defaultProfile = null;
116
			foreach ( $profiles as $profile ) {
117
				$types[] = $profile['name'];
118
				if ( isset ( $profile['desc-message'] ) ) {
119
					$helpMessages[$profile['name']] = $profile['desc-message'];
120
				}
121
				if ( !empty( $profile['default'] ) ) {
122
					$defaultProfile = $profile['name'];
123
				}
124
			}
125
126
			$params[$paramName] = [
127
				ApiBase::PARAM_TYPE => $types,
128
				ApiBase::PARAM_HELP_MSG => $paramConfig['help-message'],
129
				ApiBase::PARAM_HELP_MSG_PER_VALUE => $helpMessages,
130
				ApiBase::PARAM_DFLT => $defaultProfile,
131
			];
132
		}
133
134
		return $params;
135
	}
136
137
	/**
138
	 * Build the search engine to use.
139
	 * If $params is provided then the following searchEngine options
140
	 * will be set:
141
	 *  - backend: which search backend to use
142
	 *  - limit: mandatory
143
	 *  - offset: optional, if set limit will be incremented by
144
	 *    one ( to support the continue parameter )
145
	 *  - namespace: mandatory
146
	 *  - search engine profiles defined by SearchApi::getSearchProfileParams()
147
	 * @param string[]|null API request params (must be sanitized by
148
	 * ApiBase::extractRequestParams() before)
149
	 * @return SearchEngine the search engine
150
	 */
151
	public function buildSearchEngine( array $params = null ) {
152
		if ( $params != null ) {
153
			$type = isset( $params['backend'] ) ? $params['backend'] : null;
154
			if ( $type === self::$BACKEND_NULL_PARAM ) {
155
				$type = null;
156
			}
157
			$searchEngine = MediaWikiServices::getInstance()->getSearchEngineFactory()->create( $type );
158
			$limit = $params['limit'];
159
			$searchEngine->setNamespaces( $params['namespace'] );
160
			$offset = null;
161
			if ( isset( $params['offset'] ) ) {
162
				// If the API supports offset then it probably
163
				// wants to fetch limit+1 so it can check if
164
				// more results are available to properly set
165
				// the continue param
166
				$offset = $params['offset'];
167
				$limit += 1;
168
			}
169
			$searchEngine->setLimitOffset( $limit, $offset );
170
171
			// Initialize requested search profiles.
172
			$configs = $this->getSearchProfileParams();
173
			foreach ( $configs as $paramName => $paramConfig ) {
174
				if ( isset( $params[$paramName] ) ) {
175
					$searchEngine->setFeatureData(
176
						$paramConfig['profile-type'],
177
						$params[$paramName]
178
					);
179
				}
180
			}
181
		} else {
182
			$searchEngine = MediaWikiServices::getInstance()->newSearchEngine();
183
		}
184
		return $searchEngine;
185
	}
186
187
	/**
188
	 * @return array[] array of arrays mapping from parameter name to a two value map
189
	 *  containing 'help-message' and 'profile-type' keys.
190
	 */
191
	abstract public function getSearchProfileParams();
192
193
	/**
194
	 * @return IContextSource
195
	 */
196
	abstract public function getContext();
197
}
198