Completed
Push — master ( 7855c2...b6f450 )
by Alexey
07:32
created

Item   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 337
Duplicated Lines 11.87 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 40
loc 337
rs 8.3206
c 2
b 0
f 0
wmc 51
lcom 1
cbo 8

9 Methods

Rating   Name   Duplication   Size   Complexity  
C simpleItemHandler() 18 51 8
A realType() 0 15 4
A indexes() 0 22 1
D beforeSave() 22 35 17
B relations() 0 39 1
B getPrice() 0 16 8
A name() 0 9 4
B beforeDelete() 0 17 7
A getHref() 0 3 1

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

1
<?php
2
3
/**
4
 * Item
5
 *
6
 * @author Alexey Krupskiy <[email protected]>
7
 * @link http://inji.ru/
8
 * @copyright 2015 Alexey Krupskiy
9
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
10
 */
11
12
namespace Ecommerce;
13
14
class Item extends \Model {
15
16
  public static $categoryModel = 'Ecommerce\Category';
17
  public static $objectName = 'Товар';
18
  public static $labels = [
19
      'name' => 'Название',
20
      'alias' => 'Алиас',
21
      'category_id' => 'Раздел',
22
      'description' => 'Описание',
23
      'item_type_id' => 'Тип товара',
24
      'image_file_id' => 'Изображение',
25
      'best' => 'Лучшее предложение',
26
      'options' => 'Параметры',
27
      'offers' => 'Торговые предложения',
28
      'widget' => 'Виджет для отображения в каталоге',
29
      'view' => 'Шаблон для отображения полной информации',
30
      'deleted' => 'Удален',
31
      'imgs' => 'Фото'
32
  ];
33
  public static $cols = [
34
      //Основные параметры
35
      'category_id' => ['type' => 'select', 'source' => 'relation', 'relation' => 'category'],
36
      'image_file_id' => ['type' => 'image'],
37
      'name' => ['type' => 'text'],
38
      'alias' => ['type' => 'text'],
39
      'description' => ['type' => 'html'],
40
      'item_type_id' => ['type' => 'select', 'source' => 'relation', 'relation' => 'type'],
41
      'best' => ['type' => 'bool'],
42
      'deleted' => ['type' => 'bool'],
43
      //Системные
44
      'user_id' => ['type' => 'select', 'source' => 'relation', 'relation' => 'user'],
45
      'weight' => ['type' => 'number'],
46
      'sales' => ['type' => 'number'],
47
      'imported' => ['type' => 'text'],
48
      'tree_path' => ['type' => 'text'],
49
      'search_index' => ['type' => 'text'],
50
      'date_create' => ['type' => 'dateTime'],
51
      'widget' => ['type' => 'text'],
52
      'view' => ['type' => 'text'],
53
      //Менеджеры
54
      'options' => ['type' => 'dataManager', 'relation' => 'options'],
55
      'offers' => ['type' => 'dataManager', 'relation' => 'offers'],
56
      'imgs' => ['type' => 'dataManager', 'relation' => 'images'],
57
  ];
58
59
  public static function simpleItemHandler($request) {
1 ignored issue
show
Coding Style introduced by
simpleItemHandler uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
60
    if ($request) {
61
      $item = new Item();
62
      $item->name = $request['name'];
63
      $item->description = $request['description'];
64
      $item->category_id = $request['category'];
65
      $item->save();
66
      if (!empty($_FILES['ActiveForm_simpleItem']['tmp_name']['Ecommerce\Item']['image'])) {
67
        $file_id = \App::$primary->files->upload([
68
            'tmp_name' => $_FILES['ActiveForm_simpleItem']['tmp_name']['Ecommerce\Item']['image'],
69
            'name' => $_FILES['ActiveForm_simpleItem']['name']['Ecommerce\Item']['image'],
70
            'type' => $_FILES['ActiveForm_simpleItem']['type']['Ecommerce\Item']['image'],
71
            'size' => $_FILES['ActiveForm_simpleItem']['size']['Ecommerce\Item']['image'],
72
            'error' => $_FILES['ActiveForm_simpleItem']['error']['Ecommerce\Item']['image'],
73
                ], [
74
            'upload_code' => 'activeForm:' . 'Ecommerce\Item' . ':' . $item->pk(),
75
            'accept_group' => 'image'
76
        ]);
77
        if ($file_id) {
78
          $item->image_file_id = $file_id;
79
          $item->save();
80
        }
81
      }
82 View Code Duplication
      if (!empty($request['options']['option'])) {
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...
83
        foreach ($request['options']['option'] as $key => $option_id) {
84
          $param = new Item\Param();
85
          $param->item_id = $item->id;
86
          $param->value = $request['options']['value'][$key];
87
          $param->item_option_id = $option_id;
88
          $param->save();
89
        }
90
      }
91
      $offer = new Item\Offer();
92
      $offer->item_id = $item->id;
93
      $offer->save();
94 View Code Duplication
      if (!empty($request['offerOptions']['option'])) {
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...
95
        foreach ($request['offerOptions']['option'] as $key => $option_id) {
96
          $param = new Item\Offer\Param();
97
          $param->item_offer_id = $offer->id;
98
          $param->value = $request['offerOptions']['value'][$key];
99
          $param->item_offer_option_id = $option_id;
100
          $param->save();
101
        }
102
      }
103
      $price = new Item\Offer\Price();
104
      $price->price = $request['price'];
105
      $price->item_offer_id = $offer->id;
106
      $price->currency_id = $request['currency'];
107
      $price->save();
108
    }
109
  }
110
111
  public static $dataManagers = [
112
      'manager' => [
113
          'name' => 'Товары',
114
          'cols' => [
115
              'name',
116
              'imgs',
117
              'category_id',
118
              'item_type_id',
119
              'best',
120
              'deleted',
121
              'options',
122
              'offers',
123
          ],
124
          'categorys' => [
125
              'model' => 'Ecommerce\Category',
126
          ],
127
          'sortMode' => true
128
      ]
129
  ];
130
  public static $forms = [
131
      'manager' => [
132
          'map' => [
133
              ['name', 'alias'],
134
              ['category_id', 'item_type_id', 'deleted'],
135
              ['widget', 'view'],
136
              ['best', 'image_file_id'],
137
              ['description'],
138
              ['imgs'],
139
              ['options'],
140
              ['offers'],
141
          ]
142
      ],
143
      'simpleItem' => [
144
          'options' => [
145
              'access' => [
146
                  'groups' => [
147
                      3
148
                  ]
149
              ],
150
          ],
151
          'name' => 'Простой товар с ценой',
152
          'inputs' => [
153
              'name' => ['type' => 'text'],
154
              'description' => ['type' => 'html'],
155
              'category' => ['type' => 'select', 'source' => 'model', 'model' => 'Ecommerce\Category', 'label' => 'Категория'],
156
              'image' => ['type' => 'image', 'label' => 'Изображение'],
157
              'price' => ['type' => 'text', 'label' => 'Цена'],
158
              'currency' => ['type' => 'select', 'source' => 'model', 'model' => 'Money\Currency', 'label' => 'Валюта'],
159
              'options' => ['type' => 'dynamicList', 'source' => 'options', 'options' => [
160
                      'inputs' => [
161
                          'option' => ['type' => 'select', 'source' => 'model', 'model' => 'Ecommerce\Item\Option', 'label' => 'Свойство'],
162
                          'value' => ['type' => 'dynamicType', 'typeSource' => 'selfMethod', 'selfMethod' => 'realType', 'label' => 'Значение'],
163
                      ]
164
                  ]
165
              ],
166
              'offerOptions' => ['type' => 'dynamicList', 'source' => 'options', 'options' => [
167
                      'inputs' => [
168
                          'option' => ['type' => 'select', 'source' => 'model', 'model' => 'Ecommerce\Item\Offer\Option', 'label' => 'Свойство предложения'],
169
                          'value' => ['type' => 'dynamicType', 'typeSource' => 'selfMethod', 'selfMethod' => 'realType', 'label' => 'Значение'],
170
                      ]
171
                  ],'label'=>'Параметры предлоежния'
172
              ]
173
          ],
174
          'map' => [
175
              ['name', 'category'],
176
              ['description'],
177
              ['image'],
178
              ['price', 'currency'],
179
              ['options'],
180
              ['offerOptions'],
181
          ],
182
          'handler' => 'simpleItemHandler'
183
      ]
184
  ];
185
186
  public function realType() {
187
    if ($this->option && $this->option->type) {
188
      $type = $this->option->type;
189
190
      if ($type == 'select') {
191
        return [
192
            'type' => 'select',
193
            'source' => 'relation',
194
            'relation' => 'option:items',
195
        ];
196
      }
197
      return $type;
198
    }
199
    return 'text';
200
  }
201
202
  public static function indexes() {
203
    return [
204
        'ecommerce_item_item_category_id' => [
205
            'type' => 'INDEX',
206
            'cols' => [
207
                'item_category_id'
208
            ]
209
        ],
210
        'inji_ecommerce_item_item_tree_path' => [
211
            'type' => 'INDEX',
212
            'cols' => [
213
                'item_tree_path(255)'
214
            ]
215
        ],
216
        'ecommerce_item_item_search_index' => [
217
            'type' => 'INDEX',
218
            'cols' => [
219
                'item_search_index(255)'
220
            ]
221
        ],
222
    ];
223
  }
224
225
  public function beforeSave() {
226
227
    if ($this->id) {
228
      $this->search_index = $this->name . ' ';
229
      if ($this->category) {
230
        $this->search_index .= $this->category->name . ' ';
231
      }
232 View Code Duplication
      if ($this->options) {
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...
233
        foreach ($this->options as $option) {
234
          if ($option->item_option_searchable && $option->value) {
235
            if ($option->item_option_type != 'select') {
236
              $this->search_index .= $option->value . ' ';
237
            } elseif (!empty($option->option->items[$option->value])) {
238
              $option->option->items[$option->value]->value . ' ';
239
            }
240
          }
241
        }
242
      }
243
      if ($this->offers) {
244
        foreach ($this->offers as $offer) {
245 View Code Duplication
          if ($offer->options) {
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...
246
            foreach ($offer->options as $option) {
247
              if ($option->item_offer_option_searchable && $option->value) {
248
                if ($option->item_offer_option_type != 'select') {
249
                  $this->search_index .= $option->value . ' ';
250
                } elseif (!empty($option->option->items[$option->value])) {
251
                  $option->option->items[$option->value]->value . ' ';
252
                }
253
              }
254
            }
255
          }
256
        }
257
      }
258
    }
259
  }
260
261
  public static function relations() {
262
263
    return [
264
        'category' => [
265
            'model' => 'Ecommerce\Category',
266
            'col' => 'category_id'
267
        ],
268
        'options' => [
269
            'type' => 'many',
270
            'model' => 'Ecommerce\Item\Param',
271
            'col' => 'item_id',
272
            //'resultKey' => 'code',
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
273
            'resultKey' => 'item_option_id',
274
            'join' => [Item\Option::table(), Item\Option::index() . ' = ' . Item\Param::colPrefix() . Item\Option::index()]
275
        ],
276
        'offers' => [
277
            'type' => 'many',
278
            'model' => 'Ecommerce\Item\Offer',
279
            'col' => 'item_id',
280
        ],
281
        'type' => [
282
            'model' => 'Ecommerce\Item\Type',
283
            'col' => 'item_type_id',
284
        ],
285
        'image' => [
286
            'model' => 'Files\File',
287
            'col' => 'image_file_id'
288
        ],
289
        'images' => [
290
            'type' => 'many',
291
            'model' => 'Ecommerce\Item\Image',
292
            'col' => 'item_id'
293
        ],
294
        'user' => [
295
            'model' => 'Users\User',
296
            'col' => 'user_id'
297
        ]
298
    ];
299
  }
300
301
  public function getPrice() {
302
    $offers = $this->offers(['key' => false]);
303
    $curPrice = null;
304
305
    foreach ($offers[0]->prices as $price) {
306
      if (!$price->type) {
307
        $curPrice = $price;
308
      } elseif (
309
              (!$price->type->roles && !$curPrice) ||
310
              ($price->type->roles && !$curPrice && strpos($price->type->roles, "|" . \Users\User::$cur->role_id . "|") !== false)
311
      ) {
312
        $curPrice = $price;
313
      }
314
    }
315
    return $curPrice;
316
  }
317
318
  public function name() {
319
    if (!empty(\App::$primary->ecommerce->config['item_option_as_name'])) {
320
      $param = Item\Param::get([['item_id', $this->id], ['item_option_id', \App::$primary->ecommerce->config['item_option_as_name']]]);
321
      if ($param && $param->value) {
322
        return $param->value;
323
      }
324
    }
325
    return $this->name;
326
  }
327
328
  public function beforeDelete() {
329
    if ($this->id) {
330
      if ($this->options) {
331
        foreach ($this->options as $option) {
332
          $option->delete();
333
        }
334
      }
335
      if ($this->offers) {
336
        foreach ($this->offers as $offer) {
337
          $offer->delete();
338
        }
339
      }
340
      if ($this->image) {
341
        $this->image->delete();
342
      }
343
    }
344
  }
345
346
  public function getHref() {
347
    return "/ecommerce/view/{$this->pk()}";
348
  }
349
350
}
351