Passed
Push — master ( 1b8200...cdf526 )
by Timo
21:46
created

SearchResultSetService   D

Complexity

Total Complexity 86

Size/Duplication

Total Lines 590
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 85.29%

Importance

Changes 0
Metric Value
wmc 86
lcom 1
cbo 12
dl 0
loc 590
ccs 174
cts 204
cp 0.8529
rs 4.0645
c 0
b 0
f 0

28 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getIsSolrAvailable() 0 5 1
A getHasSearched() 0 4 1
A getSearch() 0 4 1
A setUseQueryAwareComponents() 0 4 1
A getUseQueryAwareComponents() 0 4 1
B getPreparedQuery() 0 37 6
A initializeRegisteredSearchComponents() 0 15 4
B getNumberOfResultsPerPage() 0 25 6
B processResponse() 0 21 5
A wrapApacheSolrDocumentInResultObject() 0 10 2
A getResultClassName() 0 5 2
A getResultSetClassName() 0 5 2
B shouldHideResultsFromInitialSearch() 0 4 5
A applyPageSectionsRootLineFilter() 0 13 3
C getAdditionalFilters() 0 36 7
B search() 0 51 6
A getDocumentById() 0 12 2
A handleSearchHook() 0 15 4
A getLastResultSet() 0 4 1
A getLastSearchWasExecutedWithEmptyQueryString() 0 9 2
A setPerPageInSession() 0 4 1
A getPerPageFromSession() 0 4 1
A getInitialSearchIsConfigured() 0 4 4
A getRegisteredSearchComponents() 0 4 1
D addExpandedDocumentsFromVariants() 0 39 10
A wrapResultDocumentInResultObject() 0 15 3
A addSearchResultsToResultSet() 0 10 3

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\SearchRequest;
29
use ApacheSolrForTypo3\Solr\Query;
30
use ApacheSolrForTypo3\Solr\Response\Processor\ResponseProcessor;
31
use ApacheSolrForTypo3\Solr\Search;
32
use ApacheSolrForTypo3\Solr\Search\QueryAware;
33
use ApacheSolrForTypo3\Solr\Search\SearchComponentManager;
34
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration;
35
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
36
use TYPO3\CMS\Core\Utility\GeneralUtility;
37
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
38
use Apache_Solr_ParserException;
39
40
/**
41
 * The SearchResultSetService is responsible to build a SearchResultSet from a SearchRequest.
42
 * It encapsulates the logic to trigger a search in order to be able to reuse it in multiple places.
43
 *
44
 * @author Timo Schmidt <[email protected]>
45
 */
46
class SearchResultSetService
47
{
48
    /**
49
     * Additional filters, which will be added to the query, as well as to
50
     * suggest queries.
51
     *
52
     * @var array
53
     */
54
    protected $additionalFilters = [];
55
56
    /**
57
     * Track, if the number of results per page has been changed by the current request
58
     *
59
     * @var bool
60
     */
61
    protected $resultsPerPageChanged = false;
62
63
    /**
64
     * @var \ApacheSolrForTypo3\Solr\Search
65
     */
66
    protected $search;
67
68
    /**
69
     * @var SearchResultSet
70
     */
71
    protected $lastResultSet = null;
72
73
    /**
74
     * @var bool
75
     */
76
    protected $useQueryAwareComponents = true;
77
78
    /**
79
     * @var
80
     */
81
    protected $isSolrAvailable = false;
82
83
    /**
84
     * @var TypoScriptConfiguration
85
     */
86
    protected $typoScriptConfiguration;
87
88
    /**
89
     * @var \ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
90
     */
91
    protected $logger = null;
92
93
    /**
94
     * @param TypoScriptConfiguration $configuration
95
     * @param Search $search
96
     */
97 40
    public function __construct(TypoScriptConfiguration $configuration, Search $search)
98
    {
99 40
        $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__);
100 40
        $this->search = $search;
101 40
        $this->typoScriptConfiguration = $configuration;
102 40
    }
103
104
    /**
105
     * @param bool $useCache
106
     * @return bool
107
     */
108 24
    public function getIsSolrAvailable($useCache = true)
109
    {
110 24
        $this->isSolrAvailable = $this->search->ping($useCache);
111 24
        return $this->isSolrAvailable;
112
    }
113
114
    /**
115
     * @return bool
116
     */
117 24
    public function getHasSearched()
118
    {
119 24
        return $this->search->hasSearched();
120
    }
121
122
    /**
123
     * Retrieves the used search instance.
124
     *
125
     * @return Search
126
     */
127 2
    public function getSearch()
128
    {
129 2
        return $this->search;
130
    }
131
132
    /**
133
     * @param bool $useQueryAwareComponents
134
     */
135
    public function setUseQueryAwareComponents($useQueryAwareComponents)
136
    {
137
        $this->useQueryAwareComponents = $useQueryAwareComponents;
138
    }
139
140
    /**
141
     * @return bool
142
     */
143
    public function getUseQueryAwareComponents()
144
    {
145
        return $this->useQueryAwareComponents;
146
    }
147
148
    /**
149
     * Initializes the Query object and SearchComponents and returns
150
     * the initialized query object, when a search should be executed.
151
     *
152
     * @param string $rawQuery
153
     * @param int $resultsPerPage
154
     * @return Query
155
     */
156 32
    protected function getPreparedQuery($rawQuery, $resultsPerPage)
157
    {
158
        /* @var $query Query */
159 32
        $query = GeneralUtility::makeInstance(Query::class, $rawQuery);
160
161 32
        $this->applyPageSectionsRootLineFilter($query);
162
163 32
        if ($this->typoScriptConfiguration->getLoggingQuerySearchWords()) {
164
            $this->logger->log(
165
                SolrLogManager::INFO,
166
                'Received search query',
167
                [
168
                    $rawQuery
169
                ]
170
            );
171
        }
172
173 32
        $query->setResultsPerPage($resultsPerPage);
174
175 32
        $this->initializeRegisteredSearchComponents($query);
176
177 32
        if ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
178
            // empty main query, but using a "return everything"
179
            // alternative query in q.alt
180 25
            $query->setAlternativeQuery('*:*');
181
        }
182
183 32
        if ($this->typoScriptConfiguration->getSearchInitializeWithQuery()) {
184 1
            $query->setAlternativeQuery($this->typoScriptConfiguration->getSearchInitializeWithQuery());
185
        }
186
187 32
        foreach ($this->getAdditionalFilters() as $additionalFilter) {
188 2
            $query->addFilter($additionalFilter);
189
        }
190
191 32
        return $query;
192
    }
193
194
    /**
195
     * @param Query $query
196
     */
197 32
    protected function initializeRegisteredSearchComponents(Query $query)
198
    {
199 32
        $searchComponents = $this->getRegisteredSearchComponents();
200
201 32
        foreach ($searchComponents as $searchComponent) {
202
            /** @var Search\SearchComponent $searchComponent */
203 26
            $searchComponent->setSearchConfiguration($this->typoScriptConfiguration->getSearchConfiguration());
204
205 26
            if ($searchComponent instanceof QueryAware && $this->useQueryAwareComponents) {
206 26
                $searchComponent->setQuery($query);
207
            }
208
209 26
            $searchComponent->initializeSearchComponent();
210
        }
211 32
    }
212
213
    /**
214
     * Returns the number of results per Page.
215
     *
216
     * Also influences how many result documents are returned by the Solr
217
     * server as the return value is used in the Solr "rows" GET parameter.
218
     *
219
     * @param string $rawQuery
220
     * @param int|null $requestedPerPage
221
     * @return int number of results to show per page
222
     */
223 32
    protected function getNumberOfResultsPerPage($rawQuery, $requestedPerPage = null)
224
    {
225 32
        $perPageSwitchOptions = $this->typoScriptConfiguration->getSearchResultsPerPageSwitchOptionsAsArray();
226 32
        if (isset($requestedPerPage) && in_array($requestedPerPage, $perPageSwitchOptions)) {
227 3
            $this->setPerPageInSession($requestedPerPage);
228 3
            $this->resultsPerPageChanged = true;
229
        }
230
231 32
        $defaultResultsPerPage = $this->typoScriptConfiguration->getSearchResultsPerPage();
232 32
        $sessionResultPerPage = $this->getPerPageFromSession();
233
234 32
        $currentNumberOfResultsShown = $defaultResultsPerPage;
235 32
        if (!is_null($sessionResultPerPage) && in_array($sessionResultPerPage, $perPageSwitchOptions)) {
236 2
            $currentNumberOfResultsShown = (int)$sessionResultPerPage;
237
        }
238
239 32
        if ($this->shouldHideResultsFromInitialSearch($rawQuery)) {
240
            // initialize search with an empty query, which would by default return all documents
241
            // anyway, tell Solr to not return any result documents
242
            // Solr will still return facets though
243
            $currentNumberOfResultsShown = 0;
244
        }
245
246 32
        return $currentNumberOfResultsShown;
247
    }
248
249
    /**
250
     * Provides a hook for other classes to process the search's response.
251
     *
252
     * @param string $rawQuery
253
     * @param Query $query The query that has been searched for.
254
     * @param \Apache_Solr_Response $response The search's response.
255
     */
256 34
    protected function processResponse($rawQuery, Query $query, \Apache_Solr_Response $response)
257
    {
258 34
        if ($this->shouldHideResultsFromInitialSearch($rawQuery)) {
259
            // explicitly set number of results to 0 as we just wanted
260
            // facets and the like according to configuration
261
            // @see getNumberOfResultsPerPage()
262
            $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...
263
        }
264
265 34
        $this->wrapResultDocumentInResultObject($response);
266 34
        $this->addExpandedDocumentsFromVariants($response);
267
268 34
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['processSearchResponse'])) {
269 22
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['processSearchResponse'] as $classReference) {
270 22
                $responseProcessor = GeneralUtility::getUserObj($classReference);
271 22
                if ($responseProcessor instanceof ResponseProcessor) {
272 22
                    $responseProcessor->processResponse($query, $response);
273
                }
274
            }
275
        }
276 34
    }
277
278
    /**
279
     * This method is used to add documents to the expanded documents of the SearchResult
280
     * when collapsing is configured.
281
     *
282
     * @param \Apache_Solr_Response $response
283
     */
284 34
    protected function addExpandedDocumentsFromVariants(\Apache_Solr_Response $response)
285
    {
286 34
        if (!is_array($response->response->docs)) {
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...
287 5
            return;
288
        }
289
290 29
        if (!$this->typoScriptConfiguration->getSearchVariants()) {
291 26
            return;
292
        }
293
294 3
        $variantsField = $this->typoScriptConfiguration->getSearchVariantsField();
295 3
        foreach ($response->response->docs as $key => $resultDocument) {
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...
296
            /** @var $resultDocument SearchResult */
297 2
            $variantField = $resultDocument->getField($variantsField);
298 2
            $variantId = isset($variantField['value']) ? $variantField['value'] : null;
299
300
                // when there is no value in the collapsing field, we can return
301 2
            if ($variantId === null) {
302
                continue;
303
            }
304
305 2
            $variantAccessKey = strtolower($variantId);
306 2
            if (!isset($response->{'expanded'}) || !isset($response->{'expanded'}->{$variantAccessKey})) {
307
                continue;
308
            }
309
310 2
            foreach ($response->{'expanded'}->{$variantAccessKey}->{'docs'} as $variantDocumentArray) {
311 2
                $variantDocument = new \Apache_Solr_Document();
312 2
                foreach (get_object_vars($variantDocumentArray) as $propertyName => $propertyValue) {
313 2
                    $variantDocument->{$propertyName} = $propertyValue;
314
                }
315 2
                $variantSearchResult = $this->wrapApacheSolrDocumentInResultObject($variantDocument);
316 2
                $variantSearchResult->setIsVariant(true);
317 2
                $variantSearchResult->setVariantParent($resultDocument);
318
319 2
                $resultDocument->addVariant($variantSearchResult);
320
            }
321
        }
322 3
    }
323
324
    /**
325
     * Wrap all results document it a custom EXT:solr SearchResult object.
326
     *
327
     * Can be overwritten:
328
     *
329
     * $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultClassName '] = ''
330
     *
331
     * to use a custom result object.
332
     *
333
     * @param \Apache_Solr_Response $response
334
     * @throws \Apache_Solr_ParserException
335
     */
336 34
    protected function wrapResultDocumentInResultObject(\Apache_Solr_Response $response)
337
    {
338 34
        $documents = $response->response->docs;
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...
339
340 34
        if (!is_array($documents)) {
341 5
            return;
342
        }
343
344 29
        foreach ($documents as $key => $originalDocument) {
345 26
            $result = $this->wrapApacheSolrDocumentInResultObject($originalDocument);
346 26
            $documents[$key] = $result;
347
        }
348
349 29
        $response->response->docs = $documents;
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...
350 29
    }
351
352
    /**
353
     * This method is used to wrap the \Apache_Solr_Document instance in an instance of the configured SearchResult
354
     * class.
355
     *
356
     * @param \Apache_Solr_Document $originalDocument
357
     * @throws \InvalidArgumentException
358
     * @return SearchResult
359
     */
360 26
    protected function wrapApacheSolrDocumentInResultObject(\Apache_Solr_Document $originalDocument)
361
    {
362 26
        $searchResultClassName = $this->getResultClassName();
363 26
        $result = GeneralUtility::makeInstance($searchResultClassName, $originalDocument);
364 26
        if (!$result instanceof SearchResult) {
365
            throw new \InvalidArgumentException('Could not create result object with class: ' . (string)$searchResultClassName, 1470037679);
366
        }
367
368 26
        return $result;
369
    }
370
371
    /**
372
     * @return string
373
     */
374 26
    protected function getResultClassName()
375
    {
376 26
        return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultClassName ']) ?
377 26
            $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultClassName '] : SearchResult::class;
378
    }
379
380
    /**
381
     * @return string
382
     */
383 34
    protected function getResultSetClassName()
384
    {
385 34
        return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName ']) ?
386 34
            $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName '] : SearchResultSet::class;
387
    }
388
389
    /**
390
     * Checks it the results should be hidden in the response.
391
     *
392
     * @param string $rawQuery
393
     * @return bool
394
     */
395 34
    protected function shouldHideResultsFromInitialSearch($rawQuery)
396
    {
397 34
        return ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchInitializeWithQuery()) && !$this->typoScriptConfiguration->getSearchShowResultsOfInitialEmptyQuery() && !$this->typoScriptConfiguration->getSearchShowResultsOfInitialQuery() && $rawQuery === null;
398
    }
399
400
    /**
401
     * Initializes additional filters configured through TypoScript and
402
     * Flexforms for use in regular queries and suggest queries.
403
     *
404
     * @param Query $query
405
     * @return void
406
     */
407 32
    protected function applyPageSectionsRootLineFilter(Query $query)
408
    {
409 32
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
410 32
        if (count($searchQueryFilters) <= 0) {
411 30
            return;
412
        }
413
414
        // special filter to limit search to specific page tree branches
415 2
        if (array_key_exists('__pageSections', $searchQueryFilters)) {
416
            $query->setRootlineFilter($searchQueryFilters['__pageSections']);
417
            $this->typoScriptConfiguration->removeSearchQueryFilterForPageSections();
418
        }
419 2
    }
420
421
    /**
422
     * Retrieves the configuration filters from the TypoScript configuration, except the __pageSections filter.
423
     *
424
     * @return array
425
     */
426 37
    public function getAdditionalFilters()
427
    {
428
        // when we've build the additionalFilter once, we could return them
429 37
        if (count($this->additionalFilters) > 0) {
430 2
            return $this->additionalFilters;
431
        }
432
433 37
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
434 37
        if (count($searchQueryFilters) <= 0) {
435 35
            return [];
436
        }
437
438 2
        $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
439
440
        // all other regular filters
441 2
        foreach ($searchQueryFilters as $filterKey => $filter) {
442
            // the __pageSections filter should not be handled as additional filter
443 2
            if ($filterKey === '__pageSections') {
444
                continue;
445
            }
446
447 2
            $filterIsArray = is_array($searchQueryFilters[$filterKey]);
448 2
            if ($filterIsArray) {
449
                continue;
450
            }
451
452 2
            $hasSubConfiguration = is_array($searchQueryFilters[$filterKey . '.']);
453 2
            if ($hasSubConfiguration) {
454
                $filter = $cObj->stdWrap($searchQueryFilters[$filterKey], $searchQueryFilters[$filterKey . '.']);
455
            }
456
457 2
            $this->additionalFilters[$filterKey] = $filter;
458
        }
459
460 2
        return $this->additionalFilters;
461
    }
462
463
    /**
464
     * Performs a search and returns a SearchResultSet.
465
     *
466
     * @param SearchRequest $searchRequest
467
     * @return SearchResultSet
468
     */
469 34
    public function search(SearchRequest $searchRequest)
470
    {
471
        /** @var $resultSet SearchResultSet */
472 34
        $resultSetClass = $this->getResultSetClassName();
473 34
        $resultSet = GeneralUtility::makeInstance($resultSetClass);
474 34
        $resultSet->setUsedSearchRequest($searchRequest);
475 34
        $this->lastResultSet = $resultSet;
476
477 34
        $resultSet = $this->handleSearchHook('beforeSearch', $resultSet);
478
479 34
        if ($searchRequest->getRawUserQueryIsNull() && !$this->getInitialSearchIsConfigured()) {
480
            // when no rawQuery was passed or no initialSearch is configured, we pass an empty result set
481 2
            return $resultSet;
482
        }
483
484 32
        if ($searchRequest->getRawUserQueryIsEmptyString() && !$this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
485
            // the user entered an empty query string "" or "  " and empty querystring is not allowed
486
            return $resultSet;
487
        }
488
489 32
        $rawQuery = $searchRequest->getRawUserQuery();
490 32
        $resultsPerPage = $this->getNumberOfResultsPerPage($rawQuery, $searchRequest->getResultsPerPage());
0 ignored issues
show
Documentation introduced by
$rawQuery is of type array|null, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
It seems like $searchRequest->getResultsPerPage() targeting ApacheSolrForTypo3\Solr\...st::getResultsPerPage() can also be of type array; however, ApacheSolrForTypo3\Solr\...umberOfResultsPerPage() does only seem to accept integer|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
491 32
        $query = $this->getPreparedQuery($rawQuery, $resultsPerPage);
0 ignored issues
show
Documentation introduced by
$rawQuery is of type array|null, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
492
493 32
        $resultSet->setUsedQuery($query);
494
495 32
        $currentPage = max(0, $searchRequest->getPage());
496
        // if the number of results per page has been changed by the current request, reset the pagebrowser
497 32
        if ($this->resultsPerPageChanged) {
498 3
            $currentPage = 0;
499
        }
500
501 32
        $offSet = $currentPage * $resultsPerPage;
502
        // performing the actual search, sending the query to the Solr server
503 32
        $response = $this->search->search($query, $offSet, null);
504
505 32
        $this->processResponse($rawQuery, $query, $response);
0 ignored issues
show
Documentation introduced by
$rawQuery is of type array|null, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
506 32
        $this->addSearchResultsToResultSet($response, $resultSet);
507
508 32
        $resultSet->setResponse($response);
509 32
        $resultSet->setUsedPage($currentPage);
510 32
        $resultSet->setUsedResultsPerPage($resultsPerPage);
511 32
        $resultSet->setUsedAdditionalFilters($this->getAdditionalFilters());
512 32
        $resultSet->setUsedSearch($this->search);
513
514
        /** @var $searchResultReconstitutionProcessor ResultSetReconstitutionProcessor */
515 32
        $searchResultReconstitutionProcessor = GeneralUtility::makeInstance(ResultSetReconstitutionProcessor::class);
516 32
        $searchResultReconstitutionProcessor->process($resultSet);
517
518 32
        return $this->handleSearchHook('afterSearch', $resultSet);
519
    }
520
521
    /**
522
     * Retrieves a single document from solr by document id.
523
     *
524
     * @param string $documentId
525
     * @return SearchResult
526
     */
527 2
    public function getDocumentById($documentId)
528
    {
529
        /* @var $query Query */
530 2
        $query = GeneralUtility::makeInstance(Query::class, $documentId);
531 2
        $query->setQueryFieldsFromString('id');
532
533 2
        $response = $this->search->search($query, 0, 1);
534 2
        $this->processResponse($documentId, $query, $response);
535
536 2
        $resultDocument = isset($response->response->docs[0]) ? $response->response->docs[0] : null;
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...
537 2
        return $resultDocument;
538
    }
539
540
    /**
541
     * This method is used to call the registered hooks during the search execution.
542
     *
543
     * @param string $eventName
544
     * @param SearchResultSet $resultSet
545
     * @return SearchResultSet
546
     */
547 34
    private function handleSearchHook($eventName, SearchResultSet $resultSet)
548
    {
549 34
        if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName])) {
550 34
            return $resultSet;
551
        }
552
553
        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName] as $classReference) {
554
            $afterSearchProcessor = GeneralUtility::getUserObj($classReference);
555
            if ($afterSearchProcessor instanceof SearchResultSetProcessor) {
556
                $afterSearchProcessor->process($resultSet);
557
            }
558
        }
559
560
        return $resultSet;
561
    }
562
563
    /**
564
     * @return SearchResultSet
565
     */
566 23
    public function getLastResultSet()
567
    {
568 23
        return $this->lastResultSet;
569
    }
570
571
    /**
572
     * This method returns true when the last search was executed with an empty query
573
     * string or whitespaces only. When no search was triggered it will return false.
574
     *
575
     * @return bool
576
     */
577
    public function getLastSearchWasExecutedWithEmptyQueryString()
578
    {
579
        $wasEmptyQueryString = false;
580
        if ($this->lastResultSet != null) {
581
            $wasEmptyQueryString = $this->lastResultSet->getUsedSearchRequest()->getRawUserQueryIsEmptyString();
582
        }
583
584
        return $wasEmptyQueryString;
585
    }
586
587
    /**
588
     * @param int $requestedPerPage
589
     */
590 2
    protected function setPerPageInSession($requestedPerPage)
591
    {
592 2
        $GLOBALS['TSFE']->fe_user->setKey('ses', 'tx_solr_resultsPerPage', intval($requestedPerPage));
593 2
    }
594
595
    /**
596
     * @return mixed
597
     */
598 25
    protected function getPerPageFromSession()
599
    {
600 25
        return $GLOBALS['TSFE']->fe_user->getKey('ses', 'tx_solr_resultsPerPage');
601
    }
602
603
    /**
604
     * @return bool
605
     */
606 2
    protected function getInitialSearchIsConfigured()
607
    {
608 2
        return $this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialEmptyQuery() || $this->typoScriptConfiguration->getSearchInitializeWithQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialQuery();
609
    }
610
611
    /**
612
     * @return mixed
613
     */
614 25
    protected function getRegisteredSearchComponents()
615
    {
616 25
        return GeneralUtility::makeInstance(SearchComponentManager::class)->getSearchComponents();
617
    }
618
619
    /**
620
     * This method is used to reference the SearchResult object from the response in the SearchResultSet object.
621
     *
622
     * @param \Apache_Solr_Response $response
623
     * @param SearchResultSet $resultSet
624
     */
625 32
    protected function addSearchResultsToResultSet($response, $resultSet)
626
    {
627 32
        if (!is_array($response->response->docs)) {
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...
628 5
            return;
629
        }
630
631 27
        foreach ($response->response->docs as $searchResult) {
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...
632 24
            $resultSet->addSearchResult($searchResult);
633
        }
634 27
    }
635
}
636