Test Failed
Branch v5 (12d602)
by Alexey
04:51
created

OptionsParser   C

Complexity

Total Complexity 69

Size/Duplication

Total Lines 284
Duplicated Lines 3.87 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 11
loc 284
rs 5.6445
c 0
b 0
f 0
wmc 69
lcom 1
cbo 2

9 Methods

Rating   Name   Duplication   Size   Complexity  
B getDefault() 0 21 6
C order() 0 41 12
A presetFilters() 0 13 4
C filters() 6 57 16
C categories() 0 24 9
B search() 0 16 6
B warehouse() 0 26 3
B parse() 0 58 6
B getWarehouses() 5 17 7

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 OptionsParser 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 OptionsParser, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Helper for module methods
5
 *
6
 * @author Alexey Krupskiy <[email protected]>
7
 * @link http://inji.ru/
8
 * @copyright 2016 Alexey Krupskiy
9
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
10
 */
11
12
namespace Ecommerce;
13
14
class OptionsParser extends \InjiObject {
15
16
    public static function parse($options = [], $forCount = false) {
17
        $selectOptions = self::getDefault($options);
18
19
        //parse order options
20
        self::order($options, $selectOptions);
21
22
        //joined offers
23
        $selectOptions['join'][] = [Item\Offer::table(), Item::index() . ' = ' . Item\Offer::colPrefix() . Item::index(), 'inner'];
24
25
        //joined prices, check price configs
26
        $comparision = Item\Offer::index() . ' = ' . Item\Offer\Price::colPrefix() . Item\Offer::index();
27
        if (empty(\App::$cur->Ecommerce->config['show_zero_price'])) {
28
            $comparision .= ' and ' . Item\Offer\Price::colPrefix() . 'price>0';
29
        }
30
        if (!empty(\App::$cur->Ecommerce->config['available_price_types'])) {
31
            $comparision .= ' and ' . Item\Offer\Price::colPrefix() . 'item_offer_price_type_id in (' . implode(',', \App::$cur->Ecommerce->config['available_price_types']) . ')';
32
        }
33
        $selectOptions['join'][] = [Item\Offer\Price::table(), $comparision,
34
            empty(\App::$cur->Ecommerce->config['show_without_price']) ? 'inner' : 'left'];
35
36
        //join item types
37
        $selectOptions['join'][] = [
38
            Item\Offer\Price\Type::table(), Item\Offer\Price::colPrefix() . Item\Offer\Price\Type::index() . ' = ' . Item\Offer\Price\Type::index()
39
        ];
40
41
        //add filter for item type user roles by current user role
42
        $selectOptions['where'][] = [
43
            [Item\Offer\Price\Type::index(), null, 'is'],
44
            [
45
                [Item\Offer\Price\Type::colPrefix() . 'roles', '', '=', 'OR'],
46
                [Item\Offer\Price\Type::colPrefix() . 'roles', '%|' . \Users\User::$cur->role_id . '|%', 'LIKE', 'OR'],
47
            ],
48
        ];
49
50
        //add custom preset filters from config on where
51
        self::presetFilters($selectOptions);
52
53
        //parse filters
54
        self::filters($options, $selectOptions);
55
56
        //categories paths
57
        self::categories($options, $selectOptions);
58
59
        //search
60
        self::search($options, $selectOptions);
61
62
        self::warehouse($selectOptions);
63
        if ($forCount) {
64
            $selectOptions['distinct'] = \Ecommerce\Item::index();
65
        } else {
66
            $selectOptions['group'] = Item::index();
67
        }
68
        if (isset($options['array'])) {
69
            $selectOptions['array'] = $options['array'];
70
        }
71
72
        return $selectOptions;
73
    }
74
75
    public static function getDefault(&$options) {
76
        $selectOptions = [
77
            'where' => !empty($options['where']) ? $options['where'] : [],
78
            'distinct' => false,
79
            'join' => [],
80
            'order' => [],
81
            'start' => isset($options['start']) ? (int) $options['start'] : 0,
82
            'key' => isset($options['key']) ? $options['key'] : null,
83
            'limit' => !empty($options['count']) ? (int) $options['count'] : 0,
84
        ];
85
86
        //only not deleted items
87
        $selectOptions['where'][] = ['deleted', 0];
88
89
        //check config of view items without images
90
        if (empty(\App::$cur->Ecommerce->config['view_empty_image'])) {
91
            $selectOptions['where'][] = ['image_file_id', 0, '!='];
92
        }
93
94
        return $selectOptions;
95
    }
96
97
    public static function order(&$options, &$selectOptions) {
98
        if (empty($options['sort']) || !is_array($options['sort'])) {
99
            return;
100
        }
101
        foreach ($options['sort'] as $col => $direction) {
102
            $direction = strtolower($direction) == 'desc' ? 'desc' : 'asc';
103
            switch ($col) {
104
                case 'price':
105
                    $selectOptions['order'][] = [Item\Offer\Price::colPrefix() . 'price', $direction];
106
                    break;
107
                case 'new':
108
                    $selectOptions['order'][] = ['date_create', $direction];
109
                    break;
110
                case 'isset':
111
                    $warehouseIds = self::getWarehouses('order');
112
                    $selectOptions['order'][] = [
113
                        '(
114
          (SELECT COALESCE(sum(`' . Item\Offer\Warehouse::colPrefix() . 'count`),0) 
115
            FROM ' . \App::$cur->db->table_prefix . Item\Offer\Warehouse::table() . ' iciw 
116
            WHERE iciw.' . Item\Offer\Warehouse::colPrefix() . Item\Offer::index() . ' = ' . Item\Offer::index() . '
117
                ' . ($warehouseIds ? ' AND iciw.' . Item\Offer\Warehouse::colPrefix() . Warehouse::index() . ' IN(' . implode(',', $warehouseIds) . ')' : '') . '
118
            )
119
          -
120
          (SELECT COALESCE(sum(' . Warehouse\Block::colPrefix() . 'count) ,0)
121
            FROM ' . \App::$cur->db->table_prefix . Warehouse\Block::table() . ' iewb
122
            inner JOIN ' . \App::$cur->db->table_prefix . Cart::table() . ' icc ON icc.' . Cart::index() . ' = iewb.' . Warehouse\Block::colPrefix() . Cart::index() . ' AND (
123
                (`' . Cart::colPrefix() . 'warehouse_block` = 1 and `' . Cart::colPrefix() . 'cart_status_id` in(2,3,6)) ||
124
                (`' . Cart::colPrefix() . Cart\Status::index() . '` in(0,1) and `' . Cart::colPrefix() . 'date_last_activ` >=subdate(now(),INTERVAL 30 MINUTE))
125
            )
126
            WHERE iewb.' . Warehouse\Block::colPrefix() . Item\Offer::index() . ' = ' . Item\Offer::index() . ')
127
          )', $direction
128
                    ];
129
                    break;
130
                case 'name':
131
                case 'sales':
132
                case 'weight':
133
                    $selectOptions['order'][] = [$col, $direction];
134
            }
135
        }
136
        $selectOptions['order'][] = ['offers:prices:type:weight', 'ASC'];
137
    }
138
139
    public static function presetFilters(&$selectOptions) {
140
        if (empty(\App::$cur->Ecommerce->config['view_filter'])) {
141
            return;
142
        }
143
        if (!empty(\App::$cur->Ecommerce->config['view_filter']['options'])) {
144
            foreach (\App::$cur->Ecommerce->config['view_filter']['options'] as $optionId => $optionValue) {
145
                $selectOptions['join'][] = [Item\Param::table(), Item::index() . ' = ' . 'option' . $optionId . '.' . Item\Param::colPrefix() . Item::index() . ' AND ' .
146
                    'option' . $optionId . '.' . Item\Param::colPrefix() . Item\Option::index() . ' = "' . (int) $optionId . '" AND ' .
147
                    'option' . $optionId . '.' . Item\Param::colPrefix() . 'value = "' . (int) $optionValue . '"',
148
                    'inner', 'option' . $optionId];
149
            }
150
        }
151
    }
152
153
    public static function filters(&$options, &$selectOptions) {
154
        if (empty($options['filters'])) {
155
            return;
156
        }
157
        foreach ($options['filters'] as $col => $filter) {
158
            switch ($col) {
159
                case 'best':
160
                    if ($filter) {
161
                        $selectOptions['where'][] = ['best', 1];
162
                    }
163
                    break;
164
                case 'badge':
165
                    $selectOptions['where'][] = ['item_badge_id', (int) $filter];
166
                    break;
167
                case 'price':
168
                    $colName = Item\Offer\Price::colPrefix() . 'price';
169 View Code Duplication
                    if (!empty($filter['min'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
170
                        $selectOptions['where'][] = [$colName, (float) $filter['min'], '>='];
171
                    }
172 View Code Duplication
                    if (!empty($filter['max'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
                        $selectOptions['where'][] = [$colName, (float) $filter['max'], '<='];
174
                    }
175
                    break;
176
                case 'options':
177
                case 'offerOptions':
178
                    if ($col == 'offerOptions') {
179
                        $paramPrefix = Item\Offer\Param::colPrefix();
180
                        $itemIndex = Item\Offer::index();
181
                        $optionIndex = Item\Offer\Option::index();
182
                        $table = Item\Offer\Param::table();
183
                    } else {
184
                        $paramPrefix = Item\Param::colPrefix();
185
                        $itemIndex = Item::index();
186
                        $optionIndex = Item\Option::index();
187
                        $table = Item\Param::table();
188
                    }
189
                    if ($filter) {
190
                        foreach ($filter as $optionId => $optionValue) {
191
                            $optionId = (int) $optionId;
192
                            if (is_array($optionValue)) {
193
                                $optionValueArr = [];
194
                                foreach ($optionValue as $val) {
195
                                    $optionValueArr[] = \App::$cur->db->connection->pdo->quote($val);
196
                                }
197
                                $qstr = 'IN (' . implode(',', $optionValueArr) . ')';
198
                            } else {
199
                                $qstr = '= ' . \App::$cur->db->connection->pdo->quote($optionValue);
200
                            }
201
                            $selectOptions['join'][] = [$table, $itemIndex . ' = ' . 'option' . $optionId . '.' . $paramPrefix . $itemIndex . ' AND ' .
202
                                'option' . $optionId . '.' . $paramPrefix . $optionIndex . ' = "' . (int) $optionId . '" AND ' .
203
                                'option' . $optionId . '.' . $paramPrefix . 'value ' . $qstr . '',
204
                                'inner', 'option' . $optionId];
205
                        }
206
                    }
207
            }
208
        }
209
    }
210
211
    public static function categories(&$options, &$selectOptions) {
212
        if (empty($options['parent'])) {
213
            return;
214
        }
215
        if (is_array($options['parent']) || strpos($options['parent'], ',') !== false) {
216
            $list = is_array($options['parent']) ? $options['parent'] : explode(',', $options['parent']);
217
            $first = true;
218
            $where = [];
219
            foreach ($list as $categoryId) {
220
                if (!$categoryId) {
221
                    continue;
222
                }
223
                $category = Category::get($categoryId);
224
                $where[] = ['tree_path', $category->tree_path . (int) $categoryId . '/%', 'LIKE', $first ? 'AND' : 'OR'];
225
                $first = false;
226
            }
227
            $selectOptions['where'][] = $where;
228
        } else {
229
            $category = Category::get($options['parent']);
230
            if ($category) {
231
                $selectOptions['where'][] = ['tree_path', $category->tree_path . (int) $options['parent'] . '/%', 'LIKE'];
232
            }
233
        }
234
    }
235
236
    public static function search(&$options, &$selectOptions) {
237
        if (empty($options['search'])) {
238
            return;
239
        }
240
        $searchStr = preg_replace('![^A-zА-я0-9 ]!iSu', ' ', $options['search']);
241
        $searchArr = [];
242
        foreach (explode(' ', $searchStr) as $part) {
243
            $part = trim($part);
244
            if ($part && strlen($part) > 2) {
245
                $searchArr[] = ['search_index', '%' . $part . '%', 'LIKE'];
246
            }
247
        }
248
        if (!empty($searchArr)) {
249
            $selectOptions['where'][] = $searchArr;
250
        }
251
    }
252
253
    public static function warehouse(&$selectOptions) {
254
        if (!empty(\App::$cur->Ecommerce->config['view_empty_warehouse'])) {
255
            return;
256
        }
257
        $warehouseIds = self::getWarehouses();
258
259
        $selectOptions['where'][] = [
260
            '(
261
          (SELECT COALESCE(sum(`' . Item\Offer\Warehouse::colPrefix() . 'count`),0) 
262
            FROM ' . \App::$cur->db->table_prefix . Item\Offer\Warehouse::table() . ' iciw 
263
            WHERE iciw.' . Item\Offer\Warehouse::colPrefix() . Item\Offer::index() . ' = ' . Item\Offer::index() . '
264
                ' . ($warehouseIds ? ' AND iciw.' . Item\Offer\Warehouse::colPrefix() . Warehouse::index() . ' IN(' . implode(',', $warehouseIds) . ')' : '') . '
265
            )
266
          -
267
          (SELECT COALESCE(sum(' . Warehouse\Block::colPrefix() . 'count) ,0)
268
            FROM ' . \App::$cur->db->table_prefix . Warehouse\Block::table() . ' iewb
269
            inner JOIN ' . \App::$cur->db->table_prefix . Cart::table() . ' icc ON icc.' . Cart::index() . ' = iewb.' . Warehouse\Block::colPrefix() . Cart::index() . ' AND (
270
                (`' . Cart::colPrefix() . 'warehouse_block` = 1 and `' . Cart::colPrefix() . 'cart_status_id` in(2,3,6)) ||
271
                (`' . Cart::colPrefix() . Cart\Status::index() . '` in(0,1) and `' . Cart::colPrefix() . 'date_last_activ` >=subdate(now(),INTERVAL 30 MINUTE))
272
            )
273
            WHERE iewb.' . Warehouse\Block::colPrefix() . Item\Offer::index() . ' = ' . Item\Offer::index() . ')
274
          )',
275
            0,
276
            '>'
277
        ];
278
    }
279
280
    public static function getWarehouses($type = 'all') {
281
        if ($type === 'order') {
282
            $warehouses = Warehouse::getList(['where' => ['type', 'order']]);
283
            return array_keys($warehouses);
284
        }
285
        if (!\App::$cur->geography || !\Geography\City::$cur) {
286
            return [];
287
        }
288
        $warehouseIds = [];
289
        $warehouses = \Geography\City\Data::get([['code', 'warehouses'], ['city_id', \Geography\City::$cur->id]]);
290 View Code Duplication
        if ($warehouses && $warehouses->data) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
291
            foreach (explode(',', $warehouses->data) as $id) {
292
                $warehouseIds[$id] = $id;
293
            }
294
        }
295
        return $warehouseIds;
296
    }
297
}