Passed
Push — master ( 3e6704...db24af )
by Rafael
43:26 queued 10s
created

UrlFacetContainer::disableSort()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Facets;
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
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
    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
        $parameterStyle = strtolower(trim($parameterStyle));
87
        if (empty($parameterStyle) ||
88
            (!in_array($parameterStyle, [self::PARAMETER_STYLE_INDEX, self::PARAMETER_STYLE_ASSOC]))) {
89
            $parameterStyle = self::PARAMETER_STYLE_INDEX;
90
        }
91
        $this->argumentsAccessor = $argumentsAccessor;
92
        $this->argumentNameSpace = $argumentNameSpace;
93
        $this->parameterStyle = $parameterStyle;
94
95
        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
    public function isSorted(): bool
133
    {
134
        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
    protected function prefixWithNamespace(string $path = 'filter'): string
152
    {
153
        return $this->argumentNameSpace . ':' . $path;
154
    }
155
156
    /**
157
     * Returns the list of activate facet names
158
     *
159
     * @return array
160
     */
161
    public function getActiveFacetNames(): array
162
    {
163
        $activeFacets = $this->getActiveFacets();
164
        $facetNames = [];
165
166
        if ($this->parameterStyle === self::PARAMETER_STYLE_INDEX) {
167
            array_map(function($activeFacet) use (&$facetNames) {
168
                $facetNames[] = substr($activeFacet, 0, strpos($activeFacet, ':'));
169
            }, $activeFacets);
170
        } else {
171
            array_map(function($activeFacet) use (&$facetNames) {
172
                $facetNames[] = substr($activeFacet, 0, strpos($activeFacet, ':'));
173
            }, array_keys($activeFacets));
174
        }
175
176
        return $facetNames;
177
    }
178
179
    /**
180
     * Returns all facet values for a certain facetName
181
     * @param string $facetName
182
     * @return array
183
     */
184
    public function getActiveFacetValuesByName(string $facetName): array
185
    {
186
        $values = [];
187
        $activeFacets = $this->getActiveFacets();
188
        if ($this->parameterStyle === self::PARAMETER_STYLE_ASSOC) {
189
            $activeFacets = array_keys($activeFacets);
190
        }
191
        array_map(function($activeFacet) use (&$values, $facetName) {
192
            $parts = explode(':', $activeFacet, 2);
193
            if ($parts[0] === $facetName) {
194
                $values[] = $parts[1];
195
            }
196
        }, $activeFacets);
197
198
        return $values;
199
    }
200
201
    /**
202
     * Returns the active facets
203
     *
204
     * @return array
205
     */
206
    public function getActiveFacets(): array
207
    {
208
        $path = $this->prefixWithNamespace('filter');
209
        $pathValue = $this->argumentsAccessor->get($path, []);
210
211
        if (!is_array($pathValue)) {
212
            $pathValue = [];
213
        }
214
215
        // Sort url parameter
216
        if ($this->sort && !empty($pathValue)) {
217
            ParameterSortingUtility::sortByType(
218
                $pathValue,
219
                $this->parameterStyle
220
            );
221
        }
222
223
        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
    public function setActiveFacets(array $activeFacets = []): UrlFacetContainer
244
    {
245
        $path = $this->prefixWithNamespace('filter');
246
        $this->argumentsAccessor->set($path, $activeFacets);
247
248
        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
    public function addFacetValue(string $facetName, $facetValue): UrlFacetContainer
260
    {
261
        if ($this->hasFacetValue($facetName, $facetValue)) {
262
            return $this;
263
        }
264
265
        $facetValues = $this->getActiveFacets();
266
        if ($this->parameterStyle === self::PARAMETER_STYLE_INDEX) {
267
            $facetValues[] = $facetName . ':' . $facetValue;
268
        } else {
269
            $facetValues[$facetName . ':' . $facetValue] = 1;
270
        }
271
272
        $this->changed = true;
273
        $this->setActiveFacets($facetValues);
274
275
        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
    public function removeFacetValue(string $facetName, $facetValue): UrlFacetContainer
287
    {
288
        if (!$this->hasFacetValue($facetName, $facetValue)) {
289
            return $this;
290
        }
291
        $facetValues = $this->getActiveFacets();
292
        $facetValueToLookFor = $facetName . ':' . $facetValue;
293
294
        if ($this->parameterStyle === self::PARAMETER_STYLE_INDEX) {
295
            foreach ($facetValues as $index => $facetValue) {
0 ignored issues
show
introduced by
$facetValue is overwriting one of the parameters of this function.
Loading history...
296
                if ($facetValue === $facetValueToLookFor) {
297
                    unset($facetValues[$index]);
298
                    break;
299
                }
300
            }
301
        } else {
302
            if (isset($facetValues[$facetValueToLookFor])) {
303
                unset($facetValues[$facetValueToLookFor]);
304
            }
305
        }
306
        $this->changed = true;
307
        $this->setActiveFacets($facetValues);
308
309
        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
    public function removeAllFacetValuesByName(string $facetName): UrlFacetContainer
320
    {
321
        $facetValues = $this->getActiveFacets();
322
        $filterOptions = 0;
323
        if ($this->parameterStyle === self::PARAMETER_STYLE_ASSOC) {
324
            $filterOptions = ARRAY_FILTER_USE_KEY;
325
        }
326
327
        $facetValues = array_filter($facetValues, function($facetNameValue) use ($facetName) {
328
            $parts = explode(':', $facetNameValue, 2);
329
            return $parts[0] !== $facetName;
330
        }, $filterOptions);
331
332
        $this->changed = true;
333
        $this->setActiveFacets($facetValues);
334
335
        return $this;
336
    }
337
338
    /**
339
     * Removes all active facets from the request.
340
     *
341
     * @return UrlFacetContainer
342
     */
343
    public function removeAllFacets(): UrlFacetContainer
344
    {
345
        $path = $this->prefixWithNamespace('filter');
346
        $this->argumentsAccessor->reset($path);
347
        $this->changed = true;
348
        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
    public function hasFacetValue(string $facetName, $facetValue): bool
359
    {
360
        $facetNameAndValueToCheck = $facetName . ':' . $facetValue;
361
        $facetValues = $this->getActiveFacets();
362
363
        if ($this->parameterStyle === self::PARAMETER_STYLE_INDEX) {
364
            return in_array($facetNameAndValueToCheck, $this->getActiveFacets());
365
        } else {
366
            return isset($facetValues[$facetNameAndValueToCheck]) && (int)$facetValues[$facetNameAndValueToCheck] === 1;
367
        }
368
    }
369
370
    /**
371
     * Returns the information if the data bag has changes
372
     *
373
     * @return bool
374
     */
375
    public function hasChanged(): bool
376
    {
377
        return $this->changed;
378
    }
379
380
    /**
381
     * Resets the internal change status by explicit acknowledge the change
382
     *
383
     * @return $this
384
     */
385
    public function acknowledgeChange(): UrlFacetContainer
386
    {
387
        $this->changed = false;
388
389
        return $this;
390
    }
391
}
392