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 — packet_price_editor ( d1862f...6d17fd )
by
unknown
09:54
created

Widget   C

Complexity

Total Complexity 59

Size/Duplication

Total Lines 344
Duplicated Lines 12.79 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

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

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