GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — filters-dev ( b8c330...c59b06 )
by Ivan
11:21
created

Widget   C

Complexity

Total Complexity 59

Size/Duplication

Total Lines 343
Duplicated Lines 12.83 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 59
lcom 1
cbo 4
dl 44
loc 343
rs 6.1904
c 2
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
D removeLostDependencies() 0 35 9
B getEavSliderFilter() 0 31 4
A getSelectedPropertyIndex() 0 7 2
B mergeUrlProperties() 0 15 5
D widgetRun() 44 216 39

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Widget often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Widget, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace app\extensions\DefaultTheme\widgets\FilterSets;
4
5
use app\extensions\DefaultTheme\components\BaseWidget;
6
use app\models\Property;
7
use app\models\PropertyStaticValues;
8
use app\modules\shop\models\FilterSets;
9
use app\modules\shop\models\Product;
10
use devgroup\TagDependencyHelper\ActiveRecordHelper;
11
use Yii;
12
use yii\caching\TagDependency;
13
use yii\helpers\Url;
14
15
class Widget extends BaseWidget
16
{
17
    protected $toUnset = [];
18
    public $viewFile = 'filter-sets';
19
    public $hideEmpty = true;
20
    public $usePjax = true;
21
    public $useNewFilter = false;
22
23
    /**
24
     * Remove lost dependencies from url params.
25
     * Also this method builds toUnset array.
26
     * @param FilterSets $filterSets
27
     * @param array $urlParams
28
     * @return array
29
     */
30
    protected function removeLostDependencies($filterSets, $urlParams)
31
    {
32
        $depends = [];
33
        $this->toUnset = [];
34
        foreach ($filterSets as $set) {
35
            if (false == empty($set->property->depends_on_property_id)) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
36
                if (isset($this->toUnset[$set->property->depends_on_property_id])) {
37
                    $this->toUnset[$set->property->depends_on_property_id][] = $set->property->id;
38
                } else {
39
                    $this->toUnset[$set->property->depends_on_property_id] = [$set->property->id];
40
                }
41
                if (false === isset($depends[$set->property->id])) {
42
                    $depends[$set->property->id] = [
43
                        $set->property->depends_on_property_id => $set->property->depended_property_values
44
                    ];
45
                } else {
46
                    $depends[$set->property->id][$set->property->depends_on_property_id] =
47
                        $set->property->depended_property_values;
48
                }
49
            }
50
        }
51
        foreach ($depends as $prop_id => $depend) {
52
            $key = key($depend);
53
            if (isset($urlParams['properties'][$prop_id])) {
54
                if (false === isset($urlParams['properties'][$key])) {
55
                    unset($urlParams['properties'][$prop_id]);
56
                } else {
57
                    if (false === in_array($depend[$key], $urlParams['properties'][$key])) {
58
                        unset($urlParams['properties'][$prop_id]);
59
                    }
60
                }
61
            }
62
        }
63
        return $urlParams;
64
    }
65
66
    public function getEavSliderFilter(Property $property, $urlParams)
67
    {
68
        $result = null;
69
        $key = $property->key;
70
        $eavCategoryData = Yii::$app->db->createCommand(
71
            'SELECT MAX(CAST({{%product_eav}}.value AS DECIMAL)) as max, MIN(CAST({{%product_eav}}.value AS DECIMAL)) as min
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
72
              FROM {{%product_eav}}
73
              LEFT JOIN {{%product_category}} ON ({{%product_category}}.object_model_id = {{%product_eav}}.object_model_id)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
74
              WHERE {{%product_eav}}.key=:key AND {{%product_category}}.category_id=:category_id'
75
        )->bindParam(':key', $key)
76
            ->bindParam(':category_id', $urlParams['last_category_id'])
77
            ->queryOne();
78
79
        if ($eavCategoryData['max'] !== null &&
80
            $eavCategoryData['min'] !== null &&
81
            $eavCategoryData['max'] !== $eavCategoryData['min']
82
        ) {
83
            $result = [
84
                'id' => $property->id,
85
                'name' => $property->name,
86
                'isRange' => 1,
87
                'selections' => [],
88
                'multiple' => 0,
89
                'max' => $eavCategoryData['max'],
90
                'min' => $eavCategoryData['min'],
91
                'property' => $property,
92
                'step' => 1
93
            ];
94
        }
95
        return $result;
96
    }
97
98
99
    /**
100
     * Get selected property index
101
     * @param array $properties
102
     * @param integer $propertyId
103
     * @param integer $propertyValueId
104
     * @return string|false
105
     */
106
    protected function getSelectedPropertyIndex($properties, $propertyId, $propertyValueId)
107
    {
108
        if (!isset($properties[$propertyId])) {
109
            return false;
110
        }
111
        return array_search($propertyValueId, $properties[$propertyId]);
112
    }
113
114
    /**
115
     * Smart url params merging
116
     * @param array $a
117
     * @param array $b
118
     * @return array mixed
119
     */
120
    protected function mergeUrlProperties($a, $b)
121
    {
122
        if (isset($a['properties'], $b['properties'])) {
123
            foreach ($b['properties'] as $propertyId => $staticValues) {
124
                foreach ($staticValues as $staticValue) {
125
                    if (isset($a['properties'][$propertyId])) {
126
                        $a['properties'][$propertyId][] = $staticValue;
127
                    } else {
128
                        $a['properties'][$propertyId] = [$staticValue];
129
                    }
130
                }
131
            }
132
        }
133
        return $a;
134
    }
135
136
    /**
137
     * Actual run function for all widget classes extending BaseWidget
138
     *
139
     * @return mixed
140
     */
141
    public function widgetRun()
142
    {
143
        $categoryId = Yii::$app->request->get('last_category_id');
144
        if ($categoryId === null) {
145
            return '<!-- no category_id specified for FilterSet widget in request -->';
146
        }
147
        $filterSets = FilterSets::getForCategoryId($categoryId);
148
        if (count($filterSets) === 0) {
149
            return '<!-- no filter sets for current category -->';
150
        }
151
        if ($this->header === '') {
152
            $this->header = Yii::t('app', 'Filters');
153
        }
154
155
        // Begin of a new filter sets implementation
156
        if ($this->useNewFilter) {
157
            $urlParams = [
158
                '@category',
159
                'last_category_id' => $categoryId,
160
                'properties' => Yii::$app->request->get('properties', []),
161
                'category_group_id' => Yii::$app->request->get('category_group_id', 0),
162
            ];
163
            $priceMin = empty(Yii::$app->request->post('price_min')) ? Yii::$app->request->get('price_min') : Yii::$app->request->post('price_min');
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 148 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
164
            $priceMax = empty(Yii::$app->request->post('price_max')) ? Yii::$app->request->get('price_max') : Yii::$app->request->post('price_max');
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 148 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
165
            if (false === empty($priceMin)) {
166
                $urlParams['price_min'] = $priceMin;
167
            }
168
            if (false === empty($priceMax)) {
169
                $urlParams['price_max'] = $priceMax;
170
            }
171
            $urlParams = $this->mergeUrlProperties($urlParams, ['properties' => Yii::$app->request->post('properties', [])]);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 125 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
172
            $urlParams = $this->removeLostDependencies($filterSets, $urlParams);
173
            $properties = $urlParams['properties'];
174
            $newGet = Yii::$app->request->get();
175
            $newGet['properties'] = $properties;
176
            Yii::$app->request->setQueryParams($newGet);
177
            ksort($properties);
178
            $cacheKey = 'FilterSets:' . $categoryId . ':' . json_encode($urlParams);
179
            unset($properties);
180
            if (false === $filtersArray = Yii::$app->cache->get($cacheKey)) {
181
                $filtersArray = [];
182
                foreach ($filterSets as $filterSet) {
183
                    /** Если eav и слайдер, то фильтр формируется по особым правилам */
184
                    if ($filterSet->is_range_slider && $filterSet->property->is_eav) {
185
                        $filter = $this->getEavSliderFilter($filterSet->property, $urlParams);
186
                        if($filter) {
187
                            $filtersArray[] = $filter;
188
                        }
189
                        continue;
190
                    } elseif ($filterSet->property->has_static_values === 0) {
191
                        continue;
192
                    }
193
                    if (!empty($filterSet->property->depends_on_property_id)
194
                        && !empty($filterSet->property->depended_property_values)
195
                    ) {
196
                        if (
197
                            $this->getSelectedPropertyIndex(
198
                                $urlParams['properties'],
199
                                $filterSet->property->depends_on_property_id,
200
                                $filterSet->property->depended_property_values
201
                            ) === false
202
                        ) {
203
                            continue;
204
                        }
205
                    }
206
                    $selections = PropertyStaticValues::getValuesForFilter(
207
                        $filterSet->property->id,
208
                        $urlParams['last_category_id'],
209
                        $urlParams['properties'],
210
                        $filterSet->multiple,
211
                        Yii::$app->getModule('shop')->filterOnlyByParentProduct
212
                    );
213
                    if (count($selections) === 0) {
214
                        continue;
215
                    }
216
                    $item = [
217
                        'id' => $filterSet->property->id,
218
                        'name' => $filterSet->property->name,
219
                        'sort_order' => $filterSet->property->sort_order,
220
                        'isRange' => $filterSet->is_range_slider,
221
                        'selections' => [],
222
                        'multiple' => $filterSet->multiple,
223
                    ];
224
                    if ($filterSet->is_range_slider) {
225
                        $item['max'] = PHP_INT_MIN;
226
                        $item['min'] = PHP_INT_MAX;
227
                        $item['property'] = $filterSet->property;
228
                    }
229
                    foreach ($selections as $selection) {
230
                        if ($filterSet->is_range_slider) {
231 View Code Duplication
                            if ((int)$selection['value'] > $item['max']) {
232
                                $item['max'] = (int)$selection['value'];
233
                            }
234 View Code Duplication
                            if ((int)$selection['value'] < $item['min']) {
235
                                $item['min'] = (int)$selection['value'];
236
                            }
237
                        } elseif($item['multiple']) {
238
                            $selectedPropertyIndex = $this->getSelectedPropertyIndex(
239
                                $urlParams['properties'],
240
                                $filterSet->property_id,
241
                                $selection['id']
242
                            );
243 View Code Duplication
                            if ($selectedPropertyIndex !== false) {
244
                                if (count($urlParams['properties'][$filterSet->property_id]) > 1) {
245
                                    $routeParams = $urlParams;
246
                                    unset($routeParams['properties'][$filterSet->property_id][$selectedPropertyIndex]);
247
                                } else {
248
                                    $routeParams = $urlParams;
249
                                    unset($routeParams['properties'][$filterSet->property_id]);
250
                                }
251
                                if (isset($this->toUnset[$filterSet->property_id])) {
252
                                    foreach ($this->toUnset[$filterSet->property_id] as $id) {
253
                                        unset($routeParams['properties'][$id]);
254
                                    }
255
                                }
256
                            } else {
257
                                $routeParams = $this->mergeUrlProperties(
258
                                    $urlParams,
259
                                    ['properties' => [$filterSet->property_id => [$selection['id']]]]
260
                                );
261
                            }
262
                            $item['selections'][] = [
263
                                'id' => $selection['id'],
264
                                'checked' => $selectedPropertyIndex !== false,
265
                                'label' => $selection['name'],
266
                                'url' =>  Url::toRoute($routeParams),
267
                                'active' => $selection['active'],
268
                            ];
269
                        } else {
270
                            $selectedPropertyIndex = $this->getSelectedPropertyIndex(
271
                                $urlParams['properties'],
272
                                $filterSet->property_id,
273
                                $selection['id']
274
                            );
275 View Code Duplication
                            if ($selectedPropertyIndex !== false) {
276
                                if (count($urlParams['properties'][$filterSet->property_id]) > 1) {
277
                                    $routeParams = $urlParams;
278
                                    unset($routeParams['properties'][$filterSet->property_id][$selectedPropertyIndex]);
279
                                } else {
280
                                    $routeParams = $urlParams;
281
                                    unset($routeParams['properties'][$filterSet->property_id]);
282
                                }
283
                                if (isset($this->toUnset[$filterSet->property_id])) {
284
                                    foreach ($this->toUnset[$filterSet->property_id] as $id) {
285
                                        unset($routeParams['properties'][$id]);
286
                                    }
287
                                }
288
                            } else {
289
                                $routeParams = $this->mergeUrlProperties(
290
                                    $urlParams,
291
                                    ['properties' => [$filterSet->property_id => [$selection['id']]]]
292
                                );
293
                            }
294
                            $item['selections'][] = [
295
                                'id' => $selection['id'],
296
                                'checked' => $selectedPropertyIndex !== false,
297
                                'label' => $selection['name'],
298
                                'url' => $selection['active'] === true || $selectedPropertyIndex !== false
299
                                    ? Url::toRoute($routeParams)
300
                                    : null,
301
                                'active' => $selection['active'],
302
                            ];
303
                        }
304
                    }
305
                    if ($filterSet->is_range_slider) {
306
                        if ($item['min'] === $item['max']) {
307
                            continue;
308
                        }
309
                        $i = 1;
310
                        $n = $item['max'] - $item['min'];
311
                        while ($n >= 10) {
312
                            $n = $n / 10;
313
                            $i++;
314
                        }
315
                        $item['step'] = $i > 3 ? (int)pow(10, $i - 3) : 1;
316
                        unset($i, $n);
317
                    }
318
                    $filtersArray[] = $item;
319
                    unset($item);
320
                }
321
                Yii::$app->cache->set(
322
                    $cacheKey,
323
                    $filtersArray,
324
                    86400,
325
                    new TagDependency(
326
                        [
327
                            'tags' => [
328
                                ActiveRecordHelper::getCommonTag(FilterSets::className()),
329
                                ActiveRecordHelper::getCommonTag(Product::className()),
330
                                ActiveRecordHelper::getCommonTag(Property::className()),
331
                            ],
332
                        ]
333
                    )
334
                );
335
            }
336
            return $this->render(
337
                $this->viewFile,
338
                [
339
                    'filtersArray' => $filtersArray,
340
                    'id' => 'filter-set-' . $this->id,
341
                    'urlParams' => $urlParams,
342
                    'usePjax' => $this->usePjax,
343
                ]
344
            );
345
        }
346
        // End of a new filter sets implementation
347
348
        return $this->render(
349
            $this->viewFile,
350
            [
351
                'filterSets' => $filterSets,
352
                'id' => 'filter-set-' . $this->id,
353
                'hideEmpty' => $this->hideEmpty,
354
            ]
355
        );
356
    }
357
}
358