1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace ApacheSolrForTypo3\Solr\Domain\Search\ResultSet; |
4
|
|
|
|
5
|
|
|
/*************************************************************** |
6
|
|
|
* Copyright notice |
7
|
|
|
* |
8
|
|
|
* (c) 2015-2016 Timo Schmidt <[email protected]> |
9
|
|
|
* All rights reserved |
10
|
|
|
* |
11
|
|
|
* This script is part of the TYPO3 project. The TYPO3 project is |
12
|
|
|
* free software; you can redistribute it and/or modify |
13
|
|
|
* it under the terms of the GNU General Public License as published by |
14
|
|
|
* the Free Software Foundation; either version 2 of the License, or |
15
|
|
|
* (at your option) any later version. |
16
|
|
|
* |
17
|
|
|
* The GNU General Public License can be found at |
18
|
|
|
* http://www.gnu.org/copyleft/gpl.html. |
19
|
|
|
* |
20
|
|
|
* This script is distributed in the hope that it will be useful, |
21
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
22
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23
|
|
|
* GNU General Public License for more details. |
24
|
|
|
* |
25
|
|
|
* This copyright notice MUST APPEAR in all copies of the script! |
26
|
|
|
***************************************************************/ |
27
|
|
|
|
28
|
|
|
use ApacheSolrForTypo3\Solr\Domain\Search\Query\ParameterBuilder\QueryFields; |
29
|
|
|
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Result\Parser\ResultParserRegistry; |
30
|
|
|
use ApacheSolrForTypo3\Solr\Domain\Search\SearchRequest; |
31
|
|
|
use ApacheSolrForTypo3\Solr\Domain\Search\SearchRequestAware; |
32
|
|
|
use ApacheSolrForTypo3\Solr\Domain\Variants\VariantsProcessor; |
33
|
|
|
use ApacheSolrForTypo3\Solr\Query; |
34
|
|
|
use ApacheSolrForTypo3\Solr\Query\Modifier\Modifier; |
35
|
|
|
use ApacheSolrForTypo3\Solr\Search; |
36
|
|
|
use ApacheSolrForTypo3\Solr\Search\QueryAware; |
37
|
|
|
use ApacheSolrForTypo3\Solr\Search\SearchAware; |
38
|
|
|
use ApacheSolrForTypo3\Solr\Search\SearchComponentManager; |
39
|
|
|
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration; |
40
|
|
|
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager; |
41
|
|
|
use ApacheSolrForTypo3\Solr\System\Solr\SolrCommunicationException; |
42
|
|
|
use ApacheSolrForTypo3\Solr\System\Solr\SolrIncompleteResponseException; |
43
|
|
|
use ApacheSolrForTypo3\Solr\System\Solr\SolrInternalServerErrorException; |
44
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
45
|
|
|
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* The SearchResultSetService is responsible to build a SearchResultSet from a SearchRequest. |
49
|
|
|
* It encapsulates the logic to trigger a search in order to be able to reuse it in multiple places. |
50
|
|
|
* |
51
|
|
|
* @author Timo Schmidt <[email protected]> |
52
|
|
|
*/ |
53
|
|
|
class SearchResultSetService |
54
|
|
|
{ |
55
|
|
|
/** |
56
|
|
|
* Additional filters, which will be added to the query, as well as to |
57
|
|
|
* suggest queries. |
58
|
|
|
* |
59
|
|
|
* @var array |
60
|
|
|
*/ |
61
|
|
|
protected $additionalFilters = []; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Track, if the number of results per page has been changed by the current request |
65
|
|
|
* |
66
|
|
|
* @var bool |
67
|
|
|
*/ |
68
|
|
|
protected $resultsPerPageChanged = false; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @var Search |
72
|
|
|
*/ |
73
|
|
|
protected $search; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @var SearchResultSet |
77
|
|
|
*/ |
78
|
|
|
protected $lastResultSet = null; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @var boolean |
82
|
|
|
*/ |
83
|
|
|
protected $isSolrAvailable = false; |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @var TypoScriptConfiguration |
87
|
|
|
*/ |
88
|
|
|
protected $typoScriptConfiguration; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @var SolrLogManager; |
92
|
|
|
*/ |
93
|
|
|
protected $logger = null; |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @var SearchResultBuilder |
97
|
|
|
*/ |
98
|
|
|
protected $searchResultBuilder; |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* @param TypoScriptConfiguration $configuration |
102
|
|
|
* @param Search $search |
103
|
|
|
* @param SolrLogManager $solrLogManager |
104
|
|
|
* @param SearchResultBuilder $resultBuilder |
105
|
47 |
|
*/ |
106
|
|
|
public function __construct(TypoScriptConfiguration $configuration, Search $search, SolrLogManager $solrLogManager = null, SearchResultBuilder $resultBuilder = null) |
107
|
47 |
|
{ |
108
|
47 |
|
$this->search = $search; |
109
|
47 |
|
$this->typoScriptConfiguration = $configuration; |
110
|
47 |
|
$this->logger = is_null($solrLogManager) ? GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__) : $solrLogManager; |
111
|
47 |
|
$this->searchResultBuilder = is_null($resultBuilder) ? GeneralUtility::makeInstance(SearchResultBuilder::class) : $resultBuilder; |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* @param bool $useCache |
116
|
|
|
* @return bool |
117
|
|
|
*/ |
118
|
|
|
public function getIsSolrAvailable($useCache = true) |
119
|
|
|
{ |
120
|
|
|
$this->isSolrAvailable = $this->search->ping($useCache); |
121
|
|
|
return $this->isSolrAvailable; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* @return bool |
126
|
30 |
|
*/ |
127
|
|
|
public function getHasSearched() |
128
|
30 |
|
{ |
129
|
|
|
return $this->search->hasSearched(); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Retrieves the used search instance. |
134
|
|
|
* |
135
|
|
|
* @return Search |
136
|
2 |
|
*/ |
137
|
|
|
public function getSearch() |
138
|
2 |
|
{ |
139
|
|
|
return $this->search; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Initializes the Query object and SearchComponents and returns |
144
|
|
|
* the initialized query object, when a search should be executed. |
145
|
|
|
* |
146
|
|
|
* @param string|null $rawQuery |
147
|
|
|
* @param int $resultsPerPage |
148
|
|
|
* @return Query |
149
|
38 |
|
*/ |
150
|
|
|
protected function getPreparedQuery($rawQuery, $resultsPerPage) |
151
|
|
|
{ |
152
|
38 |
|
/* @var $query Query */ |
153
|
|
|
$query = $this->getQueryInstance($rawQuery); |
154
|
38 |
|
|
155
|
|
|
$this->applyPageSectionsRootLineFilter($query); |
156
|
38 |
|
|
157
|
|
|
if ($this->typoScriptConfiguration->getLoggingQuerySearchWords()) { |
158
|
|
|
$this->logger->log( |
159
|
|
|
SolrLogManager::INFO, |
160
|
|
|
'Received search query', |
161
|
|
|
[ |
162
|
|
|
$rawQuery |
163
|
|
|
] |
164
|
|
|
); |
165
|
|
|
} |
166
|
38 |
|
|
167
|
|
|
$query->setResultsPerPage($resultsPerPage); |
168
|
38 |
|
|
169
|
|
|
if ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) { |
170
|
|
|
// empty main query, but using a "return everything" |
171
|
32 |
|
// alternative query in q.alt |
172
|
|
|
$query->setAlternativeQuery('*:*'); |
173
|
|
|
} |
174
|
38 |
|
|
175
|
3 |
|
if ($this->typoScriptConfiguration->getSearchInitializeWithQuery()) { |
176
|
|
|
$query->setAlternativeQuery($this->typoScriptConfiguration->getSearchInitializeWithQuery()); |
177
|
|
|
} |
178
|
38 |
|
|
179
|
2 |
|
foreach ($this->getAdditionalFilters() as $additionalFilter) { |
180
|
|
|
$query->getFilters()->add($additionalFilter); |
181
|
|
|
} |
182
|
38 |
|
|
183
|
|
|
return $query; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* @param Query $query |
188
|
|
|
* @param SearchRequest $searchRequest |
189
|
38 |
|
*/ |
190
|
|
|
protected function initializeRegisteredSearchComponents(Query $query, SearchRequest $searchRequest) |
191
|
38 |
|
{ |
192
|
|
|
$searchComponents = $this->getRegisteredSearchComponents(); |
193
|
38 |
|
|
194
|
|
|
foreach ($searchComponents as $searchComponent) { |
195
|
33 |
|
/** @var Search\SearchComponent $searchComponent */ |
196
|
|
|
$searchComponent->setSearchConfiguration($this->typoScriptConfiguration->getSearchConfiguration()); |
197
|
33 |
|
|
198
|
33 |
|
if ($searchComponent instanceof QueryAware) { |
199
|
|
|
$searchComponent->setQuery($query); |
200
|
|
|
} |
201
|
33 |
|
|
202
|
32 |
|
if ($searchComponent instanceof SearchRequestAware) { |
203
|
|
|
$searchComponent->setSearchRequest($searchRequest); |
204
|
|
|
} |
205
|
33 |
|
|
206
|
|
|
$searchComponent->initializeSearchComponent(); |
207
|
38 |
|
} |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* @return string |
212
|
|
|
*/ |
213
|
|
|
protected function getResultSetClassName() |
214
|
39 |
|
{ |
215
|
|
|
return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName ']) ? |
216
|
39 |
|
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName '] : SearchResultSet::class; |
217
|
39 |
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Initializes additional filters configured through TypoScript and |
221
|
|
|
* Flexforms for use in regular queries and suggest queries. |
222
|
|
|
* |
223
|
|
|
* @param Query $query |
224
|
|
|
* @return void |
225
|
|
|
*/ |
226
|
|
|
protected function applyPageSectionsRootLineFilter(Query $query) |
227
|
|
|
{ |
228
|
|
|
$searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration(); |
229
|
|
|
if (count($searchQueryFilters) <= 0) { |
230
|
|
|
return; |
231
|
39 |
|
} |
232
|
|
|
|
233
|
39 |
|
// special filter to limit search to specific page tree branches |
234
|
|
|
if (array_key_exists('__pageSections', $searchQueryFilters)) { |
235
|
39 |
|
$query->setRootlineFilter($searchQueryFilters['__pageSections']); |
236
|
4 |
|
$this->typoScriptConfiguration->removeSearchQueryFilterForPageSections(); |
237
|
|
|
} |
238
|
|
|
} |
239
|
35 |
|
|
240
|
35 |
|
/** |
241
|
29 |
|
* Retrieves the configuration filters from the TypoScript configuration, except the __pageSections filter. |
242
|
29 |
|
* |
243
|
|
|
* @return array |
244
|
|
|
*/ |
245
|
35 |
|
public function getAdditionalFilters() |
246
|
35 |
|
{ |
247
|
35 |
|
// when we've build the additionalFilter once, we could return them |
248
|
|
|
if (count($this->additionalFilters) > 0) { |
249
|
|
|
return $this->additionalFilters; |
250
|
|
|
} |
251
|
|
|
|
252
|
40 |
|
$searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration(); |
253
|
|
|
if (count($searchQueryFilters) <= 0) { |
254
|
40 |
|
return []; |
255
|
40 |
|
} |
256
|
|
|
|
257
|
|
|
$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class); |
258
|
|
|
|
259
|
|
|
// all other regular filters |
260
|
|
|
foreach ($searchQueryFilters as $filterKey => $filter) { |
261
|
|
|
// the __pageSections filter should not be handled as additional filter |
262
|
|
|
if ($filterKey === '__pageSections') { |
263
|
|
|
continue; |
264
|
|
|
} |
265
|
38 |
|
|
266
|
|
|
$filterIsArray = is_array($searchQueryFilters[$filterKey]); |
267
|
38 |
|
if ($filterIsArray) { |
268
|
38 |
|
continue; |
269
|
36 |
|
} |
270
|
|
|
|
271
|
|
|
$hasSubConfiguration = is_array($searchQueryFilters[$filterKey . '.']); |
272
|
|
|
if ($hasSubConfiguration) { |
273
|
2 |
|
$filter = $cObj->stdWrap($searchQueryFilters[$filterKey], $searchQueryFilters[$filterKey . '.']); |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
$this->additionalFilters[$filterKey] = $filter; |
277
|
2 |
|
} |
278
|
|
|
|
279
|
|
|
return $this->additionalFilters; |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
/** |
283
|
|
|
* Performs a search and returns a SearchResultSet. |
284
|
43 |
|
* |
285
|
|
|
* @param SearchRequest $searchRequest |
286
|
|
|
* @return SearchResultSet |
287
|
43 |
|
*/ |
288
|
2 |
|
public function search(SearchRequest $searchRequest) |
289
|
|
|
{ |
290
|
|
|
/** @var $resultSet SearchResultSet */ |
291
|
43 |
|
$resultSetClass = $this->getResultSetClassName(); |
292
|
43 |
|
$resultSet = GeneralUtility::makeInstance($resultSetClass); |
293
|
41 |
|
$resultSet->setUsedSearchRequest($searchRequest); |
294
|
|
|
$this->lastResultSet = $resultSet; |
295
|
|
|
|
296
|
2 |
|
$resultSet = $this->handleSearchHook('beforeSearch', $resultSet); |
297
|
|
|
|
298
|
|
|
if ($searchRequest->getRawUserQueryIsNull() && !$this->getInitialSearchIsConfigured()) { |
299
|
2 |
|
// when no rawQuery was passed or no initialSearch is configured, we pass an empty result set |
300
|
|
|
return $resultSet; |
301
|
2 |
|
} |
302
|
|
|
|
303
|
|
|
if ($searchRequest->getRawUserQueryIsEmptyString() && !$this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) { |
304
|
|
|
// the user entered an empty query string "" or " " and empty querystring is not allowed |
305
|
2 |
|
return $resultSet; |
306
|
2 |
|
} |
307
|
|
|
|
308
|
|
|
$rawQuery = $searchRequest->getRawUserQuery(); |
309
|
|
|
$resultsPerPage = (int)$searchRequest->getResultsPerPage(); |
310
|
2 |
|
$query = $this->getPreparedQuery($rawQuery, $resultsPerPage); |
311
|
2 |
|
$this->initializeRegisteredSearchComponents($query, $searchRequest); |
312
|
|
|
$resultSet->setUsedQuery($query); |
313
|
|
|
|
314
|
|
|
// the offset mulitplier is page - 1 but not less then zero |
315
|
2 |
|
$offsetMultiplier = max(0, $searchRequest->getPage() - 1); |
316
|
|
|
$offSet = $offsetMultiplier * $resultsPerPage; |
317
|
|
|
|
318
|
2 |
|
// performing the actual search, sending the query to the Solr server |
319
|
|
|
$query = $this->modifyQuery($query, $searchRequest, $this->search); |
320
|
|
|
$response = $this->doASearch($query, $offSet); |
321
|
|
|
|
322
|
|
|
if ($resultsPerPage === 0) { |
323
|
|
|
// when resultPerPage was forced to 0 we also set the numFound to 0 to hide results, e.g. |
324
|
|
|
// when results for the initial search should not be shown. |
325
|
|
|
$response->response->numFound = 0; |
|
|
|
|
326
|
|
|
} |
327
|
40 |
|
|
328
|
|
|
$resultSet->setUsedSearch($this->search); |
329
|
|
|
$resultSet->setResponse($response); |
330
|
40 |
|
|
331
|
40 |
|
/** @var ResultParserRegistry $parserRegistry */ |
332
|
40 |
|
$parserRegistry = GeneralUtility::makeInstance(ResultParserRegistry::class, $this->typoScriptConfiguration); |
333
|
40 |
|
$useRawDocuments = (bool)$this->typoScriptConfiguration->getValueByPathOrDefaultValue('plugin.tx_solr.features.useRawDocuments', false); |
334
|
|
|
$searchResults = $parserRegistry->getParser($resultSet)->parse($resultSet, $useRawDocuments); |
335
|
40 |
|
$resultSet->setSearchResults($searchResults); |
336
|
|
|
|
337
|
40 |
|
$resultSet->setUsedPage((int)$searchRequest->getPage()); |
338
|
|
|
$resultSet->setUsedResultsPerPage($resultsPerPage); |
339
|
2 |
|
$resultSet->setUsedAdditionalFilters($this->getAdditionalFilters()); |
340
|
|
|
|
341
|
|
|
/** @var $variantsProcessor VariantsProcessor */ |
342
|
38 |
|
$variantsProcessor = GeneralUtility::makeInstance(VariantsProcessor::class, $this->typoScriptConfiguration, $this->searchResultBuilder); |
343
|
|
|
$variantsProcessor->process($resultSet); |
344
|
|
|
|
345
|
|
|
/** @var $searchResultReconstitutionProcessor ResultSetReconstitutionProcessor */ |
346
|
|
|
$searchResultReconstitutionProcessor = GeneralUtility::makeInstance(ResultSetReconstitutionProcessor::class); |
347
|
38 |
|
$searchResultReconstitutionProcessor->process($resultSet); |
348
|
38 |
|
|
349
|
38 |
|
$resultSet = $this->getAutoCorrection($resultSet); |
350
|
38 |
|
|
351
|
38 |
|
return $this->handleSearchHook('afterSearch', $resultSet); |
352
|
|
|
} |
353
|
|
|
|
354
|
38 |
|
/** |
355
|
38 |
|
* Executes the search and builds a fake response for a current bug in Apache Solr 6.3 |
356
|
|
|
* |
357
|
|
|
* @param Query $query |
358
|
38 |
|
* @param int $offSet |
359
|
38 |
|
* @return \Apache_Solr_Response |
360
|
|
|
*/ |
361
|
37 |
|
protected function doASearch($query, $offSet) |
362
|
|
|
{ |
363
|
|
|
$response = $this->search->search($query, $offSet, null); |
364
|
2 |
|
if($response === null) { |
365
|
|
|
throw new SolrIncompleteResponseException('The response retrieved from solr was incomplete', 1505989678); |
366
|
|
|
} |
367
|
37 |
|
|
368
|
37 |
|
return $response; |
369
|
|
|
} |
370
|
37 |
|
|
371
|
37 |
|
/** |
372
|
37 |
|
* @param SearchResultSet $searchResultSet |
373
|
37 |
|
* @return SearchResultSet |
374
|
37 |
|
*/ |
375
|
|
|
protected function getAutoCorrection(SearchResultSet $searchResultSet) |
376
|
|
|
{ |
377
|
37 |
|
// no secondary search configured |
378
|
37 |
|
if (!$this->typoScriptConfiguration->getSearchSpellcheckingSearchUsingSpellCheckerSuggestion()) { |
379
|
|
|
return $searchResultSet; |
380
|
|
|
} |
381
|
37 |
|
|
382
|
37 |
|
// more then zero results |
383
|
|
|
if ($searchResultSet->getAllResultCount() > 0) { |
384
|
37 |
|
return $searchResultSet; |
385
|
|
|
} |
386
|
37 |
|
|
387
|
|
|
// no corrections present |
388
|
|
|
if (!$searchResultSet->getHasSpellCheckingSuggestions()) { |
389
|
|
|
return $searchResultSet; |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
$searchResultSet = $this->peformAutoCorrection($searchResultSet); |
393
|
|
|
|
394
|
|
|
return $searchResultSet; |
395
|
|
|
} |
396
|
|
|
|
397
|
38 |
|
/** |
398
|
|
|
* @param SearchResultSet $searchResultSet |
399
|
|
|
* @return SearchResultSet |
400
|
38 |
|
*/ |
401
|
2 |
|
protected function peformAutoCorrection(SearchResultSet $searchResultSet) |
402
|
|
|
{ |
403
|
|
|
$searchRequest = $searchResultSet->getUsedSearchRequest(); |
404
|
|
|
$suggestions = $searchResultSet->getSpellCheckingSuggestions(); |
405
|
|
|
|
406
|
1 |
|
$maximumRuns = $this->typoScriptConfiguration->getSearchSpellcheckingNumberOfSuggestionsToTry(1); |
407
|
|
|
$runs = 0; |
408
|
|
|
|
409
|
|
|
foreach ($suggestions as $suggestion) { |
410
|
1 |
|
$runs++; |
411
|
|
|
|
412
|
1 |
|
$correction = $suggestion->getSuggestion(); |
413
|
1 |
|
$initialQuery = $searchRequest->getRawUserQuery(); |
414
|
1 |
|
|
415
|
1 |
|
$searchRequest->setRawQueryString($correction); |
416
|
1 |
|
$searchResultSet = $this->search($searchRequest); |
417
|
1 |
|
if ($searchResultSet->getAllResultCount() > 0) { |
418
|
1 |
|
$searchResultSet->setIsAutoCorrected(true); |
419
|
1 |
|
$searchResultSet->setCorrectedQueryString($correction); |
420
|
1 |
|
$searchResultSet->setInitialQueryString($initialQuery); |
421
|
|
|
break; |
422
|
|
|
} |
423
|
|
|
|
424
|
37 |
|
if ($runs > $maximumRuns) { |
425
|
|
|
break; |
426
|
|
|
} |
427
|
|
|
} |
428
|
37 |
|
return $searchResultSet; |
429
|
|
|
} |
430
|
|
|
|
431
|
|
|
/** |
432
|
|
|
* Allows to modify a query before eventually handing it over to Solr. |
433
|
|
|
* |
434
|
|
|
* @param Query $query The current query before it's being handed over to Solr. |
435
|
37 |
|
* @param SearchRequest $searchRequest The searchRequest, relevant in the current context |
436
|
|
|
* @param Search $search The search, relevant in the current context |
437
|
|
|
* @throws \UnexpectedValueException |
438
|
37 |
|
* @return Query The modified query that is actually going to be given to Solr. |
439
|
36 |
|
*/ |
440
|
|
|
protected function modifyQuery(Query $query, SearchRequest $searchRequest, Search $search) |
441
|
|
|
{ |
442
|
|
|
// hook to modify the search query |
443
|
1 |
|
if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifySearchQuery'])) { |
444
|
1 |
|
foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifySearchQuery'] as $classReference) { |
445
|
|
|
$queryModifier = GeneralUtility::getUserObj($classReference); |
446
|
|
|
|
447
|
|
|
if ($queryModifier instanceof Modifier) { |
448
|
1 |
|
if ($queryModifier instanceof SearchAware) { |
449
|
|
|
$queryModifier->setSearch($search); |
450
|
|
|
} |
451
|
|
|
|
452
|
1 |
|
if ($queryModifier instanceof SearchRequestAware) { |
453
|
|
|
$queryModifier->setSearchRequest($searchRequest); |
454
|
1 |
|
} |
455
|
|
|
|
456
|
|
|
$query = $queryModifier->modifyQuery($query); |
457
|
|
|
} else { |
458
|
|
|
throw new \UnexpectedValueException( |
459
|
|
|
get_class($queryModifier) . ' must implement interface ' . Modifier::class, |
460
|
|
|
1310387414 |
461
|
1 |
|
); |
462
|
|
|
} |
463
|
1 |
|
} |
464
|
1 |
|
} |
465
|
|
|
|
466
|
1 |
|
return $query; |
467
|
1 |
|
} |
468
|
|
|
|
469
|
1 |
|
/** |
470
|
1 |
|
* Retrieves a single document from solr by document id. |
471
|
|
|
* |
472
|
1 |
|
* @param string $documentId |
473
|
1 |
|
* @return SearchResult |
474
|
|
|
*/ |
475
|
1 |
|
public function getDocumentById($documentId) |
476
|
1 |
|
{ |
477
|
1 |
|
/* @var $query Query */ |
478
|
1 |
|
$query = GeneralUtility::makeInstance(Query::class, $documentId); |
479
|
1 |
|
$query->setQueryFields(QueryFields::fromString('id')); |
480
|
1 |
|
$response = $this->search->search($query, 0, 1); |
481
|
1 |
|
$parsedData = $response->getParsedData(); |
482
|
|
|
$resultDocument = isset($parsedData->response->docs[0]) ? $parsedData->response->docs[0] : null; |
483
|
|
|
|
484
|
|
|
return $this->searchResultBuilder->fromApacheSolrDocument($resultDocument); |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
/** |
488
|
1 |
|
* This method is used to call the registered hooks during the search execution. |
489
|
|
|
* |
490
|
|
|
* @param string $eventName |
491
|
|
|
* @param SearchResultSet $resultSet |
492
|
|
|
* @return SearchResultSet |
493
|
|
|
*/ |
494
|
|
|
private function handleSearchHook($eventName, SearchResultSet $resultSet) |
495
|
|
|
{ |
496
|
|
|
if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName])) { |
497
|
|
|
return $resultSet; |
498
|
|
|
} |
499
|
|
|
|
500
|
38 |
|
foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName] as $classReference) { |
501
|
|
|
$afterSearchProcessor = GeneralUtility::getUserObj($classReference); |
502
|
|
|
if ($afterSearchProcessor instanceof SearchResultSetProcessor) { |
503
|
38 |
|
$afterSearchProcessor->process($resultSet); |
504
|
32 |
|
} |
505
|
32 |
|
} |
506
|
|
|
|
507
|
32 |
|
return $resultSet; |
508
|
32 |
|
} |
509
|
|
|
|
510
|
|
|
/** |
511
|
|
|
* @return SearchResultSet |
512
|
32 |
|
*/ |
513
|
32 |
|
public function getLastResultSet() |
514
|
|
|
{ |
515
|
|
|
return $this->lastResultSet; |
516
|
32 |
|
} |
517
|
|
|
|
518
|
|
|
/** |
519
|
|
|
* This method returns true when the last search was executed with an empty query |
520
|
32 |
|
* string or whitespaces only. When no search was triggered it will return false. |
521
|
|
|
* |
522
|
|
|
* @return bool |
523
|
|
|
*/ |
524
|
|
|
public function getLastSearchWasExecutedWithEmptyQueryString() |
525
|
|
|
{ |
526
|
38 |
|
$wasEmptyQueryString = false; |
527
|
|
|
if ($this->lastResultSet != null) { |
528
|
|
|
$wasEmptyQueryString = $this->lastResultSet->getUsedSearchRequest()->getRawUserQueryIsEmptyString(); |
529
|
|
|
} |
530
|
|
|
|
531
|
|
|
return $wasEmptyQueryString; |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
/** |
535
|
3 |
|
* @return bool |
536
|
|
|
*/ |
537
|
|
|
protected function getInitialSearchIsConfigured() |
538
|
3 |
|
{ |
539
|
3 |
|
return $this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialEmptyQuery() || $this->typoScriptConfiguration->getSearchInitializeWithQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialQuery(); |
540
|
|
|
} |
541
|
3 |
|
|
542
|
2 |
|
/** |
543
|
|
|
* @return mixed |
544
|
2 |
|
*/ |
545
|
2 |
|
protected function getRegisteredSearchComponents() |
546
|
2 |
|
{ |
547
|
|
|
return GeneralUtility::makeInstance(SearchComponentManager::class)->getSearchComponents(); |
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
/** |
551
|
|
|
* @param string $rawQuery |
552
|
|
|
* @return Query|object |
553
|
|
|
*/ |
554
|
|
|
protected function getQueryInstance($rawQuery) |
555
|
|
|
{ |
556
|
40 |
|
$query = GeneralUtility::makeInstance(Query::class, $rawQuery, $this->typoScriptConfiguration); |
557
|
|
|
return $query; |
558
|
40 |
|
} |
559
|
|
|
} |
560
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.