Failed Conditions
Push — release-11.5.x ( 71e6eb...3bfdb1 )
by Markus
27:37
created

UrlFacetContainer::removeAllFacets()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Facets;
17
18
use ApacheSolrForTypo3\Solr\Domain\Search\SearchRequest;
19
use ApacheSolrForTypo3\Solr\System\Util\ArrayAccessor;
20
use ApacheSolrForTypo3\Solr\Utility\ParameterSortingUtility;
21
22
/**
23
 * Data bag for facets inside of an url
24
 *
25
 * @author Lars Tode <[email protected]>
26
 * @api
27
 */
28
class UrlFacetContainer implements \Countable
29
{
30
    /**
31
     * Parameters array has a numeric index
32
     */
33
    const PARAMETER_STYLE_INDEX = 'index';
34
35
    /**
36
     * Parameters array uses combination of key and value as index
37
     */
38
    const PARAMETER_STYLE_ASSOC = 'assoc';
39
40
    /**
41
     * Used parameter style
42
     *
43
     * @var string
44
     */
45
    protected $parameterStyle = self::PARAMETER_STYLE_INDEX;
46
47
    /**
48
     * Argument namespace as configures in TypoScript
49
     *
50
     * @var string
51
     */
52
    protected $argumentNameSpace = 'tx_solr';
53
54
    /**
55
     * @var ArrayAccessor
56
     */
57
    protected $argumentsAccessor;
58
59
    /**
60
     * Mark the data bag as changed
61
     *
62
     * @var bool
63
     */
64
    protected $changed = false;
65
66
    /**
67
     * Parameters should be sorted
68
     *
69
     * @var bool
70
     */
71
    protected $sort = false;
72
73
    /**
74
     * UrlFacetConstructor constructor.
75
     *
76
     * @param ArrayAccessor $argumentsAccessor
77
     * @param string $argumentNameSpace
78
     * @param string $parameterStyle
79
     */
80 82
    public function __construct(
81
        ArrayAccessor $argumentsAccessor,
82
        string $argumentNameSpace = SearchRequest::DEFAULT_PLUGIN_NAMESPACE,
83
        string $parameterStyle = self::PARAMETER_STYLE_INDEX
84
    ) {
85
        // Take care that the url style matches in case and is one of the allowed values
86 82
        $parameterStyle = strtolower(trim($parameterStyle));
87 82
        if (empty($parameterStyle) ||
88 82
            (!in_array($parameterStyle, [self::PARAMETER_STYLE_INDEX, self::PARAMETER_STYLE_ASSOC]))) {
89
            $parameterStyle = self::PARAMETER_STYLE_INDEX;
90
        }
91 82
        $this->argumentsAccessor = $argumentsAccessor;
92 82
        $this->argumentNameSpace = $argumentNameSpace;
93 82
        $this->parameterStyle = $parameterStyle;
94
95 82
        if ($this->parameterStyle === self::PARAMETER_STYLE_ASSOC) {
96
            $this->sort = true;
97
        }
98
    }
99
100
    /**
101
     * Enable the sort of URL parameters
102
     *
103
     * @return $this
104
     */
105
    public function enableSort(): self
106
    {
107
        $this->sort = true;
108
109
        return $this;
110
    }
111
112
    /**
113
     * Disable the sort of URL parameters
114
     *
115
     * @return $this
116
     */
117
    public function disableSort(): self
118
    {
119
        // If the parameter style is assoc, all parameters have to be sorted!
120
        if ($this->parameterStyle === self::PARAMETER_STYLE_INDEX) {
121
            $this->sort = false;
122
        }
123
124
        return $this;
125
    }
126
127
    /**
128
     * Returns the information if the parameters are sorted
129
     *
130
     * @return bool
131
     */
132 34
    public function isSorted(): bool
133
    {
134 34
        return $this->sort;
135
    }
136
137
    /**
138
     * @return string
139
     */
140
    public function getParameterStyle(): string
141
    {
142
        return $this->parameterStyle;
143
    }
144
145
    /**
146
     * Helper method to prefix an accessor with the arguments namespace.
147
     *
148
     * @param string $path
149
     * @return string
150
     */
151 34
    protected function prefixWithNamespace(string $path = 'filter'): string
152
    {
153 34
        return $this->argumentNameSpace . ':' . $path;
154
    }
155
156
    /**
157
     * Returns the list of activate facet names
158
     *
159
     * @return array
160
     */
161 2
    public function getActiveFacetNames(): array
162
    {
163 2
        $activeFacets = $this->getActiveFacets();
164 2
        $facetNames = [];
165
166 2
        if ($this->parameterStyle === self::PARAMETER_STYLE_INDEX) {
167 2
            array_map(function ($activeFacet) use (&$facetNames) {
168
                $facetNames[] = substr($activeFacet, 0, strpos($activeFacet, ':'));
169 2
            }, $activeFacets);
170
        } else {
171
            array_map(function ($activeFacet) use (&$facetNames) {
172
                $facetNames[] = substr($activeFacet, 0, strpos($activeFacet, ':'));
173
            }, array_keys($activeFacets));
174
        }
175
176 2
        return $facetNames;
177
    }
178
179
    /**
180
     * Returns all facet values for a certain facetName
181
     * @param string $facetName
182
     * @return array
183
     */
184 34
    public function getActiveFacetValuesByName(string $facetName): array
185
    {
186 34
        $values = [];
187 34
        $activeFacets = $this->getActiveFacets();
188 34
        if ($this->parameterStyle === self::PARAMETER_STYLE_ASSOC) {
189
            $activeFacets = array_keys($activeFacets);
190
        }
191 34
        array_map(function ($activeFacet) use (&$values, $facetName) {
192 8
            $parts = explode(':', $activeFacet, 2);
193 8
            if ($parts[0] === $facetName) {
194 8
                $values[] = $parts[1];
195
            }
196 34
        }, $activeFacets);
197
198 34
        return $values;
199
    }
200
201
    /**
202
     * Returns the active facets
203
     *
204
     * @return array
205
     */
206 34
    public function getActiveFacets(): array
207
    {
208 34
        $path = $this->prefixWithNamespace('filter');
209 34
        $pathValue = $this->argumentsAccessor->get($path, []);
210
211 34
        if (!is_array($pathValue)) {
212
            $pathValue = [];
213
        }
214
215
        // Sort url parameter
216 34
        if ($this->sort && !empty($pathValue)) {
217
            ParameterSortingUtility::sortByType(
218
                $pathValue,
219
                $this->parameterStyle
220
            );
221
        }
222
223 34
        return $pathValue;
224
    }
225
226
    /**
227
     * Returns the active count of facets
228
     *
229
     * @return int
230
     */
231
    public function count(): int
232
    {
233
        return count($this->getActiveFacets());
234
    }
235
236
    /**
237
     * Sets and overwrite the active facets
238
     *
239
     * @param array $activeFacets
240
     *
241
     * @return UrlFacetContainer
242
     */
243 32
    public function setActiveFacets(array $activeFacets = []): UrlFacetContainer
244
    {
245 32
        $path = $this->prefixWithNamespace('filter');
246 32
        $this->argumentsAccessor->set($path, $activeFacets);
247
248 32
        return $this;
249
    }
250
251
    /**
252
     * Adds a facet value to the request.
253
     *
254
     * @param string $facetName
255
     * @param mixed $facetValue
256
     *
257
     * @return UrlFacetContainer
258
     */
259 30
    public function addFacetValue(string $facetName, $facetValue): UrlFacetContainer
260
    {
261 30
        if ($this->hasFacetValue($facetName, $facetValue)) {
262 6
            return $this;
263
        }
264
265 28
        $facetValues = $this->getActiveFacets();
266 28
        if ($this->parameterStyle === self::PARAMETER_STYLE_INDEX) {
267 28
            $facetValues[] = $facetName . ':' . $facetValue;
268
        } else {
269
            $facetValues[$facetName . ':' . $facetValue] = 1;
270
        }
271
272 28
        $this->changed = true;
273 28
        $this->setActiveFacets($facetValues);
274
275 28
        return $this;
276
    }
277
278
    /**
279
     * Removes a facet value from the request.
280
     *
281
     * @param string $facetName
282
     * @param mixed $facetValue
283
     *
284
     * @return UrlFacetContainer
285
     */
286 8
    public function removeFacetValue(string $facetName, $facetValue): UrlFacetContainer
287
    {
288 8
        if (!$this->hasFacetValue($facetName, $facetValue)) {
289
            return $this;
290
        }
291 8
        $facetValues = $this->getActiveFacets();
292 8
        $facetValueToLookFor = $facetName . ':' . $facetValue;
293
294 8
        if ($this->parameterStyle === self::PARAMETER_STYLE_INDEX) {
295 8
            foreach ($facetValues as $index => $facetValue) {
0 ignored issues
show
introduced by
$facetValue is overwriting one of the parameters of this function.
Loading history...
296 8
                if ($facetValue === $facetValueToLookFor) {
297 8
                    unset($facetValues[$index]);
298 8
                    break;
299
                }
300
            }
301
        } else {
302
            if (isset($facetValues[$facetValueToLookFor])) {
303
                unset($facetValues[$facetValueToLookFor]);
304
            }
305
        }
306 8
        $this->changed = true;
307 8
        $this->setActiveFacets($facetValues);
308
309 8
        return $this;
310
    }
311
312
    /**
313
     * Removes all facet values from the request by a certain facet name
314
     *
315
     * @param string $facetName
316
     *
317
     * @return UrlFacetContainer
318
     */
319 2
    public function removeAllFacetValuesByName(string $facetName): UrlFacetContainer
320
    {
321 2
        $facetValues = $this->getActiveFacets();
322 2
        $filterOptions = 0;
323 2
        if ($this->parameterStyle === self::PARAMETER_STYLE_ASSOC) {
324
            $filterOptions = ARRAY_FILTER_USE_KEY;
325
        }
326
327 2
        $facetValues = array_filter($facetValues, function ($facetNameValue) use ($facetName) {
328
            $parts = explode(':', $facetNameValue, 2);
329
            return $parts[0] !== $facetName;
330 2
        }, $filterOptions);
331
332 2
        $this->changed = true;
333 2
        $this->setActiveFacets($facetValues);
334
335 2
        return $this;
336
    }
337
338
    /**
339
     * Removes all active facets from the request.
340
     *
341
     * @return UrlFacetContainer
342
     */
343 8
    public function removeAllFacets(): UrlFacetContainer
344
    {
345 8
        $path = $this->prefixWithNamespace('filter');
346 8
        $this->argumentsAccessor->reset($path);
347 8
        $this->changed = true;
348 8
        return $this;
349
    }
350
351
    /**
352
     * Test if there is a active facet with a given value
353
     *
354
     * @param string $facetName
355
     * @param mixed $facetValue
356
     * @return bool
357
     */
358 32
    public function hasFacetValue(string $facetName, $facetValue): bool
359
    {
360 32
        $facetNameAndValueToCheck = $facetName . ':' . $facetValue;
361 32
        $facetValues = $this->getActiveFacets();
362
363 32
        if ($this->parameterStyle === self::PARAMETER_STYLE_INDEX) {
364 32
            return in_array($facetNameAndValueToCheck, $this->getActiveFacets());
365
        }
366
        return isset($facetValues[$facetNameAndValueToCheck]) && (int)$facetValues[$facetNameAndValueToCheck] === 1;
367
    }
368
369
    /**
370
     * Returns the information if the data bag has changes
371
     *
372
     * @return bool
373
     */
374 32
    public function hasChanged(): bool
375
    {
376 32
        return $this->changed;
377
    }
378
379
    /**
380
     * Resets the internal change status by explicit acknowledge the change
381
     *
382
     * @return $this
383
     */
384 32
    public function acknowledgeChange(): UrlFacetContainer
385
    {
386 32
        $this->changed = false;
387
388 32
        return $this;
389
    }
390
}
391