Passed
Push — master ( fe60d3...0720cb )
by Timo
05:22
created

wrapResultDocumentInResultObject()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 15
ccs 6
cts 7
cp 0.8571
rs 9.4285
cc 3
eloc 8
nc 3
nop 1
crap 3.0261
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\Plugin\PluginAware;
30
use ApacheSolrForTypo3\Solr\Query;
31
use ApacheSolrForTypo3\Solr\Response\Processor\ResponseProcessor;
32
use ApacheSolrForTypo3\Solr\Search;
33
use ApacheSolrForTypo3\Solr\Search\QueryAware;
34
use ApacheSolrForTypo3\Solr\Search\SearchComponentManager;
35
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration;
36
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
37
use TYPO3\CMS\Core\SingletonInterface;
38
use TYPO3\CMS\Core\Utility\GeneralUtility;
39
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
40
use TYPO3\CMS\Frontend\Plugin\AbstractPlugin;
41
use Apache_Solr_ParserException;
42
43
/**
44
 * The SearchResultSetService is responsible to build a SearchResultSet from a SearchRequest.
45
 * It encapsulates the logic to trigger a search in order to be able to reuse it in multiple places.
46
 *
47
 * @author Timo Schmidt <[email protected]>
48
 */
49
class SearchResultSetService implements SingletonInterface
50
{
51
    /**
52
     * Additional filters, which will be added to the query, as well as to
53
     * suggest queries.
54
     *
55
     * @var array
56
     */
57
    protected $additionalFilters = [];
58
59
    /**
60
     * Track, if the number of results per page has been changed by the current request
61
     *
62
     * @var bool
63
     */
64
    protected $resultsPerPageChanged = false;
65
66
    /**
67
     * @var \ApacheSolrForTypo3\Solr\Search
68
     */
69
    protected $search;
70
71
    /**
72
     * @var SearchResultSet
73
     */
74
    protected $lastResultSet = null;
75
76
    /**
77
     * @var AbstractPlugin
78
     */
79
    protected $parentPlugin;
80
81
    /**
82
     * @var bool
83
     */
84
    protected $useQueryAwareComponents = true;
85
86
    /**
87
     * @var bool
88
     */
89
    protected $usePluginAwareComponents = true;
90
91
    /**
92
     * @var
93
     */
94
    protected $isSolrAvailable = false;
95
96
    /**
97
     * @var TypoScriptConfiguration
98
     */
99
    protected $typoScriptConfiguration;
100
101
    /**
102
     * @var \ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
103
     */
104
    protected $logger = null;
105
106
    /**
107
     * @param TypoScriptConfiguration $configuration
108
     * @param Search $search
109
     * @param AbstractPlugin $parentPlugin (optional parent plugin, needed for plugin aware components)
110
     */
111 37
    public function __construct(TypoScriptConfiguration $configuration, Search $search, AbstractPlugin $parentPlugin = null)
112
    {
113 37
        $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__);
114 37
        $this->search = $search;
115 37
        $this->typoScriptConfiguration = $configuration;
116 37
        $this->parentPlugin = $parentPlugin;
117 37
    }
118
119
    /**
120
     * @return AbstractPlugin
121
     */
122 1
    public function getParentPlugin()
123
    {
124 1
        return $this->parentPlugin;
125
    }
126
127
    /**
128
     * @param bool $useCache
129
     * @return bool
130
     */
131 25
    public function getIsSolrAvailable($useCache = true)
132
    {
133 25
        $this->isSolrAvailable = $this->search->ping($useCache);
134 25
        return $this->isSolrAvailable;
135
    }
136
137
    /**
138
     * @return bool
139
     */
140 25
    public function getHasSearched()
141
    {
142 25
        return $this->search->hasSearched();
143
    }
144
145
    /**
146
     * Retrieves the used search instance.
147
     *
148
     * @return Search
149
     */
150 25
    public function getSearch()
151
    {
152 25
        return $this->search;
153
    }
154
155
    /**
156
     * @param bool $usePluginAwareComponents
157
     */
158
    public function setUsePluginAwareComponents($usePluginAwareComponents)
159
    {
160
        $this->usePluginAwareComponents = $usePluginAwareComponents;
161
    }
162
163
    /**
164
     * @return bool
165
     */
166
    public function getUsePluginAwareComponents()
167
    {
168
        return $this->usePluginAwareComponents;
169
    }
170
171
    /**
172
     * @param bool $useQueryAwareComponents
173
     */
174
    public function setUseQueryAwareComponents($useQueryAwareComponents)
175
    {
176
        $this->useQueryAwareComponents = $useQueryAwareComponents;
177
    }
178
179
    /**
180
     * @return bool
181
     */
182
    public function getUseQueryAwareComponents()
183
    {
184
        return $this->useQueryAwareComponents;
185
    }
186
187
    /**
188
     * Initializes the Query object and SearchComponents and returns
189
     * the initialized query object, when a search should be executed.
190
     *
191
     * @param string $rawQuery
192
     * @param int $resultsPerPage
193
     * @return Query
194
     */
195 31
    protected function getPreparedQuery($rawQuery, $resultsPerPage)
196
    {
197
        /* @var $query Query */
198 31
        $query = GeneralUtility::makeInstance(Query::class, $rawQuery);
199
200 31
        $this->applyPageSectionsRootLineFilter($query);
201
202 31
        if ($this->typoScriptConfiguration->getLoggingQuerySearchWords()) {
203
            $this->logger->log(
204
                SolrLogManager::INFO,
205
                'Received search query',
206
                [
207
                    $rawQuery
208
                ]
209
            );
210
        }
211
212 31
        $query->setResultsPerPage($resultsPerPage);
213
214 31
        $this->initializeRegisteredSearchComponents($query);
215
216 31
        if ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
217
            // empty main query, but using a "return everything"
218
            // alternative query in q.alt
219 24
            $query->setAlternativeQuery('*:*');
220
        }
221
222 31
        if ($this->typoScriptConfiguration->getSearchInitializeWithQuery()) {
223 3
            $query->setAlternativeQuery($this->typoScriptConfiguration->getSearchInitializeWithQuery());
224
        }
225
226 31
        foreach ($this->getAdditionalFilters() as $additionalFilter) {
227 2
            $query->addFilter($additionalFilter);
228
        }
229
230 31
        return $query;
231
    }
232
233
    /**
234
     * @param Query $query
235
     */
236 31
    protected function initializeRegisteredSearchComponents(Query $query)
237
    {
238 31
        $searchComponents = $this->getRegisteredSearchComponents();
239
240 31
        foreach ($searchComponents as $searchComponent) {
241
            /** @var Search\SearchComponent $searchComponent */
242 25
            $searchComponent->setSearchConfiguration($this->typoScriptConfiguration->getSearchConfiguration());
243
244 25
            if ($searchComponent instanceof QueryAware && $this->useQueryAwareComponents) {
245 25
                $searchComponent->setQuery($query);
246
            }
247
248 25
            if ($searchComponent instanceof PluginAware && $this->usePluginAwareComponents) {
249
                $searchComponent->setParentPlugin($this->parentPlugin);
250
            }
251
252 25
            $searchComponent->initializeSearchComponent();
253
        }
254 31
    }
255
256
    /**
257
     * Returns the number of results per Page.
258
     *
259
     * Also influences how many result documents are returned by the Solr
260
     * server as the return value is used in the Solr "rows" GET parameter.
261
     *
262
     * @param string $rawQuery
263
     * @param int|null $requestedPerPage
264
     * @return int number of results to show per page
265
     */
266 31
    protected function getNumberOfResultsPerPage($rawQuery, $requestedPerPage = null)
267
    {
268 31
        $perPageSwitchOptions = $this->typoScriptConfiguration->getSearchResultsPerPageSwitchOptionsAsArray();
269 31
        if (isset($requestedPerPage) && in_array($requestedPerPage, $perPageSwitchOptions)) {
270 1
            $this->setPerPageInSession($requestedPerPage);
271 1
            $this->resultsPerPageChanged = true;
272
        }
273
274 31
        $defaultResultsPerPage = $this->typoScriptConfiguration->getSearchResultsPerPage();
275 31
        $sessionResultPerPage = $this->getPerPageFromSession();
276
277 31
        $currentNumberOfResultsShown = $defaultResultsPerPage;
278 31
        if (!is_null($sessionResultPerPage) && in_array($sessionResultPerPage, $perPageSwitchOptions)) {
279
            $currentNumberOfResultsShown = (int)$sessionResultPerPage;
280
        }
281
282 31
        if ($this->shouldHideResultsFromInitialSearch($rawQuery)) {
283
            // initialize search with an empty query, which would by default return all documents
284
            // anyway, tell Solr to not return any result documents
285
            // Solr will still return facets though
286
            $currentNumberOfResultsShown = 0;
287
        }
288
289 31
        return $currentNumberOfResultsShown;
290
    }
291
292
    /**
293
     * Provides a hook for other classes to process the search's response.
294
     *
295
     * @param string $rawQuery
296
     * @param Query $query The query that has been searched for.
297
     * @param \Apache_Solr_Response $response The search's response.
298
     */
299 32
    protected function processResponse($rawQuery, Query $query, \Apache_Solr_Response &$response)
300
    {
301 32
        if ($this->shouldHideResultsFromInitialSearch($rawQuery)) {
302
            // explicitly set number of results to 0 as we just wanted
303
            // facets and the like according to configuration
304
            // @see getNumberOfResultsPerPage()
305
            $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...
306
        }
307
308 32
        $this->wrapResultDocumentInResultObject($response);
309 32
        $this->addExpandedDocumentsFromVariants($response);
310
311 32
        if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['processSearchResponse'])) {
312 21
            foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['processSearchResponse'] as $classReference) {
313 21
                $responseProcessor = GeneralUtility::getUserObj($classReference);
314 21
                if ($responseProcessor instanceof ResponseProcessor) {
315 21
                    $responseProcessor->processResponse($query, $response);
316
                }
317
            }
318
        }
319 32
    }
320
321
    /**
322
     * This method is used to add documents to the expanded documents of the SearchResult
323
     * when collapsing is configured.
324
     *
325
     * @param \Apache_Solr_Response $response
326
     */
327 32
    protected function addExpandedDocumentsFromVariants(\Apache_Solr_Response &$response)
328
    {
329 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...
330 5
            return;
331
        }
332
333 27
        if (!$this->typoScriptConfiguration->getSearchVariants()) {
334 24
            return;
335
        }
336
337 3
        $variantsField = $this->typoScriptConfiguration->getSearchVariantsField();
338 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...
339
            /** @var $resultDocument SearchResult */
340 2
            $variantField = $resultDocument->getField($variantsField);
341 2
            $variantId = isset($variantField['value']) ? $variantField['value'] : null;
342
343
                // when there is no value in the collapsing field, we can return
344 2
            if ($variantId === null) {
345
                continue;
346
            }
347
348 2
            $variantAccessKey = strtolower($variantId);
349 2
            if (!isset($response->{'expanded'}) || !isset($response->{'expanded'}->{$variantAccessKey})) {
350
                continue;
351
            }
352
353 2
            foreach ($response->{'expanded'}->{$variantAccessKey}->{'docs'} as $variantDocumentArray) {
354 2
                $variantDocument = new \Apache_Solr_Document();
355 2
                foreach (get_object_vars($variantDocumentArray) as $propertyName => $propertyValue) {
356 2
                    $variantDocument->{$propertyName} = $propertyValue;
357
                }
358 2
                $variantSearchResult = $this->wrapApacheSolrDocumentInResultObject($variantDocument);
359 2
                $variantSearchResult->setIsVariant(true);
360 2
                $variantSearchResult->setVariantParent($resultDocument);
361
362 2
                $resultDocument->addVariant($variantSearchResult);
363
            }
364
        }
365 3
    }
366
367
    /**
368
     * Wrap all results document it a custom EXT:solr SearchResult object.
369
     *
370
     * Can be overwritten:
371
     *
372
     * $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultClassName '] = ''
373
     *
374
     * to use a custom result object.
375
     *
376
     * @param \Apache_Solr_Response $response
377
     * @throws \Apache_Solr_ParserException
378
     */
379 32
    protected function wrapResultDocumentInResultObject(\Apache_Solr_Response &$response)
380
    {
381
        $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...
382 32
383 1
        if (!is_array($documents)) {
384
            return;
385
        }
386
387
        foreach ($documents as $key => $originalDocument) {
388 1
            $result = $this->wrapApacheSolrDocumentInResultObject($originalDocument);
389
            $documents[$key] = $result;
390
        }
391
392 1
        $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...
393 1
    }
394 1
395 1
    /**
396 1
     * This method is used to wrap the \Apache_Solr_Document instance in an instance of the configured SearchResult
397
     * class.
398 1
     *
399
     * @param \Apache_Solr_Document $originalDocument
400
     * @throws \InvalidArgumentException
401 32
     * @return SearchResult
402 5
     */
403
    protected function wrapApacheSolrDocumentInResultObject(\Apache_Solr_Document $originalDocument)
404
    {
405 27
        $searchResultClassName = $this->getResultClassName();
406 24
        $result = GeneralUtility::makeInstance($searchResultClassName, $originalDocument);
407 24
        if (!$result instanceof SearchResult) {
408
            throw new \InvalidArgumentException('Could not create result object with class: ' . (string)$searchResultClassName, 1470037679);
409
        }
410 27
411 27
        return $result;
412
    }
413
414
    /**
415
     * @return string
416
     */
417
    protected function getResultClassName()
418
    {
419
        return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultClassName ']) ?
420
            $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultClassName '] : SearchResult::class;
421 24
    }
422
423 24
    /**
424 24
     * @return string
425 24
     */
426
    protected function getResultSetClassName()
427
    {
428
        return isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName ']) ?
429 24
            $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['searchResultSetClassName '] : SearchResultSet::class;
430
    }
431
432
    /**
433
     * Checks it the results should be hidden in the response.
434
     *
435 24
     * @param string $rawQuery
436
     * @return bool
437 24
     */
438 24
    protected function shouldHideResultsFromInitialSearch($rawQuery)
439
    {
440
        return ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchInitializeWithQuery()) && !$this->typoScriptConfiguration->getSearchShowResultsOfInitialEmptyQuery() && !$this->typoScriptConfiguration->getSearchShowResultsOfInitialQuery() && $rawQuery === null;
441
    }
442
443
    /**
444 34
     * Initializes additional filters configured through TypoScript and
445
     * Flexforms for use in regular queries and suggest queries.
446 34
     *
447 34
     * @param Query $query
448
     * @return void
449
     */
450
    protected function applyPageSectionsRootLineFilter(Query $query)
451
    {
452
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
453
        if (count($searchQueryFilters) <= 0) {
454
            return;
455
        }
456 32
457
        // special filter to limit search to specific page tree branches
458 32
        if (array_key_exists('__pageSections', $searchQueryFilters)) {
459
            $query->setRootlineFilter($searchQueryFilters['__pageSections']);
460
            $this->typoScriptConfiguration->removeSearchQueryFilterForPageSections();
461
        }
462
    }
463
464
    /**
465
     * Retrieves the configuration filters from the TypoScript configuration, except the __pageSections filter.
466
     *
467
     * @return array
468 31
     */
469
    public function getAdditionalFilters()
470 31
    {
471 31
        // when we've build the additionalFilter once, we could return them
472 29
        if (count($this->additionalFilters) > 0) {
473
            return $this->additionalFilters;
474
        }
475
476 2
        $searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
477
        if (count($searchQueryFilters) <= 0) {
478
            return [];
479
        }
480 2
481
        $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
482
483
        // all other regular filters
484
        foreach ($searchQueryFilters as $filterKey => $filter) {
485
            // the __pageSections filter should not be handled as additional filter
486
            if ($filterKey === '__pageSections') {
487 36
                continue;
488
            }
489
490 36
            $filterIsArray = is_array($searchQueryFilters[$filterKey]);
491 2
            if ($filterIsArray) {
492
                continue;
493
            }
494 36
495 36
            $hasSubConfiguration = is_array($searchQueryFilters[$filterKey . '.']);
496 33
            if ($hasSubConfiguration) {
497
                $filter = $cObj->stdWrap($searchQueryFilters[$filterKey], $searchQueryFilters[$filterKey . '.']);
498
            }
499 3
500
            $this->additionalFilters[$filterKey] = $filter;
501
        }
502 3
503
        return $this->additionalFilters;
504 3
    }
505
506
    /**
507
     * Performs a search and returns a SearchResultSet.
508 3
     *
509 3
     * @param SearchRequest $searchRequest
510
     * @return SearchResultSet
511
     */
512
    public function search(SearchRequest $searchRequest)
513 3
    {
514 3
        /** @var $resultSet SearchResultSet */
515
        $resultSetClass = $this->getResultSetClassName();
516
        $resultSet = GeneralUtility::makeInstance($resultSetClass);
517
        $resultSet->setUsedSearchRequest($searchRequest);
518 3
        $this->lastResultSet = $resultSet;
519
520
        $resultSet = $this->handleSearchHook('beforeSearch', $resultSet);
521 3
522
        if ($searchRequest->getRawUserQueryIsNull() && !$this->getInitialSearchIsConfigured()) {
523
            // when no rawQuery was passed or no initialSearch is configured, we pass an empty result set
524
            return $resultSet;
525
        }
526
527
        if ($searchRequest->getRawUserQueryIsEmptyString() && !$this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
528
            // the user entered an empty query string "" or "  " and empty querystring is not allowed
529
            return $resultSet;
530 34
        }
531
532
        $rawQuery = $searchRequest->getRawUserQuery();
533 34
        $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...
534 34
        $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...
535 34
536 34
        $resultSet->setUsedQuery($query);
537
538 34
        $currentPage = max(0, $searchRequest->getPage());
539
        // if the number of results per page has been changed by the current request, reset the pagebrowser
540 34
        if ($this->resultsPerPageChanged) {
541
            $currentPage = 0;
542 1
        }
543
544
        $offSet = $currentPage * $resultsPerPage;
545 33
        // performing the actual search, sending the query to the Solr server
546
        $response = $this->search->search($query, $offSet, null);
547 2
548
        $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...
549
        $this->addSearchResultsToResultSet($response, $resultSet);
550 31
551 31
        $resultSet->setResponse($response);
552 31
        $resultSet->setUsedPage($currentPage);
553
        $resultSet->setUsedResultsPerPage($resultsPerPage);
554 31
        $resultSet->setUsedAdditionalFilters($this->getAdditionalFilters());
555
        $resultSet->setUsedSearch($this->search);
556 31
557
        return $this->handleSearchHook('afterSearch', $resultSet);
558 31
    }
559 1
560
    /**
561
     * Retrieves a single document from solr by document id.
562 31
     *
563
     * @param string $documentId
564 31
     * @return SearchResult
565
     */
566 31
    public function getDocumentById($documentId)
567 31
    {
568
        /* @var $query Query */
569 31
        $query = GeneralUtility::makeInstance(Query::class, $documentId);
570 31
        $query->setQueryFieldsFromString('id');
571 31
572 31
        $response = $this->search->search($query, 0, 1);
573 31
        $this->processResponse($documentId, $query, $response);
574
575 31
        $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...
576
        return $resultDocument;
577
    }
578
579
    /**
580
     * This method is used to call the registered hooks during the search execution.
581
     *
582
     * @param string $eventName
583
     * @param SearchResultSet $resultSet
584 1
     * @return SearchResultSet
585
     */
586
    private function handleSearchHook($eventName, SearchResultSet $resultSet)
587 1
    {
588 1
        if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName])) {
589
            return $resultSet;
590 1
        }
591 1
592
        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr'][$eventName] as $classReference) {
593 1
            $afterSearchProcessor = GeneralUtility::getUserObj($classReference);
594 1
            if ($afterSearchProcessor instanceof SearchResultSetProcessor) {
595
                $afterSearchProcessor->process($resultSet);
596
            }
597
        }
598
599
        return $resultSet;
600
    }
601
602
    /**
603
     * @return SearchResultSet
604 34
     */
605
    public function getLastResultSet()
606 34
    {
607 34
        return $this->lastResultSet;
608
    }
609
610
    /**
611
     * This method returns true when the last search was executed with an empty query
612
     * string or whitespaces only. When no search was triggered it will return false.
613
     *
614
     * @return bool
615
     */
616
    public function getLastSearchWasExecutedWithEmptyQueryString()
617
    {
618
        $wasEmptyQueryString = false;
619
        if ($this->lastResultSet != null) {
620
            $wasEmptyQueryString = $this->lastResultSet->getUsedSearchRequest()->getRawUserQueryIsEmptyString();
621
        }
622
623 19
        return $wasEmptyQueryString;
624
    }
625 19
626
    /**
627
     * @param int $requestedPerPage
628
     */
629
    protected function setPerPageInSession($requestedPerPage)
630
    {
631
        $GLOBALS['TSFE']->fe_user->setKey('ses', 'tx_solr_resultsPerPage', intval($requestedPerPage));
632
    }
633
634 25
    /**
635
     * @return mixed
636 25
     */
637 25
    protected function getPerPageFromSession()
638 23
    {
639
        return $GLOBALS['TSFE']->fe_user->getKey('ses', 'tx_solr_resultsPerPage');
640
    }
641 25
642
    /**
643
     * @return bool
644
     */
645
    protected function getInitialSearchIsConfigured()
646
    {
647
        return $this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialEmptyQuery() || $this->typoScriptConfiguration->getSearchInitializeWithQuery() || $this->typoScriptConfiguration->getSearchShowResultsOfInitialQuery();
648
    }
649
650
    /**
651
     * @return mixed
652
     */
653
    protected function getRegisteredSearchComponents()
654
    {
655 24
        return GeneralUtility::makeInstance(SearchComponentManager::class)->getSearchComponents();
656
    }
657 24
658
    /**
659
     * This method is used to reference the SearchResult object from the response in the SearchResultSet object.
660
     *
661
     * @param \Apache_Solr_Response $response
662
     * @param SearchResultSet $resultSet
663 2
     */
664
    protected function addSearchResultsToResultSet($response, $resultSet)
665 2
    {
666
        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...
667
            return;
668
        }
669
670
        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...
671 24
            $resultSet->addSearchResult($searchResult);
672
        }
673 24
    }
674
}
675