Passed
Pull Request — master (#1339)
by Timo
38:37 queued 06:25
created

SearchResultSetService::processResponse()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.0187

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 10
cts 11
cp 0.9091
rs 8.7624
c 0
b 0
f 0
cc 5
eloc 10
nc 8
nop 3
crap 5.0187
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 41
    public function __construct(TypoScriptConfiguration $configuration, Search $search)
98
    {
99 41
        $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__);
100 41
        $this->search = $search;
101 41
        $this->typoScriptConfiguration = $configuration;
102 41
    }
103
104
    /**
105
     * @param bool $useCache
106
     * @return bool
107
     */
108 25
    public function getIsSolrAvailable($useCache = true)
109
    {
110 25
        $this->isSolrAvailable = $this->search->ping($useCache);
111 25
        return $this->isSolrAvailable;
112
    }
113
114
    /**
115
     * @return bool
116
     */
117 25
    public function getHasSearched()
118
    {
119 25
        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 33
    protected function getPreparedQuery($rawQuery, $resultsPerPage)
157
    {
158
        /* @var $query Query */
159 33
        $query = GeneralUtility::makeInstance(Query::class, $rawQuery);
160
161 33
        $this->applyPageSectionsRootLineFilter($query);
162
163 33
        if ($this->typoScriptConfiguration->getLoggingQuerySearchWords()) {
164
            $this->logger->log(
165
                SolrLogManager::INFO,
166
                'Received search query',
167
                [
168
                    $rawQuery
169
                ]
170
            );
171
        }
172
173 33
        $query->setResultsPerPage($resultsPerPage);
174
175 33
        $this->initializeRegisteredSearchComponents($query);
176
177 33
        if ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
178
            // empty main query, but using a "return everything"
179
            // alternative query in q.alt
180 26
            $query->setAlternativeQuery('*:*');
181
        }
182
183 33
        if ($this->typoScriptConfiguration->getSearchInitializeWithQuery()) {
184 1
            $query->setAlternativeQuery($this->typoScriptConfiguration->getSearchInitializeWithQuery());
185
        }
186
187 33
        foreach ($this->getAdditionalFilters() as $additionalFilter) {
188 2
            $query->addFilter($additionalFilter);
189
        }
190
191 33
        return $query;
192
    }
193
194
    /**
195
     * @param Query $query
196
     */
197 33
    protected function initializeRegisteredSearchComponents(Query $query)
198
    {
199 33
        $searchComponents = $this->getRegisteredSearchComponents();
200
201 33
        foreach ($searchComponents as $searchComponent) {
202
            /** @var Search\SearchComponent $searchComponent */
203 27
            $searchComponent->setSearchConfiguration($this->typoScriptConfiguration->getSearchConfiguration());
204
205 27
            if ($searchComponent instanceof QueryAware && $this->useQueryAwareComponents) {
206 27
                $searchComponent->setQuery($query);
207
            }
208
209 27
            $searchComponent->initializeSearchComponent();
210
        }
211 33
    }
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 33
    protected function getNumberOfResultsPerPage($rawQuery, $requestedPerPage = null)
224
    {
225 33
        $perPageSwitchOptions = $this->typoScriptConfiguration->getSearchResultsPerPageSwitchOptionsAsArray();
226 33
        if (isset($requestedPerPage) && in_array($requestedPerPage, $perPageSwitchOptions)) {
227 4
            $this->setPerPageInSession($requestedPerPage);
228 4
            $this->resultsPerPageChanged = true;
229
        }
230
231 33
        $defaultResultsPerPage = $this->typoScriptConfiguration->getSearchResultsPerPage();
232 33
        $sessionResultPerPage = $this->getPerPageFromSession();
233
234 33
        $currentNumberOfResultsShown = $defaultResultsPerPage;
235 33
        if (!is_null($sessionResultPerPage) && in_array($sessionResultPerPage, $perPageSwitchOptions)) {
236 3
            $currentNumberOfResultsShown = (int)$sessionResultPerPage;
237
        }
238
239 33
        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 33
        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 35
    protected function processResponse($rawQuery, Query $query, \Apache_Solr_Response $response)
257
    {
258 35
        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 35
        $this->wrapResultDocumentInResultObject($response);
266 35
        $this->addExpandedDocumentsFromVariants($response);
267
268 35
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['processSearchResponse'])) {
269 23
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['processSearchResponse'] as $classReference) {
270 23
                $responseProcessor = GeneralUtility::getUserObj($classReference);
271 23
                if ($responseProcessor instanceof ResponseProcessor) {
272 23
                    $responseProcessor->processResponse($query, $response);
273
                }
274
            }
275
        }
276 35
    }
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 35
    protected function addExpandedDocumentsFromVariants(\Apache_Solr_Response $response)
285
    {
286 35
        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 30
        if (!$this->typoScriptConfiguration->getSearchVariants()) {
291 27
            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 35
    protected function wrapResultDocumentInResultObject(\Apache_Solr_Response $response)
337
    {
338 35
        try {
339
            $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...
340 35
        } catch (Apache_Solr_ParserException $e) {
0 ignored issues
show
Unused Code introduced by
catch (\Apache_Solr_Pars...$documents = array(); } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
341 5
            // when variant are enable and the index is empty, we get a parse exception, because of a
342
            // Apache Solr Bug.
343
            // see: https://github.com/TYPO3-Solr/ext-solr/issues/668
344 30
            // @todo this try/catch block can be removed after upgrading to Apache Solr 6.4
345 27
            if (!$this->typoScriptConfiguration->getSearchVariants()) {
346 27
                throw $e;
347
            }
348
349 30
            $response->response = new \stdClass();
350 30
            $response->spellcheck = [];
351
            $response->debug = [];
352
            $response->responseHeader = [];
353
            $response->facet_counts = [];
354
355
            $documents = [];
356
        }
357
358
        if (!is_array($documents)) {
359
            return;
360 27
        }
361
362 27
        foreach ($documents as $key => $originalDocument) {
363 27
            $result = $this->wrapApacheSolrDocumentInResultObject($originalDocument);
364 27
            $documents[$key] = $result;
365
        }
366
367
        $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...
368 27
    }
369
370
    /**
371
     * This method is used to wrap the \Apache_Solr_Document instance in an instance of the configured SearchResult
372
     * class.
373
     *
374 27
     * @param \Apache_Solr_Document $originalDocument
375
     * @throws \InvalidArgumentException
376 27
     * @return SearchResult
377 27
     */
378
    protected function wrapApacheSolrDocumentInResultObject(\Apache_Solr_Document $originalDocument)
379
    {
380
        $searchResultClassName = $this->getResultClassName();
381
        $result = GeneralUtility::makeInstance($searchResultClassName, $originalDocument);
382
        if (!$result instanceof SearchResult) {
383 35
            throw new \InvalidArgumentException('Could not create result object with class: ' . (string)$searchResultClassName, 1470037679);
384
        }
385 35
386 35
        return $result;
387
    }
388
389
    /**
390
     * @return string
391
     */
392
    protected function getResultClassName()
393
    {
394
        return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultClassName ']) ?
395 35
            $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultClassName '] : SearchResult::class;
396
    }
397 35
398
    /**
399
     * @return string
400
     */
401
    protected function getResultSetClassName()
402
    {
403
        return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName ']) ?
404
            $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName '] : SearchResultSet::class;
405
    }
406
407 33
    /**
408
     * Checks it the results should be hidden in the response.
409 33
     *
410 33
     * @param string $rawQuery
411 31
     * @return bool
412
     */
413
    protected function shouldHideResultsFromInitialSearch($rawQuery)
414
    {
415 2
        return ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchInitializeWithQuery()) && !$this->typoScriptConfiguration->getSearchShowResultsOfInitialEmptyQuery() && !$this->typoScriptConfiguration->getSearchShowResultsOfInitialQuery() && $rawQuery === null;
416
    }
417
418
    /**
419 2
     * Initializes additional filters configured through TypoScript and
420
     * Flexforms for use in regular queries and suggest queries.
421
     *
422
     * @param Query $query
423
     * @return void
424
     */
425
    protected function applyPageSectionsRootLineFilter(Query $query)
426 38
    {
427
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
428
        if (count($searchQueryFilters) <= 0) {
429 38
            return;
430 2
        }
431
432
        // special filter to limit search to specific page tree branches
433 38
        if (array_key_exists('__pageSections', $searchQueryFilters)) {
434 38
            $query->setRootlineFilter($searchQueryFilters['__pageSections']);
435 36
            $this->typoScriptConfiguration->removeSearchQueryFilterForPageSections();
436
        }
437
    }
438 2
439
    /**
440
     * Retrieves the configuration filters from the TypoScript configuration, except the __pageSections filter.
441 2
     *
442
     * @return array
443 2
     */
444
    public function getAdditionalFilters()
445
    {
446
        // when we've build the additionalFilter once, we could return them
447 2
        if (count($this->additionalFilters) > 0) {
448 2
            return $this->additionalFilters;
449
        }
450
451
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
452 2
        if (count($searchQueryFilters) <= 0) {
453 2
            return [];
454
        }
455
456
        $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
457 2
458
        // all other regular filters
459
        foreach ($searchQueryFilters as $filterKey => $filter) {
460 2
            // the __pageSections filter should not be handled as additional filter
461
            if ($filterKey === '__pageSections') {
462
                continue;
463
            }
464
465
            $filterIsArray = is_array($searchQueryFilters[$filterKey]);
466
            if ($filterIsArray) {
467
                continue;
468
            }
469 35
470
            $hasSubConfiguration = is_array($searchQueryFilters[$filterKey . '.']);
471
            if ($hasSubConfiguration) {
472 35
                $filter = $cObj->stdWrap($searchQueryFilters[$filterKey], $searchQueryFilters[$filterKey . '.']);
473 35
            }
474 35
475 35
            $this->additionalFilters[$filterKey] = $filter;
476
        }
477 35
478
        return $this->additionalFilters;
479 35
    }
480
481 2
    /**
482
     * Performs a search and returns a SearchResultSet.
483
     *
484 33
     * @param SearchRequest $searchRequest
485
     * @return SearchResultSet
486
     */
487
    public function search(SearchRequest $searchRequest)
488
    {
489 33
        /** @var $resultSet SearchResultSet */
490 33
        $resultSetClass = $this->getResultSetClassName();
491 33
        $resultSet = GeneralUtility::makeInstance($resultSetClass);
492
        $resultSet->setUsedSearchRequest($searchRequest);
493 33
        $this->lastResultSet = $resultSet;
494
495 33
        $resultSet = $this->handleSearchHook('beforeSearch', $resultSet);
496
497 33
        if ($searchRequest->getRawUserQueryIsNull() && !$this->getInitialSearchIsConfigured()) {
498 4
            // when no rawQuery was passed or no initialSearch is configured, we pass an empty result set
499
            return $resultSet;
500
        }
501 33
502
        if ($searchRequest->getRawUserQueryIsEmptyString() && !$this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
503 33
            // the user entered an empty query string "" or "  " and empty querystring is not allowed
504
            return $resultSet;
505 33
        }
506 33
507
        $rawQuery = $searchRequest->getRawUserQuery();
508 33
        $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...
509 33
        $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...
510 33
511 33
        $resultSet->setUsedQuery($query);
512 33
513
        $currentPage = max(0, $searchRequest->getPage());
514
        // if the number of results per page has been changed by the current request, reset the pagebrowser
515 33
        if ($this->resultsPerPageChanged) {
516 33
            $currentPage = 0;
517
        }
518 33
519
        $offSet = $currentPage * $resultsPerPage;
520
        // performing the actual search, sending the query to the Solr server
521
        $response = $this->search->search($query, $offSet, null);
522
523
        $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...
524
        $this->addSearchResultsToResultSet($response, $resultSet);
525
526
        $resultSet->setResponse($response);
527 2
        $resultSet->setUsedPage($currentPage);
528
        $resultSet->setUsedResultsPerPage($resultsPerPage);
529
        $resultSet->setUsedAdditionalFilters($this->getAdditionalFilters());
530 2
        $resultSet->setUsedSearch($this->search);
531 2
532
        /** @var $searchResultReconstitutionProcessor ResultSetReconstitutionProcessor */
533 2
        $searchResultReconstitutionProcessor = GeneralUtility::makeInstance(ResultSetReconstitutionProcessor::class);
534 2
        $searchResultReconstitutionProcessor->process($resultSet);
535
536 2
        return $this->handleSearchHook('afterSearch', $resultSet);
537 2
    }
538
539
    /**
540
     * Retrieves a single document from solr by document id.
541
     *
542
     * @param string $documentId
543
     * @return SearchResult
544
     */
545
    public function getDocumentById($documentId)
546
    {
547 35
        /* @var $query Query */
548
        $query = GeneralUtility::makeInstance(Query::class, $documentId);
549 35
        $query->setQueryFieldsFromString('id');
550 35
551
        $response = $this->search->search($query, 0, 1);
552
        $this->processResponse($documentId, $query, $response);
553
554
        $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...
555
        return $resultDocument;
556
    }
557
558
    /**
559
     * This method is used to call the registered hooks during the search execution.
560
     *
561
     * @param string $eventName
562
     * @param SearchResultSet $resultSet
563
     * @return SearchResultSet
564
     */
565
    private function handleSearchHook($eventName, SearchResultSet $resultSet)
566 24
    {
567
        if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName])) {
568 24
            return $resultSet;
569
        }
570
571
        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName] as $classReference) {
572
            $afterSearchProcessor = GeneralUtility::getUserObj($classReference);
573
            if ($afterSearchProcessor instanceof SearchResultSetProcessor) {
574
                $afterSearchProcessor->process($resultSet);
575
            }
576
        }
577
578
        return $resultSet;
579
    }
580
581
    /**
582
     * @return SearchResultSet
583
     */
584
    public function getLastResultSet()
585
    {
586
        return $this->lastResultSet;
587
    }
588
589
    /**
590 3
     * This method returns true when the last search was executed with an empty query
591
     * string or whitespaces only. When no search was triggered it will return false.
592 3
     *
593 3
     * @return bool
594
     */
595
    public function getLastSearchWasExecutedWithEmptyQueryString()
596
    {
597
        $wasEmptyQueryString = false;
598 26
        if ($this->lastResultSet != null) {
599
            $wasEmptyQueryString = $this->lastResultSet->getUsedSearchRequest()->getRawUserQueryIsEmptyString();
600 26
        }
601
602
        return $wasEmptyQueryString;
603
    }
604
605
    /**
606 2
     * @param int $requestedPerPage
607
     */
608 2
    protected function setPerPageInSession($requestedPerPage)
609
    {
610
        $GLOBALS['TSFE']->fe_user->setKey('ses', 'tx_solr_resultsPerPage', intval($requestedPerPage));
611
    }
612
613
    /**
614 26
     * @return mixed
615
     */
616 26
    protected function getPerPageFromSession()
617
    {
618
        return $GLOBALS['TSFE']->fe_user->getKey('ses', 'tx_solr_resultsPerPage');
619
    }
620
621
    /**
622
     * @return bool
623
     */
624
    protected function getInitialSearchIsConfigured()
625 33
    {
626
        return $this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialEmptyQuery() || $this->typoScriptConfiguration->getSearchInitializeWithQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialQuery();
627 33
    }
628 5
629
    /**
630
     * @return mixed
631 28
     */
632 25
    protected function getRegisteredSearchComponents()
633
    {
634 28
        return GeneralUtility::makeInstance(SearchComponentManager::class)->getSearchComponents();
635
    }
636
637
    /**
638
     * This method is used to reference the SearchResult object from the response in the SearchResultSet object.
639
     *
640
     * @param \Apache_Solr_Response $response
641
     * @param SearchResultSet $resultSet
642
     */
643
    protected function addSearchResultsToResultSet($response, $resultSet)
644
    {
645
        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...
646
            return;
647
        }
648
649
        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...
650
            $resultSet->addSearchResult($searchResult);
651
        }
652
    }
653
}
654