Completed
Push — master ( 9819c1...f2d6e9 )
by Rafael
06:19
created

SearchUriBuilder::getResultGroupItemPageUri()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

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