Passed
Pull Request — master (#1638)
by Timo
04:21
created

wrapResultDocumentInResultObject()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 15
ccs 11
cts 11
cp 1
rs 9.4285
cc 3
eloc 8
nc 3
nop 1
crap 3
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 46
     * @param SearchResultBuilder $resultBuilder
104
     */
105 46
    public function __construct(TypoScriptConfiguration $configuration, Search $search, SolrLogManager $solrLogManager = null, SearchResultBuilder $resultBuilder = null)
106 46
    {
107 46
        $this->search = $search;
108 46
        $this->typoScriptConfiguration = $configuration;
109
        $this->logger = is_null($solrLogManager) ? GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__) : $solrLogManager;
110
        $this->searchResultBuilder = is_null($resultBuilder) ? GeneralUtility::makeInstance(SearchResultBuilder::class) : $resultBuilder;
111
    }
112
113
    /**
114 30
     * @param bool $useCache
115
     * @return bool
116 30
     */
117 30
    public function getIsSolrAvailable($useCache = true)
118
    {
119
        $this->isSolrAvailable = $this->search->ping($useCache);
120
        return $this->isSolrAvailable;
121
    }
122
123 30
    /**
124
     * @return bool
125 30
     */
126
    public function getHasSearched()
127
    {
128
        return $this->search->hasSearched();
129
    }
130
131
    /**
132
     * Retrieves the used search instance.
133 2
     *
134
     * @return Search
135 2
     */
136
    public function getSearch()
137
    {
138
        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
    protected function getPreparedQuery($rawQuery, $resultsPerPage)
150
    {
151
        /* @var $query Query */
152
        $query = $this->getQueryInstance($rawQuery);
153
154
        $this->applyPageSectionsRootLineFilter($query);
155
156
        if ($this->typoScriptConfiguration->getLoggingQuerySearchWords()) {
157
            $this->logger->log(
158
                SolrLogManager::INFO,
159
                'Received search query',
160
                [
161
                    $rawQuery
162 38
                ]
163
            );
164
        }
165 38
166
        $query->setResultsPerPage($resultsPerPage);
167 38
168
        if ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
169 38
            // empty main query, but using a "return everything"
170
            // alternative query in q.alt
171
            $query->setAlternativeQuery('*:*');
172
        }
173
174
        if ($this->typoScriptConfiguration->getSearchInitializeWithQuery()) {
175
            $query->setAlternativeQuery($this->typoScriptConfiguration->getSearchInitializeWithQuery());
176
        }
177
178
        foreach ($this->getAdditionalFilters() as $additionalFilter) {
179 38
            $query->getFilters()->add($additionalFilter);
180
        }
181 38
182
        return $query;
183
    }
184 31
185
    /**
186
     * @param Query $query
187 38
     * @param SearchRequest $searchRequest
188 3
     */
189
    protected function initializeRegisteredSearchComponents(Query $query, SearchRequest $searchRequest)
190
    {
191 38
        $searchComponents = $this->getRegisteredSearchComponents();
192 2
193
        foreach ($searchComponents as $searchComponent) {
194
            /** @var Search\SearchComponent $searchComponent */
195 38
            $searchComponent->setSearchConfiguration($this->typoScriptConfiguration->getSearchConfiguration());
196
197
            if ($searchComponent instanceof QueryAware) {
198
                $searchComponent->setQuery($query);
199
            }
200
201
            if ($searchComponent instanceof SearchRequestAware) {
202 38
                $searchComponent->setSearchRequest($searchRequest);
203
            }
204 38
205
            $searchComponent->initializeSearchComponent();
206 38
        }
207
    }
208 32
209
    /**
210 32
     * Does post processing of the response.
211 32
     *
212
     * @param \Apache_Solr_Response $response The search's response.
213
     */
214 32
    protected function processResponse(\Apache_Solr_Response $response)
215 31
    {
216
        $this->wrapResultDocumentInResultObject($response);
217
    }
218 32
219
    /**
220 38
     * 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 38
    protected function wrapResultDocumentInResultObject(\Apache_Solr_Response $response)
232
    {
233 38
        $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...
234 38
235 38
        if (!is_array($documents)) {
236 4
            return;
237 4
        }
238
239
        foreach ($documents as $key => $originalDocument) {
240 38
            $result = $this->searchResultBuilder->fromApacheSolrDocument($originalDocument);
241 38
            $documents[$key] = $result;
242
        }
243 38
244 38
        $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...
245 3
    }
246
247
    /**
248 38
     * @return string
249
     */
250
    protected function getResultSetClassName()
251
    {
252 2
        return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName ']) ?
253
            $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName '] : SearchResultSet::class;
254
    }
255 38
256
    /**
257
     * Initializes additional filters configured through TypoScript and
258
     * Flexforms for use in regular queries and suggest queries.
259
     *
260
     * @param Query $query
261
     * @return void
262
     */
263
    protected function applyPageSectionsRootLineFilter(Query $query)
264 40
    {
265
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
266 40
        if (count($searchQueryFilters) <= 0) {
267 40
            return;
268
        }
269 40
270 40
        // special filter to limit search to specific page tree branches
271
        if (array_key_exists('__pageSections', $searchQueryFilters)) {
272
            $query->setRootlineFilter($searchQueryFilters['__pageSections']);
273
            $this->typoScriptConfiguration->removeSearchQueryFilterForPageSections();
274
        }
275
    }
276
277
    /**
278
     * Retrieves the configuration filters from the TypoScript configuration, except the __pageSections filter.
279 40
     *
280
     * @return array
281 40
     */
282 1
    public function getAdditionalFilters()
283
    {
284 1
        // when we've build the additionalFilter once, we could return them
285 1
        if (count($this->additionalFilters) > 0) {
286 1
            return $this->additionalFilters;
287 1
        }
288
289
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
290
        if (count($searchQueryFilters) <= 0) {
291 40
            return [];
292
        }
293
294
        $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
295
296
        // all other regular filters
297
        foreach ($searchQueryFilters as $filterKey => $filter) {
298
            // the __pageSections filter should not be handled as additional filter
299 40
            if ($filterKey === '__pageSections') {
300
                continue;
301 40
            }
302 5
303
            $filterIsArray = is_array($searchQueryFilters[$filterKey]);
304
            if ($filterIsArray) {
305 35
                continue;
306 32
            }
307
308
            $hasSubConfiguration = is_array($searchQueryFilters[$filterKey . '.']);
309 3
            if ($hasSubConfiguration) {
310 3
                $filter = $cObj->stdWrap($searchQueryFilters[$filterKey], $searchQueryFilters[$filterKey . '.']);
311
            }
312 2
313 2
            $this->additionalFilters[$filterKey] = $filter;
314
        }
315
316 2
        return $this->additionalFilters;
317
    }
318
319
    /**
320 2
     * Performs a search and returns a SearchResultSet.
321 2
     *
322
     * @param SearchRequest $searchRequest
323
     * @return SearchResultSet
324
     */
325 2
    public function search(SearchRequest $searchRequest)
326 2
    {
327 2
        /** @var $resultSet SearchResultSet */
328 2
        $resultSetClass = $this->getResultSetClassName();
329
        $resultSet = GeneralUtility::makeInstance($resultSetClass);
330 2
        $resultSet->setUsedSearchRequest($searchRequest);
331 2
        $this->lastResultSet = $resultSet;
332 2
333
        $resultSet = $this->handleSearchHook('beforeSearch', $resultSet);
334 2
335
        if ($searchRequest->getRawUserQueryIsNull() && !$this->getInitialSearchIsConfigured()) {
336
            // when no rawQuery was passed or no initialSearch is configured, we pass an empty result set
337 3
            return $resultSet;
338
        }
339
340
        if ($searchRequest->getRawUserQueryIsEmptyString() && !$this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
341
            // the user entered an empty query string "" or "  " and empty querystring is not allowed
342
            return $resultSet;
343
        }
344
345
        $rawQuery = $searchRequest->getRawUserQuery();
346
        $resultsPerPage = (int)$searchRequest->getResultsPerPage();
347
        $query = $this->getPreparedQuery($rawQuery, $resultsPerPage);
348
        $this->initializeRegisteredSearchComponents($query, $searchRequest);
349
        $resultSet->setUsedQuery($query);
350
351 40
        // the offset mulitplier is page - 1 but not less then zero
352
        $offsetMultiplier = max(0, $searchRequest->getPage() - 1);
353
        $offSet = $offsetMultiplier * $resultsPerPage;
354 40
355 1
        // performing the actual search, sending the query to the Solr server
356
        $query = $this->modifyQuery($query, $searchRequest, $this->search);
357
        $response = $this->doASearch($query, $offSet);
358
359
        if ($resultsPerPage === 0) {
360 1
            // when resultPerPage was forced to 0 we also set the numFound to 0 to hide results, e.g.
361
            // when results for the initial search should not be shown.
362
            $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...
363
        }
364 1
365 1
        $this->processResponse($response);
366 1
        $this->addSearchResultsToResultSet($response, $resultSet);
367 1
368 1
        $resultSet->setResponse($response);
369
        $resultSet->setUsedPage((int)$searchRequest->getPage());
370 1
        $resultSet->setUsedResultsPerPage($resultsPerPage);
371
        $resultSet->setUsedAdditionalFilters($this->getAdditionalFilters());
372
        $resultSet->setUsedSearch($this->search);
373 40
374 5
        /** @var $variantsProcessor VariantsProcessor */
375
        $variantsProcessor = GeneralUtility::makeInstance(VariantsProcessor::class, $this->typoScriptConfiguration, $this->searchResultBuilder);
376
        $variantsProcessor->process($resultSet);
377 35
378 29
        /** @var $searchResultReconstitutionProcessor ResultSetReconstitutionProcessor */
379 29
        $searchResultReconstitutionProcessor = GeneralUtility::makeInstance(ResultSetReconstitutionProcessor::class);
380
        $searchResultReconstitutionProcessor->process($resultSet);
381
382 35
        $resultSet = $this->getAutoCorrection($resultSet);
383 35
384
        return $this->handleSearchHook('afterSearch', $resultSet);
385
    }
386
387
    /**
388
     * Executes the search and builds a fake response for a current bug in Apache Solr 6.3
389
     *
390
     * @param Query $query
391
     * @param int $offSet
392
     * @throws SolrCommunicationException
393 29
     * @return \Apache_Solr_Response
394
     */
395 29
    protected function doASearch($query, $offSet)
396 29
    {
397 29
        try {
398
            $response = $this->search->search($query, $offSet, null);
399
        } catch (SolrInternalServerErrorException $e) {
400
            // when variants are enable and the index is empty, we get a parse exception, because of a
401 29
            // Apache Solr Bug.
402
            // see: https://github.com/TYPO3-Solr/ext-solr/issues/668
403
            // @todo this try/catch block can be removed after upgrading to Apache Solr 6.4
404
            if (!$this->typoScriptConfiguration->getSearchVariants()) {
405
                throw $e;
406
            }
407 29
408
            $response = $e->getSolrResponse();
409 29
            $response->response = new \stdClass();
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...
410 29
            $response->spellcheck = [];
0 ignored issues
show
Bug introduced by
The property spellcheck does not seem to exist in Apache_Solr_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...
411
            $response->debug = [];
0 ignored issues
show
Bug introduced by
The property debug does not seem to exist in Apache_Solr_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...
412
            $response->responseHeader = [];
0 ignored issues
show
Bug introduced by
The property responseHeader does not seem to exist in Apache_Solr_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...
413
            $response->facet_counts = [];
0 ignored issues
show
Bug introduced by
The property facet_counts does not seem to exist in Apache_Solr_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...
414
            $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...
415
        }
416 40
417
        if($response === null) {
418 40
            throw new SolrIncompleteResponseException('The response retrieved from solr was incomplete', 1505989678);
419 40
        }
420
421
        return $response;
422
    }
423
424
    /**
425
     * @param SearchResultSet $searchResultSet
426
     * @return SearchResultSet
427
     */
428 38
    protected function getAutoCorrection(SearchResultSet $searchResultSet)
429
    {
430 38
        // no secondary search configured
431
        if (!$this->typoScriptConfiguration->getSearchSpellcheckingSearchUsingSpellCheckerSuggestion()) {
432
            return $searchResultSet;
433
        }
434
435
        // more then zero results
436
        if ($searchResultSet->getAllResultCount() > 0) {
437
            return $searchResultSet;
438
        }
439
440 38
        // no corrections present
441
        if (!$searchResultSet->getHasSpellCheckingSuggestions()) {
442 38
            return $searchResultSet;
443 38
        }
444 36
445
        $searchResultSet = $this->peformAutoCorrection($searchResultSet);
446
447
        return $searchResultSet;
448 2
    }
449
450
    /**
451
     * @param SearchResultSet $searchResultSet
452 2
     * @return SearchResultSet
453
     */
454
    protected function peformAutoCorrection(SearchResultSet $searchResultSet)
455
    {
456
        $searchRequest = $searchResultSet->getUsedSearchRequest();
457
        $suggestions = $searchResultSet->getSpellCheckingSuggestions();
458
459 43
        $maximumRuns = $this->typoScriptConfiguration->getSearchSpellcheckingNumberOfSuggestionsToTry(1);
460
        $runs = 0;
461
462 43
        foreach ($suggestions as $suggestion) {
463 2
            $runs++;
464
465
            $correction = $suggestion->getSuggestion();
466 43
            $initialQuery = $searchRequest->getRawUserQuery();
467 43
468 41
            $searchRequest->setRawQueryString($correction);
469
            $searchResultSet = $this->search($searchRequest);
470
            if ($searchResultSet->getAllResultCount() > 0) {
471 2
                $searchResultSet->setIsAutoCorrected(true);
472
                $searchResultSet->setCorrectedQueryString($correction);
473
                $searchResultSet->setInitialQueryString($initialQuery);
474 2
                break;
475
            }
476 2
477
            if ($runs > $maximumRuns) {
478
                break;
479
            }
480 2
        }
481 2
        return $searchResultSet;
482
    }
483
484
    /**
485 2
     * Allows to modify a query before eventually handing it over to Solr.
486 2
     *
487
     * @param Query $query The current query before it's being handed over to Solr.
488
     * @param SearchRequest $searchRequest The searchRequest, relevant in the current context
489
     * @param Search $search The search, relevant in the current context
490 2
     * @throws \UnexpectedValueException
491
     * @return Query The modified query that is actually going to be given to Solr.
492
     */
493 2
    protected function modifyQuery(Query $query, SearchRequest $searchRequest, Search $search)
494
    {
495
        // hook to modify the search query
496
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifySearchQuery'])) {
497
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['modifySearchQuery'] as $classReference) {
498
                $queryModifier = GeneralUtility::getUserObj($classReference);
499
500
                if ($queryModifier instanceof Modifier) {
501
                    if ($queryModifier instanceof SearchAware) {
502 40
                        $queryModifier->setSearch($search);
503
                    }
504
505 40
                    if ($queryModifier instanceof SearchRequestAware) {
506 40
                        $queryModifier->setSearchRequest($searchRequest);
507 40
                    }
508 40
509
                    $query = $queryModifier->modifyQuery($query);
510 40
                } else {
511
                    throw new \UnexpectedValueException(
512 40
                        get_class($queryModifier) . ' must implement interface ' . Modifier::class,
513
                        1310387414
514 2
                    );
515
                }
516
            }
517 38
        }
518
519
        return $query;
520
    }
521
522 38
    /**
523 38
     * Retrieves a single document from solr by document id.
524 38
     *
525 38
     * @param string $documentId
526 38
     * @return SearchResult
527
     */
528 38
    public function getDocumentById($documentId)
529
    {
530 38
        /* @var $query Query */
531 4
        $query = GeneralUtility::makeInstance(Query::class, $documentId);
532
        $query->setQueryFields(QueryFields::fromString('id'));
533
534 38
        $response = $this->search->search($query, 0, 1);
535
        $this->processResponse($response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $this->search->search($query, 0, 1) on line 534 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...
536
537 38
        $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...
538 38
        return $resultDocument;
539 38
    }
540
541 38
    /**
542
     * This method is used to call the registered hooks during the search execution.
543
     *
544 2
     * @param string $eventName
545
     * @param SearchResultSet $resultSet
546
     * @return SearchResultSet
547 38
     */
548
    private function handleSearchHook($eventName, SearchResultSet $resultSet)
549 38
    {
550
        if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName])) {
551 38
            return $resultSet;
552 38
        }
553 38
554 38
        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName] as $classReference) {
555 38
            $afterSearchProcessor = GeneralUtility::getUserObj($classReference);
556
            if ($afterSearchProcessor instanceof SearchResultSetProcessor) {
557
                $afterSearchProcessor->process($resultSet);
558 38
            }
559 38
        }
560
561 38
        return $resultSet;
562
    }
563 38
564
    /**
565
     * @return SearchResultSet
566
     */
567
    public function getLastResultSet()
568
    {
569
        return $this->lastResultSet;
570 38
    }
571
572
    /**
573 38
     * This method returns true when the last search was executed with an empty query
574 37
     * string or whitespaces only. When no search was triggered it will return false.
575
     *
576
     * @return bool
577
     */
578 1
    public function getLastSearchWasExecutedWithEmptyQueryString()
579 1
    {
580
        $wasEmptyQueryString = false;
581
        if ($this->lastResultSet != null) {
582
            $wasEmptyQueryString = $this->lastResultSet->getUsedSearchRequest()->getRawUserQueryIsEmptyString();
583 1
        }
584
585
        return $wasEmptyQueryString;
586
    }
587 1
588
    /**
589 1
     * @return bool
590
     */
591
    protected function getInitialSearchIsConfigured()
592
    {
593
        return $this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialEmptyQuery() || $this->typoScriptConfiguration->getSearchInitializeWithQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialQuery();
594
    }
595
596 1
    /**
597
     * @return mixed
598 1
     */
599 1
    protected function getRegisteredSearchComponents()
600
    {
601 1
        return GeneralUtility::makeInstance(SearchComponentManager::class)->getSearchComponents();
602 1
    }
603
604 1
    /**
605 1
     * This method is used to reference the SearchResult object from the response in the SearchResultSet object.
606
     *
607 1
     * @param \Apache_Solr_Response $response
608 1
     * @param SearchResultSet $resultSet
609
     */
610 1
    protected function addSearchResultsToResultSet($response, $resultSet)
611 1
    {
612 1
        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...
613 1
            return;
614 1
        }
615 1
616 1
        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...
617
            $resultSet->addSearchResult($searchResult);
618
        }
619
    }
620
621
    /**
622
     * @param string $rawQuery
623 1
     * @return Query|object
624
     */
625
    protected function getQueryInstance($rawQuery)
626
    {
627
        $query = GeneralUtility::makeInstance(Query::class, $rawQuery, $this->typoScriptConfiguration);
628
        return $query;
629
    }
630
631
}
632