Passed
Push — master ( 1b8200...cdf526 )
by Timo
21:46
created

SearchUriBuilder::getRemoveFacetValueUri()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 9
cts 9
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 10
nc 2
nop 3
crap 2
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Domain\Search\Uri;
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\SearchRequest;
18
use TYPO3\CMS\Core\Utility\GeneralUtility;
19
use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
20
21
/**
22
 * SearchUriBuilder
23
 *
24
 * Responsibility:
25
 *
26
 * The SearchUriBuilder is responsible to build uris, that are used in the
27
 * searchContext. It can use the previous request with it's persistent
28
 * arguments to build the url for a search sub request.
29
 *
30
 * @author Frans Saris <[email protected]>
31
 * @author Timo Hund <[email protected]>
32
 * @package ApacheSolrForTypo3\Solrfluid\Domain\Search\Uri
33
 */
34
35
class SearchUriBuilder
36
{
37
38
    /**
39
     * @var UriBuilder
40
     */
41
    protected $uriBuilder;
42
43
    /**
44
     * @var array
45
     */
46
    protected static $preCompiledLinks = [];
47
48
    /**
49
     * @var integer
50
     */
51
    protected static $hitCount;
52
53
    /**
54
     * @var integer
55
     */
56
    protected static $missCount;
57
58
    /**
59
     * @var array
60
     */
61
    protected static $additionalArgumentsCache = [];
62
63
    /**
64
     * @param UriBuilder $uriBuilder
65
     */
66 30
    public function injectUriBuilder(UriBuilder $uriBuilder)
67
    {
68 30
        $this->uriBuilder = $uriBuilder;
69 30
    }
70
71
    /**
72
     * @param SearchRequest $previousSearchRequest
73
     * @param $facetName
74
     * @param $facetValue
75
     * @return string
76
     */
77 21
    public function getAddFacetValueUri(SearchRequest $previousSearchRequest, $facetName, $facetValue)
78
    {
79
        $persistentAndFacetArguments = $previousSearchRequest
80 21
            ->getCopyForSubRequest()->addFacetValue($facetName, $facetValue)
81 21
            ->getAsArray();
82
83 21
        $additionalArguments = $this->getAdditionalArgumentsFromRequestConfiguration($previousSearchRequest);
84 21
        $arguments = $persistentAndFacetArguments + $additionalArguments;
85
86 21
        $pageUid = $this->getTargetPageUidFromRequestConfiguration($previousSearchRequest);
87 21
        return $this->buildLinkWithInMemoryCache($pageUid, $arguments);
88
    }
89
90
    /**
91
     * Removes all other facet values for this name and only set's the passed value for the facet.
92
     *
93
     * @param SearchRequest $previousSearchRequest
94
     * @param $facetName
95
     * @param $facetValue
96
     * @return string
97
     */
98 1
    public function getSetFacetValueUri(SearchRequest $previousSearchRequest, $facetName, $facetValue)
99
    {
100
        $previousSearchRequest = $previousSearchRequest
101 1
            ->getCopyForSubRequest()->removeAllFacetValuesByName($facetName);
102
103 1
        return $this->getAddFacetValueUri($previousSearchRequest, $facetName, $facetValue);
104
    }
105
106
    /**
107
     * @param SearchRequest $previousSearchRequest
108
     * @param $facetName
109
     * @param $facetValue
110
     * @return string
111
     */
112 3
    public function getRemoveFacetValueUri(SearchRequest $previousSearchRequest, $facetName, $facetValue)
113
    {
114
        $persistentAndFacetArguments = $previousSearchRequest
115 3
            ->getCopyForSubRequest()->removeFacetValue($facetName, $facetValue)
116 3
            ->getAsArray();
117
118 3
        $additionalArguments = [];
119 3
        if ($previousSearchRequest->getContextTypoScriptConfiguration()->getSearchFacetingFacetLinkUrlParametersUseForFacetResetLinkUrl()) {
120 2
            $additionalArguments = $this->getAdditionalArgumentsFromRequestConfiguration($previousSearchRequest);
121
        }
122
123 3
        $arguments = $persistentAndFacetArguments + $additionalArguments;
124
125 3
        $pageUid = $this->getTargetPageUidFromRequestConfiguration($previousSearchRequest);
126 3
        return $this->buildLinkWithInMemoryCache($pageUid, $arguments);
127
    }
128
129
    /**
130
     * @param SearchRequest $previousSearchRequest
131
     * @param $facetName
132
     * @return string
133
     */
134 1
    public function getRemoveFacetUri(SearchRequest $previousSearchRequest, $facetName)
135
    {
136
        $persistentAndFacetArguments = $previousSearchRequest
137 1
            ->getCopyForSubRequest()->removeAllFacetValuesByName($facetName)
138 1
            ->getAsArray();
139
140 1
        $additionalArguments = [];
141 1
        if ($previousSearchRequest->getContextTypoScriptConfiguration()->getSearchFacetingFacetLinkUrlParametersUseForFacetResetLinkUrl()) {
142
            $additionalArguments = $this->getAdditionalArgumentsFromRequestConfiguration($previousSearchRequest);
143
        }
144
145 1
        $arguments = $persistentAndFacetArguments + $additionalArguments;
146
147 1
        $pageUid = $this->getTargetPageUidFromRequestConfiguration($previousSearchRequest);
148 1
        return $this->buildLinkWithInMemoryCache($pageUid, $arguments);
149
    }
150
151
    /**
152
     * @param SearchRequest $previousSearchRequest
153
     * @return string
154
     */
155 2
    public function getRemoveAllFacetsUri(SearchRequest $previousSearchRequest)
156
    {
157
        $persistentAndFacetArguments = $previousSearchRequest
158 2
            ->getCopyForSubRequest()->removeAllFacets()
159 2
            ->getAsArray();
160
161 2
        $additionalArguments = [];
162 2
        if ($previousSearchRequest->getContextTypoScriptConfiguration()->getSearchFacetingFacetLinkUrlParametersUseForFacetResetLinkUrl()) {
163 2
            $additionalArguments = $this->getAdditionalArgumentsFromRequestConfiguration($previousSearchRequest);
164
        }
165
166 2
        $arguments = $persistentAndFacetArguments + $additionalArguments;
167
168 2
        $pageUid = $this->getTargetPageUidFromRequestConfiguration($previousSearchRequest);
169 2
        return $this->buildLinkWithInMemoryCache($pageUid, $arguments);
170
    }
171
172
    /**
173
     * @param SearchRequest $previousSearchRequest
174
     * @param $page
175
     * @return string
176
     */
177 8
    public function getResultPageUri(SearchRequest $previousSearchRequest, $page)
178
    {
179
        $persistentAndFacetArguments = $previousSearchRequest
180 8
            ->getCopyForSubRequest()->setPage($page)
181 8
            ->getAsArray();
182
183 8
        $pageUid = $this->getTargetPageUidFromRequestConfiguration($previousSearchRequest);
184 8
        return $this->buildLinkWithInMemoryCache($pageUid, $persistentAndFacetArguments);
185
    }
186
187
    /**
188
     * @param SearchRequest $previousSearchRequest
189
     * @param $queryString
190
     * @return string
191
     */
192 21
    public function getNewSearchUri(SearchRequest $previousSearchRequest, $queryString)
193
    {
194
        /** @var $request SearchRequest */
195 21
        $contextConfiguration = $previousSearchRequest->getContextTypoScriptConfiguration();
196 21
        $contextSystemLanguage = $previousSearchRequest->getContextSystemLanguageUid();
197 21
        $contextPageUid = $previousSearchRequest->getContextPageUid();
198
199 21
        $request = GeneralUtility::makeInstance(SearchRequest::class, [], $contextPageUid, $contextSystemLanguage, $contextConfiguration);
200 21
        $arguments = $request->setRawQueryString($queryString)->getAsArray();
201
202 21
        $pageUid = $this->getTargetPageUidFromRequestConfiguration($previousSearchRequest);
203 21
        return $this->buildLinkWithInMemoryCache($pageUid, $arguments);
204
    }
205
206
    /**
207
     * @param SearchRequest $previousSearchRequest
208
     * @param $sortingName
209
     * @param $sortingDirection
210
     * @return string
211
     */
212 22
    public function getSetSortingUri(SearchRequest $previousSearchRequest, $sortingName, $sortingDirection)
213
    {
214
        $persistentAndFacetArguments = $previousSearchRequest
215 22
            ->getCopyForSubRequest()->setSorting($sortingName, $sortingDirection)
216 22
            ->getAsArray();
217
218 22
        $pageUid = $this->getTargetPageUidFromRequestConfiguration($previousSearchRequest);
219 22
        return $this->buildLinkWithInMemoryCache($pageUid, $persistentAndFacetArguments);
220
    }
221
222
    /**
223
     * @param SearchRequest $previousSearchRequest
224
     * @return string
225
     */
226 21
    public function getRemoveSortingUri(SearchRequest $previousSearchRequest)
227
    {
228
        $persistentAndFacetArguments = $previousSearchRequest
229 21
            ->getCopyForSubRequest()->removeSorting()
230 21
            ->getAsArray();
231
232 21
        $pageUid = $this->getTargetPageUidFromRequestConfiguration($previousSearchRequest);
233 21
        return $this->buildLinkWithInMemoryCache($pageUid, $persistentAndFacetArguments);
234
    }
235
236
    /**
237
     * @param SearchRequest $previousSearchRequest
238
     * @return string
239
     */
240 19
    public function getCurrentSearchUri(SearchRequest $previousSearchRequest)
241
    {
242
        $persistentAndFacetArguments = $previousSearchRequest
243 19
            ->getCopyForSubRequest()
244 19
            ->getAsArray();
245
246
247 19
        $pageUid = $this->getTargetPageUidFromRequestConfiguration($previousSearchRequest);
248 19
        return $this->buildLinkWithInMemoryCache($pageUid, $persistentAndFacetArguments);
249
    }
250
251
    /**
252
     * @param SearchRequest $request
253
     * @return array
254
     */
255 21
    protected function getAdditionalArgumentsFromRequestConfiguration(SearchRequest $request)
256
    {
257 21
        if ($request->getContextTypoScriptConfiguration() == null) {
258 2
            return [];
259
        }
260
261 19
        $reQuestId = $request->getId();
262 19
        if (isset(self::$additionalArgumentsCache[$reQuestId])) {
263 18
            return self::$additionalArgumentsCache[$reQuestId];
264
        }
265
266 19
        self::$additionalArgumentsCache[$reQuestId] = $request->getContextTypoScriptConfiguration()
267 19
            ->getSearchFacetingFacetLinkUrlParametersAsArray();
268
269 19
        return self::$additionalArgumentsCache[$reQuestId];
270
    }
271
272
    /**
273
     * @param SearchRequest $request
274
     * @return integer|null
275
     */
276 29
    protected function getTargetPageUidFromRequestConfiguration(SearchRequest $request)
277
    {
278 29
        if ($request->getContextTypoScriptConfiguration() == null) {
279 2
            return null;
280
        }
281
282 27
        return $request->getContextTypoScriptConfiguration()->getSearchTargetPage();
283
    }
284
285
    /**
286
     * @param integer $pageUid
287
     * @param array $arguments
288
     * @return string
289
     */
290 29
    protected function buildLinkWithInMemoryCache($pageUid, array $arguments)
291
    {
292 29
        $values = [];
293 29
        $structure = $arguments;
294 29
        $this->getSubstitution($structure, $values);
295 29
        $hash = md5($pageUid . json_encode($structure));
296
297 29
        if (isset(self::$preCompiledLinks[$hash])) {
298 22
            self::$hitCount++;
299 22
            $template = self::$preCompiledLinks[$hash];
300
        } else {
301 29
            self::$missCount++;
302 29
            $this->uriBuilder->setTargetPageUid($pageUid);
303 29
            $template = $this->uriBuilder->setArguments($structure)->setUseCacheHash(false)->build();
304 29
            self::$preCompiledLinks[$hash] = $template;
305
        }
306
307
        $keys = array_map(function($value) {
308 27
            return urlencode($value);
309 29
        }, array_keys($values));
310 29
        $values = array_map(function($value) {
311 27
            return urlencode($value);
312 29
        }, $values);
313 29
        $uri = str_replace($keys, $values, $template);
314 29
        return $uri;
315
    }
316
317
    /**
318
     * This method is used to build two arrays from a nested array. The first one represents the structure.
319
     * In this structure the values are replaced with the pass to the value. At the same time the values get collected
320
     * in the $values array, with the path as key. This can be used to build a comparable hash from the arguments
321
     * in order to reduce the amount of typolink calls
322
     *
323
     *
324
     * Example input
325
     *
326
     * $data = [
327
     *  'foo' => [
328
     *      'bar' => 111
329
     *   ]
330
     * ]
331
     *
332
     * will return:
333
     *
334
     * $structure = [
335
     *  'foo' => [
336
     *      'bar' => '###foo:bar###'
337
     *   ]
338
     * ]
339
     *
340
     * $values = [
341
     *  '###foo:bar###' => 111
342
     * ]
343
     *
344
     * @param $structure
345
     * @param $values
346
     * @param array $branch
347
     */
348 29
    protected function getSubstitution(array &$structure, array  &$values, array $branch = [])
349
    {
350 29
        foreach ($structure as $key => &$value) {
351 29
            $branch[] = $key;
352 29
            if (is_array($value)) {
353 27
                $this->getSubstitution($value, $values, $branch);
354
            } else {
355 27
                $path = '###' . implode(':', $branch) . '###';
356 27
                $values[$path] = $value;
357 27
                $structure[$key] = $path;
358
            }
359
        }
360 29
    }
361
}
362