Completed
Branch master (b9fc31)
by Timo
05:19
created

SearchResultSetService::getIsSolrAvailable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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