Completed
Push — master ( 01c552...6fe5c3 )
by
unknown
23s queued 14s
created

setObjectManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
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
17
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Facets\AbstractFacet;
18
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Facets\FacetRegistry;
19
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Facets\RequirementsService;
20
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Sorting\Sorting;
21
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Spellchecking\Suggestion;
22
use TYPO3\CMS\Core\Utility\GeneralUtility;
23
use TYPO3\CMS\Extbase\Object\ObjectManager;
24
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
25
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
26
27
/**
28
 * This processor is used to transform the solr response into a
29
 * domain object hierarchy that can be used in the application (controller and view).
30
 *
31
 * @author Frans Saris <[email protected]>
32
 * @author Timo Hund <[email protected]>
33
 */
34
class ResultSetReconstitutionProcessor implements SearchResultSetProcessor
35
{
36
    /**
37
     * @var ObjectManagerInterface
38
     */
39
    protected $objectManager;
40
41
    /**
42
     * @return ObjectManagerInterface
43
     */
44 28
    public function getObjectManager()
45
    {
46 28
        if ($this->objectManager === null) {
47
            $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
48
        }
49 28
        return $this->objectManager;
50
    }
51
52
    /**
53
     * @param ObjectManagerInterface $objectManager
54
     */
55 28
    public function setObjectManager($objectManager)
56
    {
57 28
        $this->objectManager = $objectManager;
58 28
    }
59
60
61
    /**
62
     * @return FacetRegistry
63
     */
64 28
    protected function getFacetRegistry()
65
    {
66
        // @extensionScannerIgnoreLine
67 28
        return $this->getObjectManager()->get(FacetRegistry::class);
0 ignored issues
show
Deprecated Code introduced by
The function TYPO3\CMS\Extbase\Object...ManagerInterface::get() has been deprecated: since TYPO3 10.4, will be removed in version 12.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

67
        return /** @scrutinizer ignore-deprecated */ $this->getObjectManager()->get(FacetRegistry::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
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 40
    public function process(SearchResultSet $resultSet)
78
    {
79 40
        if (!$resultSet instanceof SearchResultSet) {
0 ignored issues
show
introduced by
$resultSet is always a sub-type of ApacheSolrForTypo3\Solr\...sultSet\SearchResultSet.
Loading history...
80
            return $resultSet;
81
        }
82
83 40
        $resultSet = $this->parseSpellCheckingResponseIntoObjects($resultSet);
84 40
        $resultSet = $this->parseSortingIntoObjects($resultSet);
85
86
        // here we can reconstitute other domain objects from the solr response
87 40
        $resultSet = $this->parseFacetsIntoObjects($resultSet);
88
89 40
        return $resultSet;
90
    }
91
92
    /**
93
     * @param SearchResultSet $resultSet
94
     * @return SearchResultSet
95
     */
96 40
    protected function parseSortingIntoObjects(SearchResultSet $resultSet)
97
    {
98 40
        $configuration = $resultSet->getUsedSearchRequest()->getContextTypoScriptConfiguration();
99 40
        $hasSorting = $resultSet->getUsedSearchRequest()->getHasSorting();
100 40
        $activeSortingName = $resultSet->getUsedSearchRequest()->getSortingName();
101 40
        $activeSortingDirection = $resultSet->getUsedSearchRequest()->getSortingDirection();
102
103
        // no configuration available
104 40
        if (!isset($configuration)) {
105 7
            return $resultSet;
106
        }
107
108
        // no sorting enabled
109 33
        if (!$configuration->getSearchSorting()) {
110 31
            return $resultSet;
111
        }
112 2
        foreach ($configuration->getSearchSortingOptionsConfiguration() as $sortingKeyName => $sortingOptions) {
113 2
            $sortingName = rtrim($sortingKeyName, '.');
114 2
            $selected = false;
115 2
            $direction = $configuration->getSearchSortingDefaultOrderBySortOptionName($sortingName);
116
117
            // when we have an active sorting in the request we compare the sortingName and mark is as active and
118
            // use the direction from the request
119 2
            if ($hasSorting && $activeSortingName == $sortingName) {
120 1
                $selected = true;
121 1
                $direction = $activeSortingDirection;
122
            }
123
124 2
            $field = $sortingOptions['field'];
125 2
            $label = $sortingOptions['label'];
126
127 2
            $isResetOption = $field === 'relevance';
128
129
            // Allow stdWrap on label:
130 2
            $labelHasSubConfiguration = is_array($sortingOptions['label.']);
131 2
            if ($labelHasSubConfiguration) {
132
                $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
133
                $label = $cObj->stdWrap($label, $sortingOptions['label.']);
134
            }
135
136 2
            $sorting = $this->getObjectManager()->get(Sorting::class, $resultSet, $sortingName, $field, $direction, $label, $selected, $isResetOption);
0 ignored issues
show
Deprecated Code introduced by
The function TYPO3\CMS\Extbase\Object...ManagerInterface::get() has been deprecated: since TYPO3 10.4, will be removed in version 12.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

136
            $sorting = /** @scrutinizer ignore-deprecated */ $this->getObjectManager()->get(Sorting::class, $resultSet, $sortingName, $field, $direction, $label, $selected, $isResetOption);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
137 2
            $resultSet->addSorting($sorting);
138
        }
139
140 2
        return $resultSet;
141
    }
142
143
    /**
144
     * @param SearchResultSet $resultSet
145
     * @return SearchResultSet
146
     */
147 40
    private function parseSpellCheckingResponseIntoObjects(SearchResultSet $resultSet)
148
    {
149
        //read the response
150 40
        $response = $resultSet->getResponse();
151
152 40
        if (!is_array($response->spellcheck->suggestions)) {
153 39
            return $resultSet;
154
        }
155
156 1
        $misspelledTerm = '';
157 1
        foreach ($response->spellcheck->suggestions as $key => $suggestionData) {
158 1
            if (is_string($suggestionData)) {
159 1
                $misspelledTerm = $key;
160 1
                continue;
161
            }
162
163 1
            if ($misspelledTerm === '') {
164
                throw new \UnexpectedValueException('No missspelled term before suggestion');
165
            }
166
167 1
            if (!is_object($suggestionData) && !is_array($suggestionData->suggestion)) {
168
                continue;
169
            }
170
171 1
            foreach ($suggestionData->suggestion as $suggestedTerm) {
172 1
                $suggestion = $this->createSuggestionFromResponseFragment($suggestionData, $suggestedTerm, $misspelledTerm);
173
                //add it to the resultSet
174 1
                $resultSet->addSpellCheckingSuggestion($suggestion);
175
            }
176
177
        }
178
179 1
        return $resultSet;
180
    }
181
182
    /**
183
     * @param \stdClass $suggestionData
184
     * @param string $suggestedTerm
185
     * @param string $misspelledTerm
186
     * @return Suggestion
187
     */
188 1
    private function createSuggestionFromResponseFragment($suggestionData, $suggestedTerm, $misspelledTerm)
189
    {
190 1
        $numFound = isset($suggestionData->numFound) ? $suggestionData->numFound : 0;
191 1
        $startOffset = isset($suggestionData->startOffset) ? $suggestionData->startOffset : 0;
192 1
        $endOffset = isset($suggestionData->endOffset) ? $suggestionData->endOffset : 0;
193
194
        // by now we avoid to use GeneralUtility::makeInstance, since we only create a value object
195
        // and the usage might be a overhead.
196 1
        $suggestion = new Suggestion($suggestedTerm, $misspelledTerm, $numFound, $startOffset, $endOffset);
197 1
        return $suggestion;
198
    }
199
200
    /**
201
     * Parse available facets into objects
202
     *
203
     * @param SearchResultSet $resultSet
204
     * @return SearchResultSet
205
     */
206 40
    private function parseFacetsIntoObjects(SearchResultSet $resultSet)
207
    {
208
        // Make sure we can access the facet configuration
209 40
        if (!$resultSet->getUsedSearchRequest() || !$resultSet->getUsedSearchRequest()->getContextTypoScriptConfiguration()) {
210 7
            return $resultSet;
211
        }
212
213
        // Read the response
214 33
        $response = $resultSet->getResponse();
215 33
        if (!is_object($response->facet_counts) && !is_object($response->facets)) {
216 5
            return $resultSet;
217
        }
218
219
        /** @var FacetRegistry $facetRegistry */
220 28
        $facetRegistry = $this->getFacetRegistry();
221 28
        $facetsConfiguration = $resultSet->getUsedSearchRequest()->getContextTypoScriptConfiguration()->getSearchFacetingFacets();
222
223 28
        foreach ($facetsConfiguration as $name => $options) {
224 26
            if (!is_array($options)) {
225
                continue;
226
            }
227 26
            $facetName = rtrim($name, '.');
228 26
            $type = !empty($options['type']) ? $options['type'] : '';
229
230 26
            $parser = $facetRegistry->getPackage($type)->getParser();
231 26
            $facet = $parser->parse($resultSet, $facetName, $options);
232 26
            if ($facet !== null) {
233 26
                $resultSet->addFacet($facet);
234
            }
235
        }
236
237 28
        $this->applyRequirements($resultSet);
238
239 28
        return $resultSet;
240
    }
241
242
    /**
243
     * @param SearchResultSet $resultSet
244
     */
245 28
    protected function applyRequirements(SearchResultSet $resultSet)
246
    {
247 28
        $requirementsService = $this->getRequirementsService();
248 28
        $facets = $resultSet->getFacets();
249 28
        foreach ($facets as $facet) {
250
            /** @var $facet AbstractFacet */
251 26
            $requirementsMet = $requirementsService->getAllRequirementsMet($facet);
252 26
            $facet->setAllRequirementsMet($requirementsMet);
253
        }
254 28
    }
255
256
    /**
257
     * @return RequirementsService
258
     */
259 28
    protected function getRequirementsService()
260
    {
261
        // @extensionScannerIgnoreLine
262 28
        return $this->getObjectManager()->get(RequirementsService::class);
0 ignored issues
show
Deprecated Code introduced by
The function TYPO3\CMS\Extbase\Object...ManagerInterface::get() has been deprecated: since TYPO3 10.4, will be removed in version 12.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

262
        return /** @scrutinizer ignore-deprecated */ $this->getObjectManager()->get(RequirementsService::class);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
263
    }
264
}
265