Completed
Push — master ( f17270...776132 )
by Alexey
07:15
created

OptionsParser   F

Complexity

Total Complexity 56

Size/Duplication

Total Lines 236
Duplicated Lines 2.54 %

Coupling/Cohesion

Components 1
Dependencies 19

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 6
loc 236
rs 2.4812
wmc 56
lcom 1
cbo 19

9 Methods

Rating   Name   Duplication   Size   Complexity  
A parse() 0 47 3
B getDefault() 0 21 6
B order() 0 20 10
A presetFilters() 0 13 4
C filters() 6 47 12
B categories() 0 21 6
B search() 0 16 6
B warehouse() 0 26 3
B getWarehouses() 0 13 6

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 \Object {
15
16
    public static function parse($options = []) {
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
        $selectOptions['join'][] = [Item\Offer\Price::table(),
27
            Item\Offer::index() . ' = ' . Item\Offer\Price::colPrefix() . Item\Offer::index() .
28
            (empty(\App::$cur->Ecommerce->config['show_zero_price']) ? ' and ' . Item\Offer\Price::colPrefix() . 'price>0' : ''),
29
            empty(\App::$cur->Ecommerce->config['show_without_price']) ? 'inner' : 'left'];
30
31
        //join item types
32
        $selectOptions['join'][] = [
33
            Item\Offer\Price\Type::table(), Item\Offer\Price::colPrefix() . Item\Offer\Price\Type::index() . ' = ' . Item\Offer\Price\Type::index()
34
        ];
35
36
        //add filter for item type user roles by current user role
37
        $selectOptions['where'][] = [
38
            [Item\Offer\Price\Type::index(), NULL, 'is'],
39
            [
40
                [Item\Offer\Price\Type::colPrefix() . 'roles', '', '=', 'OR'],
41
                [Item\Offer\Price\Type::colPrefix() . 'roles', '%|' . \Users\User::$cur->role_id . '|%', 'LIKE', 'OR'],
42
            ],
43
        ];
44
45
        //add custom preset filters from config on where
46
        self::presetFilters($options, $selectOptions);
47
48
        //parse filters
49
        self::filters($options, $selectOptions);
50
51
        //categories paths
52
        self::categories($options, $selectOptions);
53
54
        //search
55
        self::search($options, $selectOptions);
56
57
        self::warehouse($options, $selectOptions);
58
59
        $selectOptions['group'] = Item::index();
60
61
        return $selectOptions;
62
    }
63
64
    public static function getDefault(&$options) {
65
        $selectOptions = [
66
            'where' => !empty($options['where']) ? $options['where'] : [],
67
            'distinct' => false,
68
            'join' => [],
69
            'order' => [],
70
            'start' => isset($options['start']) ? (int) $options['start'] : 0,
71
            'key' => isset($options['key']) ? $options['key'] : null,
72
            'limit' => !empty($options['count']) ? (int) $options['count'] : 0,
73
        ];
74
75
        //only not deleted items
76
        $selectOptions['where'][] = ['deleted', 0];
77
78
        //check config of view items without images
79
        if (empty(\App::$cur->Ecommerce->config['view_empty_image'])) {
80
            $selectOptions['where'][] = ['image_file_id', 0, '!='];
81
        }
82
83
        return $selectOptions;
84
    }
85
86
    public static function order(&$options, &$selectOptions) {
87
        if (empty($options['sort']) || !is_array($options['sort'])) {
88
            return;
89
        }
90
        foreach ($options['sort'] as $col => $direction) {
91
            $direction = strtolower($direction) == 'desc' ? 'desc' : 'asc';
92
            switch ($col) {
93
                case 'price':
94
                    $selectOptions['order'][] = [Item\Offer\Price::colPrefix() . 'price', $direction];
95
                    break;
96
                case 'new':
97
                    $selectOptions['order'][] = ['date_create', $direction];
98
                    break;
99
                case 'name':
100
                case 'sales':
101
                case 'weight':
102
                    $selectOptions['order'][] = [$col, $direction];
103
            }
104
        }
105
    }
106
107
    public static function presetFilters(&$options, &$selectOptions) {
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
108
        if (empty(\App::$cur->Ecommerce->config['view_filter'])) {
109
            return;
110
        }
111
        if (!empty(\App::$cur->Ecommerce->config['view_filter']['options'])) {
112
            foreach (\App::$cur->Ecommerce->config['view_filter']['options'] as $optionId => $optionValue) {
113
                $selectOptions['join'][] = [Item\Param::table(), Item::index() . ' = ' . 'option' . $optionId . '.' . Item\Param::colPrefix() . Item::index() . ' AND ' .
114
                    'option' . $optionId . '.' . Item\Param::colPrefix() . Item\Option::index() . ' = "' . (int) $optionId . '" AND ' .
115
                    'option' . $optionId . '.' . Item\Param::colPrefix() . 'value = "' . (int) $optionValue . '"',
116
                    'inner', 'option' . $optionId];
117
            }
118
        }
119
    }
120
121
    public static function filters(&$options, &$selectOptions) {
122
        if (empty($options['filters'])) {
123
            return;
124
        }
125
        foreach ($options['filters'] as $col => $filter) {
126
            switch ($col) {
127
                case 'price':
128
                    $colName = Item\Offer\Price::colPrefix() . 'price';
129 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...
130
                        $selectOptions['where'][] = [$colName, (float) $filter['min'], '>='];
131
                    }
132 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...
133
                        $selectOptions['where'][] = [$colName, (float) $filter['max'], '<='];
134
                    }
135
                    break;
136
                case 'options':
137
                case 'offerOptions':
138
                    if ($col == 'offerOptions') {
139
                        $paramPrefix = Item\Offer\Param::colPrefix();
140
                        $itemIndex = Item\Offer::index();
141
                        $optionIndex = Item\Offer\Option::index();
142
                        $table = Item\Offer\Param::table();
143
                    } else {
144
                        $paramPrefix = Item\Param::colPrefix();
145
                        $itemIndex = Item::index();
146
                        $optionIndex = Item\Option::index();
147
                        $table = Item\Param::table();
148
                    }
149
                    foreach ($filter as $optionId => $optionValue) {
150
                        $optionId = (int) $optionId;
151
                        if (is_array($optionValue)) {
152
                            $optionValueArr = [];
153
                            foreach ($optionValue as $val) {
154
                                $optionValueArr[] = \App::$cur->db->connection->pdo->quote($val);
155
                            }
156
                            $qstr = 'IN (' . implode(',', $optionValueArr) . ')';
157
                        } else {
158
                            $qstr = '= ' . \App::$cur->db->connection->pdo->quote($optionValue);
159
                        }
160
                        $selectOptions['join'][] = [$table, $itemIndex . ' = ' . 'option' . $optionId . '.' . $paramPrefix . $itemIndex . ' AND ' .
161
                            'option' . $optionId . '.' . $paramPrefix . $optionIndex . ' = "' . (int) $optionId . '" AND ' .
162
                            'option' . $optionId . '.' . $paramPrefix . 'value ' . $qstr . '',
163
                            'inner', 'option' . $optionId];
164
                    }
165
            }
166
        }
167
    }
168
169
    public static function categories(&$options, &$selectOptions) {
170
        if (empty($options['parent'])) {
171
            return;
172
        }
173
        if (strpos($options['parent'], ',') !== false) {
174
            $first = true;
175
            $where = [];
176
            foreach (explode(',', $options['parent']) as $categoryId) {
177
                if (!$categoryId) {
178
                    continue;
179
                }
180
                $category = Category::get($categoryId);
181
                $where[] = ['tree_path', $category->tree_path . (int) $categoryId . '/%', 'LIKE', $first ? 'AND' : 'OR'];
182
                $first = false;
183
            }
184
            $selectOptions['where'][] = $where;
185
        } else {
186
            $category = Category::get($options['parent']);
187
            $selectOptions['where'][] = ['tree_path', $category->tree_path . (int) $options['parent'] . '/%', 'LIKE'];
188
        }
189
    }
190
191
    public static function search(&$options, &$selectOptions) {
192
        if (empty($options['search'])) {
193
            return;
194
        }
195
        $searchStr = preg_replace('![^A-zА-я0-9 ]!iSu', ' ', $options['search']);
196
        $searchArr = [];
197
        foreach (explode(' ', $searchStr) as $part) {
198
            $part = trim($part);
199
            if ($part && strlen($part) > 2) {
200
                $searchArr[] = ['search_index', '%' . $part . '%', 'LIKE'];
201
            }
202
        }
203
        if (!empty($searchArr)) {
204
            $selectOptions['where'][] = $searchArr;
205
        }
206
    }
207
208
    public static function warehouse(&$options, &$selectOptions) {
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
209
        if (!empty(\App::$cur->Ecommerce->config['view_empty_warehouse'])) {
210
            return;
211
        }
212
        $warehouseIds = self::getWarehouses();
213
214
        $selectOptions['where'][] = [
215
            '(
216
          (SELECT COALESCE(sum(`' . Item\Offer\Warehouse::colPrefix() . 'count`),0) 
217
            FROM ' . \App::$cur->db->table_prefix . Item\Offer\Warehouse::table() . ' iciw 
218
            WHERE iciw.' . Item\Offer\Warehouse::colPrefix() . Item\Offer::index() . ' = ' . Item\Offer::index() . '
219
                ' . ($warehouseIds ? ' AND iciw.' . Item\Offer\Warehouse::colPrefix() . Warehouse::index() . ' IN(' . implode(',', $warehouseIds) . ')' : '') . '
220
            )
221
          -
222
          (SELECT COALESCE(sum(' . Warehouse\Block::colPrefix() . 'count) ,0)
223
            FROM ' . \App::$cur->db->table_prefix . Warehouse\Block::table() . ' iewb
224
            inner JOIN ' . \App::$cur->db->table_prefix . Cart::table() . ' icc ON icc.' . Cart::index() . ' = iewb.' . Warehouse\Block::colPrefix() . Cart::index() . ' AND (
225
                (`' . Cart::colPrefix() . 'warehouse_block` = 1 and `' . Cart::colPrefix() . 'cart_status_id` in(2,3,6)) ||
226
                (`' . Cart::colPrefix() . Cart\Status::index() . '` in(0,1) and `' . Cart::colPrefix() . 'date_last_activ` >=subdate(now(),INTERVAL 30 MINUTE))
227
            )
228
            WHERE iewb.' . Warehouse\Block::colPrefix() . Item\Offer::index() . ' = ' . Item\Offer::index() . ')
229
          )',
230
            0,
231
            '>'
232
        ];
233
    }
234
235
    public static function getWarehouses() {
236
        if (!\App::$cur->geography || !\Geography\City::$cur) {
237
            return [];
238
        }
239
        $warehouseIds = [];
240
        $warehouses = \Geography\City\Data::get([['code', 'warehouses'], ['city_id', \Geography\City::$cur->id]]);
241
        if ($warehouses && $warehouses->data) {
242
            foreach (explode(',', $warehouses->data) as $id) {
243
                $warehouseIds[$id] = $id;
244
            }
245
        }
246
        return $warehouseIds;
247
    }
248
249
}
250