Passed
Push — master ( a95893...a4d2df )
by Timo
57s
created

getFacetParserRegistry()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Domain\Search\ResultSet;
3
4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
 * It is free software; you can redistribute it and/or modify it under
8
 * the terms of the GNU General Public License, either version 2
9
 * of the License, or any later version.
10
 *
11
 * For the full copyright and license information, please read the
12
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
 * The TYPO3 project - inspiring people to share!
15
 */
16
use ApacheSolrForTypo3\Solr\Domain\Search\LastSearches\LastSearchesService;
17
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Facets\FacetParserRegistry;
18
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Sorting\Sorting;
19
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Spellchecking\Suggestion;
20
use TYPO3\CMS\Core\Utility\GeneralUtility;
21
use TYPO3\CMS\Extbase\Object\ObjectManager;
22
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
23
24
/**
25
 * This processor is used to transform the solr response into a
26
 * domain object hierarchy that can be used in the application (controller and view).
27
 *
28
 * @todo: the logic in this class can go into the SearchResultSetService after moving the
29
 * code of EXT:solrfluid to EXT:solr
30
 *
31
 * @author Frans Saris <[email protected]>
32
 * @author Timo Hund <[email protected]>
33
 * @package ApacheSolrForTypo3\Solr\Domain\Search\ResultSet
34
 */
35
class ResultSetReconstitutionProcessor implements SearchResultSetProcessor
36
{
37
    /**
38
     * @var ObjectManagerInterface
39
     */
40
    protected $objectManager;
41
42
    /**
43
     * @return ObjectManagerInterface
44
     */
45 42
    public function getObjectManager()
46
    {
47 42
        if ($this->objectManager === null) {
48 21
            $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
49
        }
50 42
        return $this->objectManager;
51
    }
52
53
    /**
54
     * @param ObjectManagerInterface $objectManager
55
     */
56 21
    public function setObjectManager($objectManager)
57
    {
58 21
        $this->objectManager = $objectManager;
59 21
    }
60
61
62
    /**
63
     * @return FacetParserRegistry
64
     */
65 42
    protected function getFacetParserRegistry()
66
    {
67 42
        return $this->getObjectManager()->get(FacetParserRegistry::class);
68
    }
69
70
    /**
71
     * The implementation can be used to influence a SearchResultSet that is
72
     * created and processed in the SearchResultSetService.
73
     *
74
     * @param SearchResultSet $resultSet
75
     * @return SearchResultSet
76
     */
77 54
    public function process(SearchResultSet $resultSet)
78
    {
79 54
        if (!$resultSet instanceof SearchResultSet) {
80
            return $resultSet;
81
        }
82
83 54
        $resultSet = $this->parseResultCount($resultSet);
84 54
        $resultSet = $this->parseSpellCheckingResponseIntoObjects($resultSet);
85 54
        $resultSet = $this->parseSortingIntoObjects($resultSet);
86
87
        // here we can reconstitute other domain objects from the solr response
88 54
        $resultSet = $this->parseFacetsIntoObjects($resultSet);
89
90 54
        $this->storeLastSearches($resultSet);
91
92 54
        return $resultSet;
93
    }
94
95
    /**
96
     * @param SearchResultSet $resultSet
97
     * @return SearchResultSet
98
     */
99 54
    protected function parseResultCount(SearchResultSet $resultSet)
100
    {
101 54
        $response = $resultSet->getResponse();
102 54
        if (!isset($response->response->numFound)) {
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...
103 5
            return $resultSet;
104
        }
105
106 49
        $resultSet->setAllResultCount($response->response->numFound);
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...
107 49
        return $resultSet;
108
    }
109
110
    /**
111
     * @param SearchResultSet $resultSet
112
     * @return SearchResultSet
113
     */
114 54
    protected function parseSortingIntoObjects(SearchResultSet $resultSet)
115
    {
116 54
        $configuration = $resultSet->getUsedSearchRequest()->getContextTypoScriptConfiguration();
117 54
        $hasSorting = $resultSet->getUsedSearchRequest()->getHasSorting();
118 54
        $activeSortingName = $resultSet->getUsedSearchRequest()->getSortingName();
119 54
        $activeSortingDirection = $resultSet->getUsedSearchRequest()->getSortingDirection();
120
121
        // no configuration available
122 54
        if (!isset($configuration)) {
123 8
            return $resultSet;
124
        }
125
126
        // no sorting enabled
127 46
        if (!$configuration->getSearchSorting()) {
128 23
            return $resultSet;
129
        }
130 23
        foreach ($configuration->getSearchSortingOptionsConfiguration() as $sortingKeyName => $sortingOptions) {
131 23
            $sortingName = rtrim($sortingKeyName, '.');
132 23
            $selected = false;
133 23
            $direction = $configuration->getSearchSortingDefaultOrderBySortOptionName($sortingName);
134
135
            // when we have an active sorting in the request we compare the sortingName and mark is as active and
136
            // use the direction from the request
137 23
            if ($hasSorting && $activeSortingName == $sortingName) {
138 1
                $selected = true;
139 1
                $direction = $activeSortingDirection;
140
            }
141
142 23
            $field = $sortingOptions['field'];
143 23
            $label = $sortingOptions['label'];
144
145 23
            $isResetOption = $field === 'relevance';
146
            // @todo allow stdWrap on label
147 23
            $sorting = new Sorting($resultSet, $sortingName, $field, $direction, $label, $selected, $isResetOption);
148 23
            $resultSet->addSorting($sorting);
149
        }
150
151 23
        return $resultSet;
152
    }
153
154
    /**
155
     * @param SearchResultSet $resultSet
156
     * @return SearchResultSet
157
     */
158 54
    private function parseSpellCheckingResponseIntoObjects(SearchResultSet $resultSet)
159
    {
160
        //read the response
161 54
        $response = $resultSet->getResponse();
162 54
        if (!is_object($response->spellcheck->suggestions)) {
163 47
            return $resultSet;
164
        }
165
166 7
        foreach ($response->spellcheck->suggestions as $key => $suggestionData) {
167 4
            if (!isset($suggestionData->suggestion) && !is_array($suggestionData->suggestion)) {
168 1
                continue;
169
            }
170
171
            // the key contains the misspelled word expect the internal key "collation"
172 4
            if ($key == 'collation') {
173
                continue;
174
            }
175
            //create the spellchecking object structure
176 4
            $misspelledTerm = $key;
177 4
            foreach ($suggestionData->suggestion as $suggestedTerm) {
178 4
                $suggestion = $this->createSuggestionFromResponseFragment($suggestionData, $suggestedTerm, $misspelledTerm);
179
180
                //add it to the resultSet
181 4
                $resultSet->addSpellCheckingSuggestion($suggestion);
182
            }
183
        }
184
185 7
        return $resultSet;
186
    }
187
188
    /**
189
     * @param \stdClass $suggestionData
190
     * @param string $suggestedTerm
191
     * @param string $misspelledTerm
192
     * @return Suggestion
193
     */
194 4
    private function createSuggestionFromResponseFragment($suggestionData, $suggestedTerm, $misspelledTerm)
195
    {
196 4
        $numFound = isset($suggestionData->numFound) ? $suggestionData->numFound : 0;
197 4
        $startOffset = isset($suggestionData->startOffset) ? $suggestionData->startOffset : 0;
198 4
        $endOffset = isset($suggestionData->endOffset) ? $suggestionData->endOffset : 0;
199
200
        // by now we avoid to use GeneralUtility::makeInstance, since we only create a value object
201
        // and the usage might be a overhead.
202 4
        $suggestion = new Suggestion($suggestedTerm, $misspelledTerm, $numFound, $startOffset, $endOffset);
203 4
        return $suggestion;
204
    }
205
206
    /**
207
     * Parse available facets into objects
208
     *
209
     * @param SearchResultSet $resultSet
210
     * @return SearchResultSet
211
     */
212 54
    private function parseFacetsIntoObjects(SearchResultSet $resultSet)
213
    {
214
        // Make sure we can access the facet configuration
215 54
        if (!$resultSet->getUsedSearchRequest() || !$resultSet->getUsedSearchRequest()->getContextTypoScriptConfiguration()) {
216 8
            return $resultSet;
217
        }
218
219
        // Read the response
220 46
        $response = $resultSet->getResponse();
221 46
        if (!is_object($response->facet_counts)) {
222 4
            return $resultSet;
223
        }
224
225
        /** @var FacetParserRegistry $facetParserRegistry */
226 42
        $facetParserRegistry = $this->getFacetParserRegistry();
227 42
        $facetsConfiguration = $resultSet->getUsedSearchRequest()->getContextTypoScriptConfiguration()->getSearchFacetingFacets();
228
229 42
        foreach ($facetsConfiguration as $name => $options) {
230 40
            if (!is_array($options)) {
231
                continue;
232
            }
233 40
            $facetName = rtrim($name, '.');
234 40
            $type = !empty($options['type']) ? $options['type'] : '';
235
236 40
            $parser = $facetParserRegistry->getParser($type);
237
238 40
            $facet = $parser->parse($resultSet, $facetName, $options);
239 40
            if ($facet !== null) {
240 38
                $resultSet->addFacet($facet);
241
            }
242
        }
243
244 42
        return $resultSet;
245
    }
246
247
    /**
248
     * @param SearchResultSet $resultSet
249
     */
250 54
    protected function storeLastSearches(SearchResultSet $resultSet)
251
    {
252 54
        if ($resultSet->getAllResultCount() === 0) {
253
            // when the search does not produce a result we do not store the last searches
254 15
            return;
255
        }
256
257 39
        if (!isset($GLOBALS['TSFE']) || !isset($GLOBALS['TYPO3_DB'])) {
258 15
            return;
259
        }
260
261
        /** @var $lastSearchesService \ApacheSolrForTypo3\Solr\Domain\Search\LastSearches\LastSearchesService */
262 24
        $lastSearchesService = GeneralUtility::makeInstance(LastSearchesService::class,
263 24
            $resultSet->getUsedSearchRequest()->getContextTypoScriptConfiguration(),
264 24
            $GLOBALS['TSFE'],
265 24
            $GLOBALS['TYPO3_DB']);
266
267
268 24
        $lastSearchesService->addToLastSearches($resultSet->getUsedSearchRequest()->getRawUserQuery());
0 ignored issues
show
Documentation introduced by
$resultSet->getUsedSearc...st()->getRawUserQuery() 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...
269 24
    }
270
}
271