Failed Conditions
Push — master ( a052b2...ee9c7d )
by Rafael
18:58
created

SearchResultSetService   F

Complexity

Total Complexity 74

Size/Duplication

Total Lines 589
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 18

Test Coverage

Coverage 87.79%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 74
lcom 1
cbo 18
dl 0
loc 589
ccs 187
cts 213
cp 0.8779
rs 2.3809
c 1
b 0
f 0

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 3
A getIsSolrAvailable() 0 5 1
A getHasSearched() 0 4 1
A getSearch() 0 4 1
B getPreparedQuery() 0 35 6
A initializeRegisteredSearchComponents() 0 19 4
A processResponse() 0 4 1
A wrapResultDocumentInResultObject() 0 17 3
A getResultSetClassName() 0 5 2
A applyPageSectionsRootLineFilter() 0 13 3
C getAdditionalFilters() 0 36 7
B search() 0 61 6
B doASearch() 0 33 4
A getAutoCorrection() 0 21 4
B peformAutoCorrection() 0 29 4
B modifyQuery() 0 28 6
A getDocumentById() 0 13 2
A handleSearchHook() 0 15 4
A getLastResultSet() 0 4 1
A getLastSearchWasExecutedWithEmptyQueryString() 0 9 2
A getInitialSearchIsConfigured() 0 4 4
A getRegisteredSearchComponents() 0 4 1
A addSearchResultsToResultSet() 0 11 3
A getQueryInstance() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like SearchResultSetService often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SearchResultSetService, and based on these observations, apply Extract Interface, too.

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\SearchRequest;
30
use ApacheSolrForTypo3\Solr\Domain\Search\SearchRequestAware;
31
use ApacheSolrForTypo3\Solr\Domain\Variants\VariantsProcessor;
32
use ApacheSolrForTypo3\Solr\Query;
33
use ApacheSolrForTypo3\Solr\Query\Modifier\Modifier;
34
use ApacheSolrForTypo3\Solr\Search;
35
use ApacheSolrForTypo3\Solr\Search\QueryAware;
36
use ApacheSolrForTypo3\Solr\Search\SearchAware;
37
use ApacheSolrForTypo3\Solr\Search\SearchComponentManager;
38
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration;
39
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
40
use ApacheSolrForTypo3\Solr\System\Solr\SolrCommunicationException;
41
use ApacheSolrForTypo3\Solr\System\Solr\SolrIncompleteResponseException;
42
use ApacheSolrForTypo3\Solr\System\Solr\SolrInternalServerErrorException;
43
use TYPO3\CMS\Core\Utility\GeneralUtility;
44
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
45
46
/**
47
 * The SearchResultSetService is responsible to build a SearchResultSet from a SearchRequest.
48
 * It encapsulates the logic to trigger a search in order to be able to reuse it in multiple places.
49
 *
50
 * @author Timo Schmidt <[email protected]>
51
 */
52
class SearchResultSetService
53
{
54
    /**
55
     * Additional filters, which will be added to the query, as well as to
56
     * suggest queries.
57
     *
58
     * @var array
59
     */
60
    protected $additionalFilters = [];
61
62
    /**
63
     * Track, if the number of results per page has been changed by the current request
64
     *
65
     * @var bool
66
     */
67
    protected $resultsPerPageChanged = false;
68
69
    /**
70
     * @var Search
71
     */
72
    protected $search;
73
74
    /**
75
     * @var SearchResultSet
76
     */
77
    protected $lastResultSet = null;
78
79
    /**
80
     * @var boolean
81
     */
82
    protected $isSolrAvailable = false;
83
84
    /**
85
     * @var TypoScriptConfiguration
86
     */
87
    protected $typoScriptConfiguration;
88
89
    /**
90
     * @var SolrLogManager;
91
     */
92
    protected $logger = null;
93
94
    /**
95
     * @var SearchResultBuilder
96
     */
97
    protected $searchResultBuilder;
98
99
    /**
100
     * @param TypoScriptConfiguration $configuration
101
     * @param Search $search
102
     * @param SolrLogManager $solrLogManager
103
     * @param SearchResultBuilder $resultBuilder
104
     */
105 47
    public function __construct(TypoScriptConfiguration $configuration, Search $search, SolrLogManager $solrLogManager = null, SearchResultBuilder $resultBuilder = null)
106
    {
107 47
        $this->search = $search;
108 47
        $this->typoScriptConfiguration = $configuration;
109 47
        $this->logger = is_null($solrLogManager) ? GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__) : $solrLogManager;
110 47
        $this->searchResultBuilder = is_null($resultBuilder) ? GeneralUtility::makeInstance(SearchResultBuilder::class) : $resultBuilder;
111 47
    }
112
113
    /**
114
     * @param bool $useCache
115
     * @return bool
116
     */
117
    public function getIsSolrAvailable($useCache = true)
118
    {
119
        $this->isSolrAvailable = $this->search->ping($useCache);
120
        return $this->isSolrAvailable;
121
    }
122
123
    /**
124
     * @return bool
125
     */
126 30
    public function getHasSearched()
127
    {
128 30
        return $this->search->hasSearched();
129
    }
130
131
    /**
132
     * Retrieves the used search instance.
133
     *
134
     * @return Search
135
     */
136 2
    public function getSearch()
137
    {
138 2
        return $this->search;
139
    }
140
141
    /**
142
     * Initializes the Query object and SearchComponents and returns
143
     * the initialized query object, when a search should be executed.
144
     *
145
     * @param string|null $rawQuery
146
     * @param int $resultsPerPage
147
     * @return Query
148
     */
149 38
    protected function getPreparedQuery($rawQuery, $resultsPerPage)
150
    {
151
        /* @var $query Query */
152 38
        $query = $this->getQueryInstance($rawQuery);
153
154 38
        $this->applyPageSectionsRootLineFilter($query);
155
156 38
        if ($this->typoScriptConfiguration->getLoggingQuerySearchWords()) {
157
            $this->logger->log(
158
                SolrLogManager::INFO,
159
                'Received search query',
160
                [
161
                    $rawQuery
162
                ]
163
            );
164
        }
165
166 38
        $query->setResultsPerPage($resultsPerPage);
167
168 38
        if ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
169
            // empty main query, but using a "return everything"
170
            // alternative query in q.alt
171 32
            $query->setAlternativeQuery('*:*');
172
        }
173
174 38
        if ($this->typoScriptConfiguration->getSearchInitializeWithQuery()) {
175 3
            $query->setAlternativeQuery($this->typoScriptConfiguration->getSearchInitializeWithQuery());
176
        }
177
178 38
        foreach ($this->getAdditionalFilters() as $additionalFilter) {
179 2
            $query->getFilters()->add($additionalFilter);
180
        }
181
182 38
        return $query;
183
    }
184
185
    /**
186
     * @param Query $query
187
     * @param SearchRequest $searchRequest
188
     */
189 38
    protected function initializeRegisteredSearchComponents(Query $query, SearchRequest $searchRequest)
190
    {
191 38
        $searchComponents = $this->getRegisteredSearchComponents();
192
193 38
        foreach ($searchComponents as $searchComponent) {
194
            /** @var Search\SearchComponent $searchComponent */
195 33
            $searchComponent->setSearchConfiguration($this->typoScriptConfiguration->getSearchConfiguration());
196
197 33
            if ($searchComponent instanceof QueryAware) {
198 33
                $searchComponent->setQuery($query);
199
            }
200
201 33
            if ($searchComponent instanceof SearchRequestAware) {
202 32
                $searchComponent->setSearchRequest($searchRequest);
203
            }
204
205 33
            $searchComponent->initializeSearchComponent();
206
        }
207 38
    }
208
209
    /**
210
     * Does post processing of the response.
211
     *
212
     * @param \Apache_Solr_Response $response The search's response.
213
     */
214 39
    protected function processResponse(\Apache_Solr_Response $response)
215
    {
216 39
        $this->wrapResultDocumentInResultObject($response);
217 39
    }
218
219
    /**
220
     * Wrap all results document it a custom EXT:solr SearchResult object.
221
     *
222
     * Can be overwritten:
223
     *
224
     * $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultClassName '] = ''
225
     *
226
     * to use a custom result object.
227
     *
228
     * @param \Apache_Solr_Response $response
229
     * @throws \Apache_Solr_ParserException
230
     */
231 39
    protected function wrapResultDocumentInResultObject(\Apache_Solr_Response $response)
232
    {
233 39
        $parsedData = $response->getParsedData();
234
235 39
        if (!is_array($parsedData->response->docs)) {
236 4
            return;
237
        }
238
239 35
        $documents = $parsedData->response->docs;
240 35
        foreach ($documents as $key => $originalDocument) {
241 29
            $result = $this->searchResultBuilder->fromApacheSolrDocument($originalDocument);
242 29
            $documents[$key] = $result;
243
        }
244
245 35
        $parsedData->response->docs = $documents;
246 35
        $response->setParsedData($parsedData);
247 35
    }
248
249
    /**
250
     * @return string
251
     */
252 40
    protected function getResultSetClassName()
253
    {
254 40
        return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName ']) ?
255 40
            $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName '] : SearchResultSet::class;
256
    }
257
258
    /**
259
     * Initializes additional filters configured through TypoScript and
260
     * Flexforms for use in regular queries and suggest queries.
261
     *
262
     * @param Query $query
263
     * @return void
264
     */
265 38
    protected function applyPageSectionsRootLineFilter(Query $query)
266
    {
267 38
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
268 38
        if (count($searchQueryFilters) <= 0) {
269 36
            return;
270
        }
271
272
        // special filter to limit search to specific page tree branches
273 2
        if (array_key_exists('__pageSections', $searchQueryFilters)) {
274
            $query->setRootlineFilter($searchQueryFilters['__pageSections']);
275
            $this->typoScriptConfiguration->removeSearchQueryFilterForPageSections();
276
        }
277 2
    }
278
279
    /**
280
     * Retrieves the configuration filters from the TypoScript configuration, except the __pageSections filter.
281
     *
282
     * @return array
283
     */
284 43
    public function getAdditionalFilters()
285
    {
286
        // when we've build the additionalFilter once, we could return them
287 43
        if (count($this->additionalFilters) > 0) {
288 2
            return $this->additionalFilters;
289
        }
290
291 43
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
292 43
        if (count($searchQueryFilters) <= 0) {
293 41
            return [];
294
        }
295
296 2
        $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
297
298
        // all other regular filters
299 2
        foreach ($searchQueryFilters as $filterKey => $filter) {
300
            // the __pageSections filter should not be handled as additional filter
301 2
            if ($filterKey === '__pageSections') {
302
                continue;
303
            }
304
305 2
            $filterIsArray = is_array($searchQueryFilters[$filterKey]);
306 2
            if ($filterIsArray) {
307
                continue;
308
            }
309
310 2
            $hasSubConfiguration = is_array($searchQueryFilters[$filterKey . '.']);
311 2
            if ($hasSubConfiguration) {
312
                $filter = $cObj->stdWrap($searchQueryFilters[$filterKey], $searchQueryFilters[$filterKey . '.']);
313
            }
314
315 2
            $this->additionalFilters[$filterKey] = $filter;
316
        }
317
318 2
        return $this->additionalFilters;
319
    }
320
321
    /**
322
     * Performs a search and returns a SearchResultSet.
323
     *
324
     * @param SearchRequest $searchRequest
325
     * @return SearchResultSet
326
     */
327 40
    public function search(SearchRequest $searchRequest)
328
    {
329
        /** @var $resultSet SearchResultSet */
330 40
        $resultSetClass = $this->getResultSetClassName();
331 40
        $resultSet = GeneralUtility::makeInstance($resultSetClass);
332 40
        $resultSet->setUsedSearchRequest($searchRequest);
333 40
        $this->lastResultSet = $resultSet;
334
335 40
        $resultSet = $this->handleSearchHook('beforeSearch', $resultSet);
336
337 40
        if ($searchRequest->getRawUserQueryIsNull() && !$this->getInitialSearchIsConfigured()) {
338
            // when no rawQuery was passed or no initialSearch is configured, we pass an empty result set
339 2
            return $resultSet;
340
        }
341
342 38
        if ($searchRequest->getRawUserQueryIsEmptyString() && !$this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
343
            // the user entered an empty query string "" or "  " and empty querystring is not allowed
344
            return $resultSet;
345
        }
346
347 38
        $rawQuery = $searchRequest->getRawUserQuery();
348 38
        $resultsPerPage = (int)$searchRequest->getResultsPerPage();
349 38
        $query = $this->getPreparedQuery($rawQuery, $resultsPerPage);
350 38
        $this->initializeRegisteredSearchComponents($query, $searchRequest);
351 38
        $resultSet->setUsedQuery($query);
352
353
        // the offset mulitplier is page - 1 but not less then zero
354 38
        $offsetMultiplier = max(0, $searchRequest->getPage() - 1);
355 38
        $offSet = $offsetMultiplier * $resultsPerPage;
356
357
        // performing the actual search, sending the query to the Solr server
358 38
        $query = $this->modifyQuery($query, $searchRequest, $this->search);
359 38
        $response = $this->doASearch($query, $offSet);
360
361 37
        if ($resultsPerPage === 0) {
362
            // when resultPerPage was forced to 0 we also set the numFound to 0 to hide results, e.g.
363
            // when results for the initial search should not be shown.
364 2
            $response->response->numFound = 0;
0 ignored issues
show
Bug introduced by
The property response does not seem to exist. Did you mean _response?

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.

Loading history...
365
        }
366
367 37
        $this->processResponse($response);
368 37
        $this->addSearchResultsToResultSet($response, $resultSet);
369
370 37
        $resultSet->setResponse($response);
371 37
        $resultSet->setUsedPage((int)$searchRequest->getPage());
372 37
        $resultSet->setUsedResultsPerPage($resultsPerPage);
373 37
        $resultSet->setUsedAdditionalFilters($this->getAdditionalFilters());
374 37
        $resultSet->setUsedSearch($this->search);
375
376
        /** @var $variantsProcessor VariantsProcessor */
377 37
        $variantsProcessor = GeneralUtility::makeInstance(VariantsProcessor::class, $this->typoScriptConfiguration, $this->searchResultBuilder);
378 37
        $variantsProcessor->process($resultSet);
379
380
        /** @var $searchResultReconstitutionProcessor ResultSetReconstitutionProcessor */
381 37
        $searchResultReconstitutionProcessor = GeneralUtility::makeInstance(ResultSetReconstitutionProcessor::class);
382 37
        $searchResultReconstitutionProcessor->process($resultSet);
383
384 37
        $resultSet = $this->getAutoCorrection($resultSet);
385
386 37
        return $this->handleSearchHook('afterSearch', $resultSet);
387
    }
388
389
    /**
390
     * Executes the search and builds a fake response for a current bug in Apache Solr 6.3
391
     *
392
     * @param Query $query
393
     * @param int $offSet
394
     * @throws SolrCommunicationException
395
     * @return \Apache_Solr_Response
396
     */
397 38
    protected function doASearch($query, $offSet)
398
    {
399
        try {
400 38
            $response = $this->search->search($query, $offSet, null);
401 2
        } catch (SolrInternalServerErrorException $e) {
402
            // when variants are enable and the index is empty, we get a parse exception, because of a
403
            // Apache Solr Bug.
404
            // see: https://github.com/TYPO3-Solr/ext-solr/issues/668
405
            // @todo this try/catch block can be removed after upgrading to Apache Solr 6.4
406 1
            if (!$this->typoScriptConfiguration->getSearchVariants()) {
407
                throw $e;
408
            }
409
410 1
            $response = $e->getSolrResponse();
411
412 1
            $parsedData = new \stdClass();
413 1
            $parsedData->response = new \stdClass();
414 1
            $parsedData->response->docs = [];
415 1
            $parsedData->spellcheck = [];
416 1
            $parsedData->debug = [];
417 1
            $parsedData->responseHeader = [];
418 1
            $parsedData->facet_counts = [];
419 1
            $parsedData->facets = [];
420 1
            $response->setParsedData($parsedData);
421
422
        }
423
424 37
        if($response === null) {
425
            throw new SolrIncompleteResponseException('The response retrieved from solr was incomplete', 1505989678);
426
        }
427
428 37
        return $response;
429
    }
430
431
    /**
432
     * @param SearchResultSet $searchResultSet
433
     * @return SearchResultSet
434
     */
435 37
    protected function getAutoCorrection(SearchResultSet $searchResultSet)
436
    {
437
        // no secondary search configured
438 37
        if (!$this->typoScriptConfiguration->getSearchSpellcheckingSearchUsingSpellCheckerSuggestion()) {
439 36
            return $searchResultSet;
440
        }
441
442
        // more then zero results
443 1
        if ($searchResultSet->getAllResultCount() > 0) {
444 1
            return $searchResultSet;
445
        }
446
447
        // no corrections present
448 1
        if (!$searchResultSet->getHasSpellCheckingSuggestions()) {
449
            return $searchResultSet;
450
        }
451
452 1
        $searchResultSet = $this->peformAutoCorrection($searchResultSet);
453
454 1
        return $searchResultSet;
455
    }
456
457
    /**
458
     * @param SearchResultSet $searchResultSet
459
     * @return SearchResultSet
460
     */
461 1
    protected function peformAutoCorrection(SearchResultSet $searchResultSet)
462
    {
463 1
        $searchRequest = $searchResultSet->getUsedSearchRequest();
464 1
        $suggestions = $searchResultSet->getSpellCheckingSuggestions();
465
466 1
        $maximumRuns = $this->typoScriptConfiguration->getSearchSpellcheckingNumberOfSuggestionsToTry(1);
467 1
        $runs = 0;
468
469 1
        foreach ($suggestions as $suggestion) {
470 1
            $runs++;
471
472 1
            $correction = $suggestion->getSuggestion();
473 1
            $initialQuery = $searchRequest->getRawUserQuery();
474
475 1
            $searchRequest->setRawQueryString($correction);
476 1
            $searchResultSet = $this->search($searchRequest);
477 1
            if ($searchResultSet->getAllResultCount() > 0) {
478 1
                $searchResultSet->setIsAutoCorrected(true);
479 1
                $searchResultSet->setCorrectedQueryString($correction);
480 1
                $searchResultSet->setInitialQueryString($initialQuery);
481 1
                break;
482
            }
483
484
            if ($runs > $maximumRuns) {
485
                break;
486
            }
487
        }
488 1
        return $searchResultSet;
489
    }
490
491
    /**
492
     * Allows to modify a query before eventually handing it over to Solr.
493
     *
494
     * @param Query $query The current query before it's being handed over to Solr.
495
     * @param SearchRequest $searchRequest The searchRequest, relevant in the current context
496
     * @param Search $search The search, relevant in the current context
497
     * @throws \UnexpectedValueException
498
     * @return Query The modified query that is actually going to be given to Solr.
499
     */
500 38
    protected function modifyQuery(Query $query, SearchRequest $searchRequest, Search $search)
501
    {
502
        // hook to modify the search query
503 38
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifySearchQuery'])) {
504 32
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifySearchQuery'] as $classReference) {
505 32
                $queryModifier = GeneralUtility::getUserObj($classReference);
506
507 32
                if ($queryModifier instanceof Modifier) {
508 32
                    if ($queryModifier instanceof SearchAware) {
509
                        $queryModifier->setSearch($search);
510
                    }
511
512 32
                    if ($queryModifier instanceof SearchRequestAware) {
513 32
                        $queryModifier->setSearchRequest($searchRequest);
514
                    }
515
516 32
                    $query = $queryModifier->modifyQuery($query);
517
                } else {
518
                    throw new \UnexpectedValueException(
519
                        get_class($queryModifier) . ' must implement interface ' . Modifier::class,
520 32
                        1310387414
521
                    );
522
                }
523
            }
524
        }
525
526 38
        return $query;
527
    }
528
529
    /**
530
     * Retrieves a single document from solr by document id.
531
     *
532
     * @param string $documentId
533
     * @return SearchResult
534
     */
535 3
    public function getDocumentById($documentId)
536
    {
537
        /* @var $query Query */
538 3
        $query = GeneralUtility::makeInstance(Query::class, $documentId);
539 3
        $query->setQueryFields(QueryFields::fromString('id'));
540
541 3
        $response = $this->search->search($query, 0, 1);
542 2
        $this->processResponse($response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $this->search->search($query, 0, 1) on line 541 can be null; however, ApacheSolrForTypo3\Solr\...vice::processResponse() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
543
544 2
        $parsedData = $response->getParsedData();
545 2
        $resultDocument = isset($parsedData->response->docs[0]) ? $parsedData->response->docs[0] : null;
546 2
        return $resultDocument;
547
    }
548
549
    /**
550
     * This method is used to call the registered hooks during the search execution.
551
     *
552
     * @param string $eventName
553
     * @param SearchResultSet $resultSet
554
     * @return SearchResultSet
555
     */
556 40
    private function handleSearchHook($eventName, SearchResultSet $resultSet)
557
    {
558 40
        if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName])) {
559 40
            return $resultSet;
560
        }
561
562 28
        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName] as $classReference) {
563 28
            $afterSearchProcessor = GeneralUtility::getUserObj($classReference);
564 28
            if ($afterSearchProcessor instanceof SearchResultSetProcessor) {
565 28
                $afterSearchProcessor->process($resultSet);
566
            }
567
        }
568
569 28
        return $resultSet;
570
    }
571
572
    /**
573
     * @return SearchResultSet
574
     */
575 29
    public function getLastResultSet()
576
    {
577 29
        return $this->lastResultSet;
578
    }
579
580
    /**
581
     * This method returns true when the last search was executed with an empty query
582
     * string or whitespaces only. When no search was triggered it will return false.
583
     *
584
     * @return bool
585
     */
586
    public function getLastSearchWasExecutedWithEmptyQueryString()
587
    {
588
        $wasEmptyQueryString = false;
589
        if ($this->lastResultSet != null) {
590
            $wasEmptyQueryString = $this->lastResultSet->getUsedSearchRequest()->getRawUserQueryIsEmptyString();
591
        }
592
593
        return $wasEmptyQueryString;
594
    }
595
596
    /**
597
     * @return bool
598
     */
599 6
    protected function getInitialSearchIsConfigured()
600
    {
601 6
        return $this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialEmptyQuery() || $this->typoScriptConfiguration->getSearchInitializeWithQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialQuery();
602
    }
603
604
    /**
605
     * @return mixed
606
     */
607 32
    protected function getRegisteredSearchComponents()
608
    {
609 32
        return GeneralUtility::makeInstance(SearchComponentManager::class)->getSearchComponents();
610
    }
611
612
    /**
613
     * This method is used to reference the SearchResult object from the response in the SearchResultSet object.
614
     *
615
     * @param \Apache_Solr_Response $response
616
     * @param SearchResultSet $resultSet
617
     */
618 37
    protected function addSearchResultsToResultSet($response, $resultSet)
619
    {
620 37
        $parsedData = $response->getParsedData();
621 37
        if (!is_array($parsedData->response->docs)) {
622 4
            return;
623
        }
624
625 33
        foreach ($parsedData->response->docs as $searchResult) {
626 27
            $resultSet->addSearchResult($searchResult);
627
        }
628 33
    }
629
630
    /**
631
     * @param string $rawQuery
632
     * @return Query|object
633
     */
634 32
    protected function getQueryInstance($rawQuery)
635
    {
636 32
        $query = GeneralUtility::makeInstance(Query::class, $rawQuery, $this->typoScriptConfiguration);
637 32
        return $query;
638
    }
639
640
}
641