Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
98.28% |
57 / 58 |
|
95.45% |
21 / 22 |
CRAP | |
0.00% |
0 / 1 |
SearchQuery | |
98.28% |
57 / 58 |
|
95.45% |
21 / 22 |
31 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
1 | |||
getDebugOptions | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getParsedQuery | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getInitialNamespaces | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getInitialCrossSearchStrategy | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCrossSearchStrategy | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
getContextualFilters | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getSearchEngineEntryPoint | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getSort | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getRandomSeed | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getForcedProfiles | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getOffset | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getLimit | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getNamespaces | |
93.33% |
14 / 15 |
|
0.00% |
0 / 1 |
8.02 | |||
getSearchConfig | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getForcedProfile | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasForcedProfile | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isWithDYMSuggestion | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isAllowRewrite | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getProfileContextParameters | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getExtraFieldsToExtract | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
shouldProvideAllSnippets | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace CirrusSearch\Search; |
4 | |
5 | use CirrusSearch\CirrusDebugOptions; |
6 | use CirrusSearch\CrossSearchStrategy; |
7 | use CirrusSearch\Parser\AST\ParsedQuery; |
8 | use CirrusSearch\SearchConfig; |
9 | |
10 | /** |
11 | * A search query, it contains all the necessary information to build and send a query to the backend. |
12 | * NOTE: Immutable value class. |
13 | */ |
14 | class SearchQuery { |
15 | /** |
16 | * Identifier for the fulltext SearchEngine entry point |
17 | * @see \SearchEngine::searchText() |
18 | */ |
19 | public const SEARCH_TEXT = 'searchText'; |
20 | |
21 | /** |
22 | * @var ParsedQuery |
23 | */ |
24 | private $parsedQuery; |
25 | |
26 | /** |
27 | * @var int[] |
28 | */ |
29 | private $initialNamespaces; |
30 | |
31 | /** |
32 | * @var CrossSearchStrategy |
33 | */ |
34 | private $initialCrossSearchStrategy; |
35 | |
36 | /** |
37 | * @var CrossSearchStrategy|null (lazy loaded) |
38 | */ |
39 | private $crossSearchStrategy; |
40 | |
41 | /** |
42 | * @var \CirrusSearch\Query\Builder\ContextualFilter[] |
43 | */ |
44 | private $contextualFilters; |
45 | |
46 | /** |
47 | * Entry point from the SearchEngine |
48 | * TODO: clarify its usage and see whether or not another |
49 | * entry point var is needed to carry some provenance information |
50 | * from the UI. |
51 | * @var string |
52 | */ |
53 | private $searchEngineEntryPoint; |
54 | |
55 | /** |
56 | * @var string |
57 | */ |
58 | private $sort; |
59 | |
60 | /** |
61 | * @var int|null |
62 | */ |
63 | private $randomSeed; |
64 | |
65 | /** |
66 | * @var string[] |
67 | */ |
68 | private $forcedProfiles; |
69 | |
70 | /** |
71 | * @var int |
72 | */ |
73 | private $offset; |
74 | |
75 | /** |
76 | * @var int |
77 | */ |
78 | private $limit; |
79 | |
80 | /** |
81 | * @var CirrusDebugOptions |
82 | */ |
83 | private $debugOptions; |
84 | |
85 | /** |
86 | * @var SearchConfig |
87 | */ |
88 | private $searchConfig; |
89 | |
90 | /** |
91 | * @var bool |
92 | */ |
93 | private $withDYMSuggestion; |
94 | |
95 | /** |
96 | * @var bool |
97 | */ |
98 | private $allowRewrite; |
99 | |
100 | /** |
101 | * @var string[] parameters for SearchProfileService |
102 | * @see \CirrusSearch\Profile\ContextualProfileOverride |
103 | */ |
104 | private $profileContextParameters; |
105 | |
106 | /** |
107 | * @var string[] list of extra fields to extract |
108 | */ |
109 | private $extraFieldsToExtract; |
110 | |
111 | /** |
112 | * @var bool |
113 | */ |
114 | private $provideAllSnippets; |
115 | |
116 | /** |
117 | * @param ParsedQuery $parsedQuery |
118 | * @param int[] $initialNamespaces |
119 | * @param CrossSearchStrategy $initialCrosswikiStrategy |
120 | * @param \CirrusSearch\Query\Builder\ContextualFilter[] $contextualFilters |
121 | * @param string $searchEngineEntryPoint |
122 | * @param string $sort |
123 | * @param int|null $randomSeed |
124 | * @param string[] $forcedProfiles |
125 | * @param int $offset |
126 | * @param int $limit |
127 | * @param CirrusDebugOptions $debugOptions |
128 | * @param SearchConfig $searchConfig |
129 | * @param bool $withDYMSuggestion |
130 | * @param bool $allowRewrite |
131 | * @param string[] $profileContextParameters |
132 | * @param string[] $extraFieldsToExtract |
133 | * @param bool $provideAllSnippets |
134 | * @see SearchQueryBuilder |
135 | */ |
136 | public function __construct( |
137 | ParsedQuery $parsedQuery, |
138 | array $initialNamespaces, |
139 | CrossSearchStrategy $initialCrosswikiStrategy, |
140 | array $contextualFilters, |
141 | $searchEngineEntryPoint, |
142 | $sort, |
143 | $randomSeed, |
144 | array $forcedProfiles, |
145 | $offset, |
146 | $limit, |
147 | CirrusDebugOptions $debugOptions, |
148 | SearchConfig $searchConfig, |
149 | $withDYMSuggestion, |
150 | $allowRewrite, |
151 | array $profileContextParameters, |
152 | array $extraFieldsToExtract, |
153 | bool $provideAllSnippets |
154 | ) { |
155 | $this->parsedQuery = $parsedQuery; |
156 | $this->initialNamespaces = $initialNamespaces; |
157 | $this->initialCrossSearchStrategy = $initialCrosswikiStrategy; |
158 | $this->contextualFilters = $contextualFilters; |
159 | $this->searchEngineEntryPoint = $searchEngineEntryPoint; |
160 | $this->sort = $sort; |
161 | $this->randomSeed = $randomSeed; |
162 | $this->forcedProfiles = $forcedProfiles; |
163 | $this->offset = $offset; |
164 | $this->limit = $limit; |
165 | $this->debugOptions = $debugOptions; |
166 | $this->searchConfig = $searchConfig; |
167 | $this->withDYMSuggestion = $withDYMSuggestion; |
168 | $this->allowRewrite = $allowRewrite; |
169 | $this->profileContextParameters = $profileContextParameters; |
170 | $this->extraFieldsToExtract = $extraFieldsToExtract; |
171 | $this->provideAllSnippets = $provideAllSnippets; |
172 | } |
173 | |
174 | /** |
175 | * @return CirrusDebugOptions |
176 | */ |
177 | public function getDebugOptions(): CirrusDebugOptions { |
178 | return $this->debugOptions; |
179 | } |
180 | |
181 | /** |
182 | * @return ParsedQuery |
183 | */ |
184 | public function getParsedQuery(): ParsedQuery { |
185 | return $this->parsedQuery; |
186 | } |
187 | |
188 | /** |
189 | * @return int[] |
190 | */ |
191 | public function getInitialNamespaces() { |
192 | return $this->initialNamespaces; |
193 | } |
194 | |
195 | /** |
196 | * @return CrossSearchStrategy |
197 | */ |
198 | public function getInitialCrossSearchStrategy(): CrossSearchStrategy { |
199 | return $this->initialCrossSearchStrategy; |
200 | } |
201 | |
202 | /** |
203 | * @return CrossSearchStrategy |
204 | */ |
205 | public function getCrossSearchStrategy(): CrossSearchStrategy { |
206 | if ( $this->crossSearchStrategy === null ) { |
207 | if ( $this->contextualFilters !== [] ) { |
208 | $this->crossSearchStrategy = CrossSearchStrategy::hostWikiOnlyStrategy(); |
209 | } else { |
210 | $this->crossSearchStrategy = $this->parsedQuery |
211 | ->getCrossSearchStrategy() |
212 | ->intersect( $this->initialCrossSearchStrategy ); |
213 | } |
214 | } |
215 | return $this->crossSearchStrategy; |
216 | } |
217 | |
218 | /** |
219 | * @return \CirrusSearch\Query\Builder\ContextualFilter[] |
220 | */ |
221 | public function getContextualFilters(): array { |
222 | return $this->contextualFilters; |
223 | } |
224 | |
225 | /** |
226 | * From which SearchEngine method this query entered CirrusSearch |
227 | * @return string |
228 | */ |
229 | public function getSearchEngineEntryPoint() { |
230 | return $this->searchEngineEntryPoint; |
231 | } |
232 | |
233 | /** |
234 | * @return string |
235 | */ |
236 | public function getSort() { |
237 | return $this->sort; |
238 | } |
239 | |
240 | /** |
241 | * @return int|null |
242 | */ |
243 | public function getRandomSeed(): ?int { |
244 | return $this->randomSeed; |
245 | } |
246 | |
247 | /** |
248 | * @return string[] |
249 | */ |
250 | public function getForcedProfiles(): array { |
251 | return $this->forcedProfiles; |
252 | } |
253 | |
254 | /** |
255 | * @return int |
256 | */ |
257 | public function getOffset() { |
258 | return $this->offset; |
259 | } |
260 | |
261 | /** |
262 | * @return int |
263 | */ |
264 | public function getLimit() { |
265 | return $this->limit; |
266 | } |
267 | |
268 | /** |
269 | * List of namespaces required to run this query. |
270 | * |
271 | * @return int[] list of namespaces, empty array means that all namespaces |
272 | * are required. |
273 | */ |
274 | public function getNamespaces(): array { |
275 | $additionalRequired = null; |
276 | if ( $this->initialNamespaces != [] && $this->contextualFilters != [] ) { |
277 | foreach ( $this->contextualFilters as $filter ) { |
278 | $additional = $filter->requiredNamespaces(); |
279 | if ( $additional === null ) { |
280 | continue; |
281 | } |
282 | if ( $additional === [] ) { |
283 | $additionalRequired = []; |
284 | break; |
285 | } |
286 | if ( $additionalRequired === null ) { |
287 | $additionalRequired = $additional; |
288 | } else { |
289 | $additionalRequired = array_merge( $additionalRequired, $additional ); |
290 | } |
291 | } |
292 | if ( $additionalRequired !== null ) { |
293 | $additionalRequired = array_unique( $additionalRequired ); |
294 | } |
295 | } |
296 | return $this->parsedQuery->getActualNamespaces( $this->initialNamespaces, $additionalRequired ); |
297 | } |
298 | |
299 | /** |
300 | * @return SearchConfig |
301 | */ |
302 | public function getSearchConfig(): SearchConfig { |
303 | return $this->searchConfig; |
304 | } |
305 | |
306 | /** |
307 | * @param string $profileType |
308 | * @see \CirrusSearch\Profile\SearchProfileService |
309 | * @return string|null name of the profile or null if nothing forced for this type |
310 | */ |
311 | public function getForcedProfile( $profileType ) { |
312 | return $this->forcedProfiles[$profileType] ?? null; |
313 | } |
314 | |
315 | /** |
316 | * @return bool |
317 | */ |
318 | public function hasForcedProfile() { |
319 | return $this->forcedProfiles !== []; |
320 | } |
321 | |
322 | /** |
323 | * @return bool |
324 | */ |
325 | public function isWithDYMSuggestion() { |
326 | return $this->withDYMSuggestion; |
327 | } |
328 | |
329 | /** |
330 | * @return bool |
331 | */ |
332 | public function isAllowRewrite() { |
333 | return $this->allowRewrite; |
334 | } |
335 | |
336 | /** |
337 | * @return string[] |
338 | * @see \CirrusSearch\Profile\ContextualProfileOverride |
339 | */ |
340 | public function getProfileContextParameters() { |
341 | return $this->profileContextParameters; |
342 | } |
343 | |
344 | /** |
345 | * @return string[] |
346 | * @see \CirrusSearch\Search\FullTextResultsType |
347 | */ |
348 | public function getExtraFieldsToExtract(): array { |
349 | return $this->extraFieldsToExtract; |
350 | } |
351 | |
352 | /** |
353 | * @return bool |
354 | */ |
355 | public function shouldProvideAllSnippets(): bool { |
356 | return $this->provideAllSnippets; |
357 | } |
358 | } |