Completed
Push — master ( 694264...44bc0a )
by Timo
11s
created

Facet   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 283
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 42.96%

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 4
dl 0
loc 283
ccs 58
cts 135
cp 0.4296
rs 9
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A initializeConfiguration() 0 7 1
A getRequirements() 0 17 3
A isActive() 0 11 2
A getSelectedOptions() 0 21 4
A isEmpty() 0 16 4
A isRenderingAllowed() 0 14 3
C isRequirementMet() 0 24 8
A getOptionsRaw() 0 18 4
A getOptionsCount() 0 6 1
A getName() 0 4 1
A getField() 0 4 1
A getConfiguration() 0 4 1
A getType() 0 4 1
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Facet;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2012-2015 Ingo Renner <[email protected]>
8
 *  All rights reserved
9
 *
10
 *  This script is part of the TYPO3 project. The TYPO3 project is
11
 *  free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 2 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  The GNU General Public License can be found at
17
 *  http://www.gnu.org/copyleft/gpl.html.
18
 *
19
 *  This script is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 *  GNU General Public License for more details.
23
 *
24
 *  This copyright notice MUST APPEAR in all copies of the script!
25
 ***************************************************************/
26
27
use ApacheSolrForTypo3\Solr\Search;
28
use ApacheSolrForTypo3\Solr\Util;
29
use TYPO3\CMS\Core\Utility\GeneralUtility;
30
31
/**
32
 * A facet
33
 *
34
 * @author Ingo Renner <[email protected]>
35
 */
36
class Facet
37
{
38
    const TYPE_FIELD = 'field';
39
    const TYPE_QUERY = 'query';
40
    const TYPE_RANGE = 'range';
41
42
    /**
43
     * @var Search
44
     */
45
    protected $search;
46
47
    /**
48
     * The facet's name as configured on TypoScript
49
     *
50
     * @var string
51
     */
52
    protected $name;
53
54
    /**
55
     * Facet type, defaults to field facet.
56
     *
57
     * @var string
58
     */
59
    protected $type = self::TYPE_FIELD;
60
61
    /**
62
     * The index field the facet is built from.
63
     *
64
     * @var string
65
     */
66
    protected $field;
67
68
    /**
69
     * Facet configuration
70
     *
71
     * @var array
72
     */
73
    protected $configuration;
74
75
    /**
76
     * Constructor.
77
     *
78
     * @param string $facetName The facet's name
79
     * @param string $facetType The facet's internal type. field, range, or query
80
     */
81 18
    public function __construct($facetName, $facetType = self::TYPE_FIELD)
82
    {
83 18
        $this->name = $facetName;
84 18
        $this->type = $facetType;
85 18
        $this->search = GeneralUtility::makeInstance(Search::class);
86
87 18
        $this->initializeConfiguration();
88 18
    }
89
90
    /**
91
     * Initializes/loads the facet configuration
92
     *
93
     */
94 18
    protected function initializeConfiguration()
95
    {
96 18
        $solrConfiguration = Util::getSolrConfiguration();
97 18
        $this->configuration = $solrConfiguration->getSearchFacetingFacetByName($this->name);
98
99 18
        $this->field = $this->configuration['field'];
100 18
    }
101
102
    /**
103
     * Checks whether an option of the facet has been selected by the user by
104
     * checking the URL GET parameters.
105
     *
106
     * @return bool TRUE if any option of the facet is applied, FALSE otherwise
107
     */
108 18
    public function isActive()
109
    {
110 18
        $isActive = false;
111
112 18
        $selectedOptions = $this->getSelectedOptions();
113 18
        if (!empty($selectedOptions)) {
114 1
            $isActive = true;
115
        }
116
117 18
        return $isActive;
118
    }
119
120
    /**
121
     * Gets the facet's currently user-selected options
122
     *
123
     * @return array An array with user-selected facet options.
124
     */
125 18
    public function getSelectedOptions()
126
    {
127 18
        $selectedOptions = array();
128
129 18
        $resultParameters = GeneralUtility::_GET('tx_solr');
130 18
        $filterParameters = array();
131 18
        if (isset($resultParameters['filter'])) {
132 1
            $filterParameters = (array)array_map('urldecode',
133 1
                $resultParameters['filter']);
134
        }
135
136 18
        foreach ($filterParameters as $filter) {
137 1
            list($facetName, $filterValue) = explode(':', $filter);
138
139 1
            if ($facetName == $this->name) {
140 1
                $selectedOptions[] = $filterValue;
141
            }
142
        }
143
144 18
        return $selectedOptions;
145
    }
146
147
    /**
148
     * Determines if a facet has any options.
149
     *
150
     * @return bool TRUE if no facet options are given, FALSE if facet options are given
151
     */
152 18
    public function isEmpty()
153
    {
154 18
        $isEmpty = false;
155
156 18
        $options = $this->getOptionsRaw();
157 18
        $optionsCount = count($options);
158
159
        // facet options include '_empty_', if no options are given
160 18
        if ($optionsCount == 0
161 18
            || ($optionsCount == 1 && array_key_exists('_empty_', $options))
162
        ) {
163 1
            $isEmpty = true;
164
        }
165
166 18
        return $isEmpty;
167
    }
168
169
    /**
170
     * Checks whether requirements are fulfilled
171
     *
172
     * @return bool TRUE if conditions required to render this facet are met, FALSE otherwise
173
     */
174 18
    public function isRenderingAllowed()
175
    {
176 18
        $renderingAllowed = true;
177
178 18
        $requirements = $this->getRequirements();
179 18
        foreach ($requirements as $requirement) {
180
            if (!$this->isRequirementMet($requirement)) {
181
                $renderingAllowed = false;
182
                break;
183
            }
184
        }
185
186 18
        return $renderingAllowed;
187
    }
188
189
    /**
190
     * Gets the configured requirements to allow rendering of the facet.
191
     *
192
     * @return array Requirements with keys "name", "facet", and "value".
193
     */
194 18
    protected function getRequirements()
195
    {
196 18
        $requirements = array();
197
198 18
        if (!empty($this->configuration['requirements.'])) {
199
            foreach ($this->configuration['requirements.'] as $name => $requirement) {
200
                $requirements[] = array(
201
                    'name' => substr($name, 0, -1),
202
                    'facet' => $requirement['facet'],
203
                    'values' => GeneralUtility::trimExplode(',',
204
                        $requirement['values']),
205
                );
206
            }
207
        }
208
209 18
        return $requirements;
210
    }
211
212
    /**
213
     * Evaluates a single facet rendering requirement.
214
     *
215
     * @param array $requirement A requirement with keys "name", "facet", and "value".
216
     * @return bool TRUE if the requirement is met, FALSE otherwise.
217
     */
218
    protected function isRequirementMet(array $requirement)
219
    {
220
        $requirementMet = false;
221
222
        $requiredFacet = GeneralUtility::makeInstance(Facet::class, $requirement['facet']);
223
        $selectedOptions = $requiredFacet->getSelectedOptions();
224
        $csvSelectedOptions = implode(', ', $selectedOptions);
225
226
        foreach ($requirement['values'] as $value) {
227
            $noFacetOptionSelectedRequirementMet = ($value === '__none' && empty($selectedOptions));
228
            $anyFacetOptionSelectedRequirementMet = ($value === '__any' && !empty($selectedOptions));
229
230
            if ($noFacetOptionSelectedRequirementMet
231
                || $anyFacetOptionSelectedRequirementMet
232
                || in_array($value, $selectedOptions)
233
                || fnmatch($value, $csvSelectedOptions)
234
            ) {
235
                $requirementMet = true;
236
                break;
237
            }
238
        }
239
240
        return $requirementMet;
241
    }
242
243
    /**
244
     * Gets the facet's options
245
     *
246
     * @return array An array with facet options.
247
     */
248 18
    public function getOptionsRaw()
249
    {
250 18
        $facetOptions = array();
251
252 18
        switch ($this->type) {
253 18
            case self::TYPE_FIELD:
254 18
                $facetOptions = $this->search->getFacetFieldOptions($this->field);
255 18
                break;
256
            case self::TYPE_QUERY:
257
                $facetOptions = $this->search->getFacetQueryOptions($this->field);
258
                break;
259
            case self::TYPE_RANGE:
260
                $facetOptions = $this->search->getFacetRangeOptions($this->field);
261
                break;
262
        }
263
264 18
        return $facetOptions;
265
    }
266
267
    /**
268
     * Gets the number of options for a facet.
269
     *
270
     * @return int Number of facet options for the current facet.
271
     */
272 18
    public function getOptionsCount()
273
    {
274 18
        $facetOptions = $this->getOptionsRaw();
275
276 18
        return count($facetOptions);
277
    }
278
279
    /**
280
     * Gets the facet's name
281
     *
282
     * @return string The facet's name
283
     */
284 18
    public function getName()
285
    {
286 18
        return $this->name;
287
    }
288
289
    /**
290
     * Gets the field name the facet is operating on.
291
     *
292
     * @return string The name of the field the facet is operating on.
293
     */
294
    public function getField()
295
    {
296
        return $this->field;
297
    }
298
299
    /**
300
     * Gets the facet's configuration.
301
     *
302
     * @return array The facet's configuration as an array.
303
     */
304
    public function getConfiguration()
305
    {
306
        return $this->configuration;
307
    }
308
309
    /**
310
     * Gets the facet's internal type. One of field, range, or query.
311
     *
312
     * @return string Facet type.
313
     */
314
    public function getType()
315
    {
316
        return $this->type;
317
    }
318
}
319