Test Failed
Push — master ( 045277...23cc6e )
by Alexey
05:33
created

Model::logChanges()   D

Complexity

Conditions 31
Paths 10

Size

Total Lines 90
Code Lines 71

Duplication

Lines 20
Ratio 22.22 %

Code Coverage

Tests 17
CRAP Score 448.0451

Importance

Changes 0
Metric Value
cc 31
eloc 71
nc 10
nop 1
dl 20
loc 90
ccs 17
cts 70
cp 0.2429
crap 448.0451
rs 4.5358
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Log
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
class Model {
12
13
    /**
14
     * Object storage type
15
     *
16
     * @var array
17
     */
18
    public static $storage = ['type' => 'db'];
19
20
    /**
21
     * Object name
22
     *
23
     * @var string
24
     */
25
    public static $objectName = '';
26
27
    /**
28
     * App type for separate data storage
29
     *
30
     * @var string
31
     */
32
    public $appType = 'app';
33
34
    /**
35
     * Object current params
36
     *
37
     * @var array
38
     */
39
    public $_params = [];
40
41
    /**
42
     * List of changed params in current instance
43
     *
44
     * @var array
45
     */
46
    public $_changedParams = [];
47
48
    /**
49
     * Loaded relations
50
     *
51
     * @var array
52
     */
53
    public $loadedRelations = [];
54
55
    /**
56
     * Model name where this model uses as category
57
     *
58
     * @var string
59
     */
60
    public static $treeCategory = '';
61
62
    /**
63
     * Model name who uses as category in this model
64
     *
65
     * @var string
66
     */
67
    public static $categoryModel = '';
68
69
    /**
70
     * Col labels
71
     *
72
     * @var array
73
     */
74
    public static $labels = [];
75
76
    /**
77
     * Model forms
78
     *
79
     * @var array
80
     */
81
    public static $forms = [];
82
83
    /**
84
     * Model cols
85
     *
86
     * @var array
87
     */
88
    public static $cols = [];
89
90
    /**
91
     * Options group for display inforamtion from model
92
     *
93
     * @var array
94
     */
95
    public static $view = [];
96
97
    /**
98
     * List of relations need loaded with item
99
     *
100
     * @var array
101
     */
102
    public static $needJoin = [];
103
104
    /**
105
     * List of joins who need to laod
106
     *
107
     * @var array
108
     */
109
    public static $relJoins = [];
110
111
    /**
112
     * Set params when model create
113
     *
114
     * @param array $params
115
     */
116 4
    public function __construct($params = []) {
117 4
        $this->setParams($params);
118 4
    }
119
120
    public static $logging = true;
121
122
    /**
123
     * return object name
124
     *
125
     * @return string
126
     */
127
    public static function objectName() {
128
        return static::$objectName;
129
    }
130
131
    /**
132
     * Retrn col value with col params and relations path
133
     *
134
     * @param Model $object
135
     * @param string $valuePath
136
     * @param boolean $convert
137
     * @param boolean $manageHref
138
     * @return string
139
     */
140
    public static function getColValue($object, $valuePath, $convert = false, $manageHref = false) {
141
        if (strpos($valuePath, ':')) {
142
            $rel = substr($valuePath, 0, strpos($valuePath, ':'));
143
            $param = substr($valuePath, strpos($valuePath, ':') + 1);
144
            if (!$object->$rel) {
145
                $modelName = get_class($object);
146
                $relations = $modelName::relations();
147
                if (empty($relations[$rel]['type']) || $relations[$rel]['type'] == 'one') {
148
                    return $object->{$relations[$rel]['col']};
149
                }
150
                return 0;
151
            }
152
            if (strpos($valuePath, ':')) {
153
                return self::getColValue($object->$rel, $param, $convert, $manageHref);
154
            } else {
155
                return $convert ? Model::resloveTypeValue($object->$rel, $param, $manageHref) : $object->$rel->$param;
156
            }
157
        } else {
158
            return $convert ? Model::resloveTypeValue($object, $valuePath, $manageHref) : $object->$valuePath;
159
        }
160
    }
161
162
    /**
163
     * Retrun value for view
164
     *
165
     * @param Model $item
166
     * @param string $colName
167
     * @param boolean $manageHref
168
     * @return string
169
     */
170
    public static function resloveTypeValue($item, $colName, $manageHref = false) {
171
        $modelName = get_class($item);
172
        $colInfo = $modelName::getColInfo($colName);
173
        $type = !empty($colInfo['colParams']['type']) ? $colInfo['colParams']['type'] : 'string';
174
        $value = '';
175
        switch ($type) {
176
            case 'select':
177
                switch ($colInfo['colParams']['source']) {
178
                    case 'model':
179
                        $sourceValue = '';
180
                        if ($item->$colName) {
181
                            $sourceValue = $colInfo['colParams']['model']::get($item->$colName);
182
                        }
183
                        $value = $sourceValue ? $sourceValue->name() : 'Не задано';
184
                        break;
185
                    case 'array':
186
                        $value = !empty($colInfo['colParams']['sourceArray'][$item->$colName]) ? $colInfo['colParams']['sourceArray'][$item->$colName] : 'Не задано';
187
                        if (is_array($value) && $value['text']) {
188
                            $value = $value['text'];
189
                        }
190
                        break;
191
                    case 'bool':
192
                        return $item->$colName ? 'Да' : 'Нет';
193
                    case 'method':
194 View Code Duplication
                        if (!empty($colInfo['colParams']['params'])) {
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...
195
                            $values = call_user_func_array([App::$cur->$colInfo['colParams']['module'], $colInfo['colParams']['method']], $colInfo['colParams']['params']);
196
                        } else {
197
                            $values = \App::$cur->{$colInfo['colParams']['module']}->$colInfo['colParams']['method']();
198
                        }
199
                        $value = !empty($values[$item->$colName]) ? $values[$item->$colName] : 'Не задано';
200
                        break;
201
                    case 'void':
202
                        if (!empty($modelName::$cols[$colName]['value']['type']) && $modelName::$cols[$colName]['value']['type'] == 'moduleMethod') {
203
                            return \App::$cur->{$modelName::$cols[$colName]['value']['module']}->{$modelName::$cols[$colName]['value']['method']}($item, $colName, $modelName::$cols[$colName]);
204
                        }
205
                        break;
206
                    case 'relation':
207
                        $relations = $colInfo['modelName']::relations();
208
                        $relValue = $relations[$colInfo['colParams']['relation']]['model']::get($item->$colName);
209
                        $relModel = $relations[$colInfo['colParams']['relation']]['model'];
210
                        $relModel = strpos($relModel, '\\') === 0 ? substr($relModel, 1) : $relModel;
211
                        if ($manageHref) {
212
                            $value = $relValue ? "<a href='/admin/" . str_replace('\\', '/view/', $relModel) . "/" . $relValue->pk() . "'>" . $relValue->name() . "</a>" : 'Не задано';
213
                        } else {
214
                            $value = $relValue ? $relValue->name() : 'Не задано';
215
                        }
216
                        break;
217
                }
218
                break;
219
            case 'image':
220
                $file = Files\File::get($item->$colName);
221
                if ($file) {
222
                    $photoId = Tools::randomString();
223
                    $value = '<a href = "' . $file->path . '" id="' . $photoId . '" rel="fgall[allimg]"><img src="' . $file->path . '?resize=60x120" /></a>';
224
                    $value .= '<script>inji.onLoad(function(){$("[rel]").fancybox();});</script>';
225
                } else {
226
                    $value = '<img src="/static/system/images/no-image.png?resize=60x120" />';
227
                }
228
                break;
229
            case 'file':
230
                $file = Files\File::get($item->$colName);
231
                if ($file) {
232
                    $value = '<a href="' . $file->path . '">' . $file->name . '.' . $file->type->ext . '</a>';
233
                } else {
234
                    $value = 'Файл не загружен';
235
                }
236
                break;
237
            case 'bool':
238
                $value = $item->$colName ? 'Да' : 'Нет';
239
                break;
240
            case 'void':
241
                if (!empty($colInfo['colParams']['value']['type']) && $colInfo['colParams']['value']['type'] == 'moduleMethod') {
242
                    return \App::$cur->{$colInfo['colParams']['value']['module']}->{$colInfo['colParams']['value']['method']}($item, $colName, $colInfo['colParams']);
243
                }
244
                break;
245 View Code Duplication
            case 'map':
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
                if ($item->$colName && json_decode($item->$colName, true)) {
247
                    $addres = json_decode($item->$colName, true);
248
                    $name = $addres['address'] ? $addres['address'] : 'lat:' . $addres['lat'] . ': lng:' . $addres['lng'];
249
                    \App::$cur->libs->loadLib('yandexMap');
250
                    ob_start();
251
                    $uid = Tools::randomString();
252
                    ?>
253
                    <div id='map<?= $uid; ?>_container' style="display:none;">
254
                        <script>/*
255
                             <div id='map<?= $uid; ?>' style="width: 100%; height: 500px"></div>
256
                             <script>
257
                             var myMap<?= $uid; ?>;
258
                             var myMap<?= $uid; ?>CurPin;
259
                             inji.onLoad(function () {
260
                             ymaps.ready(init<?= $uid; ?>);
261
                             function init<?= $uid; ?>() {
262
                             var myPlacemark;
263
                             myMap<?= $uid; ?> = new ymaps.Map("map<?= $uid; ?>", {
264
                             center: ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"],
265
                             zoom: 13
266
                             });
267
                             myCoords = ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"];
268
                             myMap<?= $uid; ?>CurPin = new ymaps.Placemark(myCoords,
269
                             {iconContent: "<?= $addres['address']; ?>"},
270
                             {preset: 'islands#greenStretchyIcon'}
271
                             );
272
                             myMap<?= $uid; ?>.geoObjects.add(myMap<?= $uid; ?>CurPin, 0);
273
                             }
274
                             window['init<?= $uid; ?>'] = init<?= $uid; ?>;
275
                             });
276
                             */</script>
277
                    </div>
278
                    <?php
279
                    $content = ob_get_contents();
280
                    ob_end_clean();
281
                    $onclick = 'inji.Ui.modals.show("' . addcslashes($addres['address'], '"') . '", $("#map' . $uid . '_container script").html().replace(/^\/\*/g, "").replace(/\*\/$/g, "")+"</script>","mapmodal' . $uid . '","modal-lg");';
282
                    $onclick .= 'return false;';
283
                    $value = "<a href ='#' onclick='{$onclick}' >{$name}</a>";
284
                    $value .= $content;
285
                } else {
286
                    $value = 'Местоположение не заданно';
287
                }
288
289
                break;
290
            case 'dynamicType':
291
                switch ($colInfo['colParams']['typeSource']) {
292
                    case 'selfMethod':
293
                        $type = $item->{$colInfo['colParams']['selfMethod']}();
294
                        if (is_array($type)) {
295 View Code Duplication
                            if (strpos($type['relation'], ':')) {
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...
296
                                $relationPath = explode(':', $type['relation']);
297
                                $relationName = array_pop($relationPath);
298
                                $curItem = $item;
299
                                foreach ($relationPath as $path) {
300
                                    $curItem = $curItem->$path;
301
                                }
302
                                $itemModel = get_class($curItem);
303
                                $relation = $itemModel::getRelation($relationName);
304
                                $sourceModel = $relation['model'];
305
                            } else {
306
                                $relation = static::getRelation($type['relation']);
307
                                $sourceModel = $relation['model'];
308
                            }
309
                            $value = $sourceModel::get($item->$colName);
310
                            if ($value) {
311
                                $value = $value->name();
312
                            } else {
313
                                $value = $item->$colName;
314
                            }
315
                        } else {
316
                            switch ($type) {
317 View Code Duplication
                                case 'map':
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...
318
                                    if ($item->$colName && json_decode($item->$colName, true)) {
319
                                        $addres = json_decode($item->$colName, true);
320
                                        $name = $addres['address'] ? $addres['address'] : 'lat:' . $addres['lat'] . ': lng:' . $addres['lng'];
321
                                        \App::$cur->libs->loadLib('yandexMap');
322
                                        ob_start();
323
                                        $uid = Tools::randomString();
324
                                        ?>
325
                                        <div id='map<?= $uid; ?>_container' style="display:none;">
326
                                            <script>/*
327
                                                 <div id='map<?= $uid; ?>' style="width: 100%; height: 500px"></div>
328
                                                 <script>
329
                                                 var myMap<?= $uid; ?>;
330
                                                 var myMap<?= $uid; ?>CurPin;
331
                                                 inji.onLoad(function () {
332
                                                 ymaps.ready(init<?= $uid; ?>);
333
                                                 function init<?= $uid; ?>() {
334
                                                 var myPlacemark;
335
                                                 myMap<?= $uid; ?> = new ymaps.Map("map<?= $uid; ?>", {
336
                                                 center: ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"],
337
                                                 zoom: 13
338
                                                 });
339
                                                 myCoords = ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"];
340
                                                 myMap<?= $uid; ?>CurPin = new ymaps.Placemark(myCoords,
341
                                                 {iconContent: "<?= $addres['address']; ?>"},
342
                                                 {preset: 'islands#greenStretchyIcon'}
343
                                                 );
344
                                                 myMap<?= $uid; ?>.geoObjects.add(myMap<?= $uid; ?>CurPin, 0);
345
                                                 }
346
                                                 window['init<?= $uid; ?>'] = init<?= $uid; ?>;
347
                                                 });
348
                                                 */</script>
349
                                        </div>
350
                                        <?php
351
                                        $content = ob_get_contents();
352
                                        ob_end_clean();
353
                                        $onclick = 'inji.Ui.modals.show("' . addcslashes($addres['address'], '"') . '", $("#map' . $uid . '_container script").html().replace(/^\/\*/g, "").replace(/\*\/$/g, "")+"</script>","mapmodal' . $uid . '","modal-lg");';
354
                                        $onclick .= 'return false;';
355
                                        $value = "<a href ='#' onclick='{$onclick}' >{$name}</a>";
356
                                        $value .= $content;
357
                                    } else {
358
                                        $value = 'Местоположение не заданно';
359
                                    }
360
361
                                    break;
362
                                default:
363
                                    $value = $item->$colName;
364
                            }
365
                        }
366
                        break;
367
                }
368
                break;
369
            default:
370
                $value = $item->$colName;
371
                break;
372
        }
373
        return $value;
374
    }
375
376
    /**
377
     * Fix col prefix
378
     *
379
     * @param mixed $array
380
     * @param string $searchtype
381
     * @param string $rootModel
382 4
     * @return null
383 4
     */
384 4
    public static function fixPrefix(&$array, $searchtype = 'key', $rootModel = '') {
385 4
        if (!$rootModel) {
386 4
            $rootModel = get_called_class();
387 4
        }
388
        $cols = static::cols();
389
        if (!$array) {
390 4
            return;
391 4
        }
392 2
        if (!is_array($array)) {
393 2 View Code Duplication
            if (!isset($cols[static::colPrefix() . $array]) && isset(static::$cols[$array])) {
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...
394 2
                static::createCol($array);
395 4
                $cols = static::cols(true);
396 4
            }
397 4
            if (!isset($cols[$array]) && isset($cols[static::colPrefix() . $array])) {
398 4
                $array = static::colPrefix() . $array;
399
            } else {
400 4
                static::checkForJoin($array, $rootModel);
401
            }
402
            return;
403 1
        }
404
        switch ($searchtype) {
405
            case 'key':
406
                foreach ($array as $key => $item) {
407 View Code Duplication
                    if (!isset($cols[static::colPrefix() . $key]) && isset(static::$cols[$key])) {
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...
408
                        static::createCol($key);
409
                        $cols = static::cols(true);
410
                    }
411
                    if (!isset($cols[$key]) && isset($cols[static::colPrefix() . $key])) {
412
                        $array[static::colPrefix() . $key] = $item;
413
                        unset($array[$key]);
414
                        $key = static::colPrefix() . $key;
415
                    }
416
                    if (is_array($array[$key])) {
417
                        static::fixPrefix($array[$key], 'key', $rootModel);
418
                    } else {
419
                        static::checkForJoin($key, $rootModel);
420
                    }
421 1
                }
422 1
                break;
423 1
            case 'first':
424
                if (isset($array[0]) && is_string($array[0])) {
425
                    if (!isset($cols[static::colPrefix() . $array[0]]) && isset(static::$cols[$array[0]])) {
426
                        static::createCol($array[0]);
427 1
                        $cols = static::cols(true);
428 1
                    }
429 1 View Code Duplication
                    if (!isset($cols[$array[0]]) && isset($cols[static::colPrefix() . $array[0]])) {
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...
430
                        $array[0] = static::colPrefix() . $array[0];
431
                    } else {
432 1
                        static::checkForJoin($array[0], $rootModel);
433 1
                    }
434 1
                } elseif (isset($array[0]) && is_array($array[0])) {
435 1
                    foreach ($array as &$item) {
436 1
                        static::fixPrefix($item, 'first', $rootModel);
437 1
                    }
438
                }
439 1
                break;
440
        }
441
    }
442
443
    /**
444 4
     * @param boolean $new
445 4
     */
446
    public function logChanges($new) {
447
        if (!App::$cur->db->connect || !App::$cur->dashboard) {
448 4
            return false;
449 4
        }
450 4
        $class = get_class($this);
451
        if (!Model::$logging || !$class::$logging) {
452 2
            return false;
453 2
        }
454
        $user_id = class_exists('Users\User') ? \Users\User::$cur->id : 0;
455
        if (!$new && !empty($this->_changedParams)) {
456
            $activity = new Dashboard\Activity([
457
                'user_id' => $user_id,
458
                'module' => substr($class, 0, strpos($class, '\\')),
459
                'model' => $class,
460
                'item_id' => $this->pk(),
461
                'type' => 'changes'
462
            ]);
463
            $changes_text = [];
464
            foreach ($this->_changedParams as $fullColName => $oldValue) {
465
                $colName = substr($fullColName, strlen($class::colPrefix()));
466 View Code Duplication
                if (isset($class::$cols[$colName]['logging']) && !$class::$cols[$colName]['logging']) {
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...
467
                    continue;
468
                }
469
                $oldValueText = $oldValue;
470
                if (isset($class::$cols[$colName]) && $class::$cols[$colName]['type'] === 'select') {
471
                    switch ($class::$cols[$colName]['source']) {
472
                        case 'array':
473
                            $oldValueText = isset($class::$cols[$colName]['sourceArray'][$oldValue]) ? $class::$cols[$colName]['sourceArray'][$oldValue] : $oldValue;
474
                            break;
475 View Code Duplication
                        case 'relation':
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...
476
                            $relation = $class::getRelation($class::$cols[$colName]['relation']);
477
                            $relModel = $relation['model'];
478
                            $rel = $relModel::get($oldValue);
479
                            if ($rel) {
480
                                $oldValueText = $rel->name();
481
                            }
482
                    }
483
                }
484
                $newValueText = $this->$colName;
485
                if (isset($class::$cols[$colName]) && $class::$cols[$colName]['type'] === 'select') {
486
                    switch ($class::$cols[$colName]['source']) {
487
                        case 'array':
488
                            $newValueText = isset($class::$cols[$colName]['sourceArray'][$this->$colName]) ? $class::$cols[$colName]['sourceArray'][$this->$colName] : $this->$colName;
489
                            break;
490 View Code Duplication
                        case 'relation':
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...
491
                            $relation = $class::getRelation($class::$cols[$colName]['relation']);
492 2
                            $relModel = $relation['model'];
493 2
                            $rel = $relModel::get($this->$colName);
494 2
                            if ($rel) {
495 2
                                $newValueText = $rel->name();
496 2
                            }
497 2
                    }
498
                }
499 2
                if (strlen($oldValueText) + strlen($newValueText) < 200) {
500 2
                    $changes_text[] = (!empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName) . ": \"{$oldValueText}\" => \"{$newValueText}\"";
501 2
                } else {
502 2
                    $changes_text[] = !empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName;
503
                }
504
            }
505
            if (!$changes_text) {
506
                return false;
507
            }
508
            $activity->changes_text = implode(', ', $changes_text);
509
            $activity->save();
510
            foreach ($this->_changedParams as $fullColName => $oldValue) {
511 4
                $colName = substr($fullColName, strlen($class::colPrefix()));
512 View Code Duplication
                if (isset($class::$cols[$colName]['logging']) && !$class::$cols[$colName]['logging']) {
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...
513 4
                    continue;
514
                }
515
                $colName = substr($fullColName, strlen($class::colPrefix()));
516
                $change = new Dashboard\Activity\Change([
517
                    'activity_id' => $activity->id,
518
                    'col' => $colName,
519
                    'old' => $oldValue,
520
                    'new' => $this->$colName
521
                ]);
522
                $change->save();
523
            }
524
        } elseif ($new) {
525
            $activity = new Dashboard\Activity([
526
                'user_id' => $user_id,
527
                'module' => substr($class, 0, strpos($class, '\\')),
528
                'model' => $class,
529
                'item_id' => $this->pk(),
530
                'type' => 'new'
531
            ]);
532
            $activity->save();
533
        }
534
        return true;
535
    }
536 4
537
    /**
538
     * Check model relations path and load need relations
539
     *
540
     * @param string $col
541
     * @param string $rootModel
542
     */
543
    public static function checkForJoin(&$col, $rootModel) {
544
545
        if (strpos($col, ':') !== false) {
546
            $relations = static::relations();
547
            if (isset($relations[substr($col, 0, strpos($col, ':'))])) {
548
                $rel = substr($col, 0, strpos($col, ':'));
549
                $col = substr($col, strpos($col, ':') + 1);
550
551
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
552
                switch ($type) {
553 View Code Duplication
                    case 'to':
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...
554
                        $relCol = $relations[$rel]['col'];
555
                        static::fixPrefix($relCol);
556
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
557
                        break;
558
                    case 'one':
559 View Code Duplication
                    case 'many':
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...
560
                        $relCol = $relations[$rel]['col'];
561
                        $relations[$rel]['model']::fixPrefix($relCol);
562
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
563
                        break;
564
                }
565
                $relations[$rel]['model']::fixPrefix($col, 'key', $rootModel);
566
            }
567
        }
568
    }
569
570
    /**
571
     * Return full col information
572
     *
573
     * @param string $col
574
     * @return array
575
     */
576
    public static function getColInfo($col) {
577
        return static::parseColRecursion($col);
578
    }
579
580
    /**
581
     * Information extractor for col relations path
582
     *
583
     * @param string $info
584
     * @return array
585
     */
586
    public static function parseColRecursion($info) {
587
        if (is_string($info)) {
588
            $info = ['col' => $info, 'rawCol' => $info, 'modelName' => '', 'label' => '', 'joins' => []];
589
        }
590
        if (strpos($info['col'], ':') !== false) {
591
            $relations = static::relations();
592
            if (isset($relations[substr($info['col'], 0, strpos($info['col'], ':'))])) {
593
                $rel = substr($info['col'], 0, strpos($info['col'], ':'));
594
                $info['col'] = substr($info['col'], strpos($info['col'], ':') + 1);
595
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
596
                switch ($type) {
597 View Code Duplication
                    case 'to':
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...
598
                        $relCol = $relations[$rel]['col'];
599
                        static::fixPrefix($relCol);
600
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
601
                        break;
602 View Code Duplication
                    case 'one':
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...
603
                        $relCol = $relations[$rel]['col'];
604
                        $relations[$rel]['model']::fixPrefix($relCol);
605
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
606
                        break;
607
                }
608 4
                $info = $relations[$rel]['model']::parseColRecursion($info);
609 4
            }
610 1
        } else {
611
            $cols = static::cols();
612 4 View Code Duplication
            if (!empty(static::$labels[$info['col']])) {
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...
613 4
                $info['label'] = static::$labels[$info['col']];
614 4
            }
615 4
616
            if (isset(static::$cols[$info['col']])) {
617
                $info['colParams'] = static::$cols[$info['col']];
618
            } elseif (isset(static::$cols[str_replace(static::colPrefix(), '', $info['col'])])) {
619 4
                $info['colParams'] = static::$cols[str_replace(static::colPrefix(), '', $info['col'])];
620
            } else {
621
                $info['colParams'] = [];
622
            }
623 View Code Duplication
            if (!isset($cols[$info['col']]) && isset($cols[static::colPrefix() . $info['col']])) {
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...
624
                $info['col'] = static::colPrefix() . $info['col'];
625
            }
626
            $info['modelName'] = get_called_class();
627 3
        }
628 3 View Code Duplication
        if (!empty(static::$labels[$info['rawCol']])) {
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...
629
            $info['label'] = static::$labels[$info['rawCol']];
630
        }
631
        return $info;
632
    }
633
634
    /**
635
     * Return actual cols from data base
636
     *
637 4
     * @param boolean $refresh
638 4
     * @return array
639 1
     */
640
    public static function cols($refresh = false) {
641 4
        if (static::$storage['type'] == 'moduleConfig') {
642 4
            return [];
643 4
        }
644 4 View Code Duplication
        if (empty(Model::$cols[static::table()]) || $refresh) {
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...
645
            Model::$cols[static::table()] = App::$cur->db->getTableCols(static::table());
646 4
        }
647 4 View Code Duplication
        if (!Model::$cols[static::table()]) {
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...
648 4
            static::createTable();
649 4
            Model::$cols[static::table()] = App::$cur->db->getTableCols(static::table());
650 4
        }
651 4
        return Model::$cols[static::table()];
652 4
    }
653 1
654 1
    /**
655 4
     * Return cols indexes for create tables
656 4
     *
657 4
     * @return array
658 4
     */
659 1
    public static function indexes() {
660 1
        return [];
661 4
    }
662
663
    /**
664 4
     * Generate params string for col by name
665 4
     *
666 3
     * @param string $colName
667 3
     * @return false|string
668 3
     */
669 3
    public static function genColParams($colName) {
670 3
        if (empty(static::$cols[$colName]) || static::$storage['type'] == 'moduleConfig') {
671 3
            return false;
672 3
        }
673 3
        $null = ' NULL';
674 1
        if (empty(static::$cols[$colName]['null'])) {
675 1
            $null = ' NOT NULL';
676 3
        }
677 1
678 1
        $params = false;
679 3
        switch (static::$cols[$colName]['type']) {
680
            case 'select':
681
                switch (static::$cols[$colName]['source']) {
682 3
                    case 'relation':
683 1
                        $params = 'int(11) UNSIGNED' . $null;
684 1
                        break;
685 3
                    default:
686 2
                        $params = 'varchar(255)' . $null;
687 2
                }
688 4
                break;
689 4
            case 'image':
690
            case 'file':
691
                $params = 'int(11) UNSIGNED' . $null;
692
                break;
693
            case 'number':
694
                $params = 'int(11)' . $null;
695
                break;
696
            case 'text':
697
            case 'email':
698 2
                $params = 'varchar(255)' . $null;
699 2
                break;
700 2
            case 'html':
701
            case 'textarea':
702
            case 'json':
703 2
            case 'password':
704 2
            case 'dynamicType':
705 2
            case 'map':
706
                $params = 'text' . $null;
707
                break;
708
            case 'bool':
709
                $params = 'tinyint(1) UNSIGNED' . $null;
710 4
                break;
711 4
            case 'decimal':
712
                $params = 'decimal(8, 2)' . $null;
713
                break;
714 4
            case 'time':
715
                $params = 'time' . $null;
716
                break;
717
            case 'date':
718 4
                $params = 'date' . $null;
719 4
                break;
720
            case 'dateTime':
721
                $params = 'timestamp' . $null;
722
                break;
723 4
        }
724 4
        return $params;
725 4
    }
726 4
727 4
    /**
728
     * Create new col in data base
729
     *
730
     * @param string $colName
731
     * @return boolean|integer
732 4
     */
733
    public static function createCol($colName) {
734
        $cols = static::cols(true);
735
        if (!empty($cols[static::colPrefix() . $colName])) {
736 4
            return true;
737 4
        }
738 4
        $params = static::genColParams($colName);
739 4
        if ($params === false) {
740 4
            return false;
741 4
        }
742 4
        return App::$cur->db->addCol(static::table(), static::colPrefix() . $colName, $params);
743 4
    }
744
745 4
    public static function createTable() {
746 4
        if (static::$storage['type'] == 'moduleConfig') {
747 4
            return true;
748 4
        }
749 4
        if (!App::$cur->db) {
750 4
            return false;
751 4
        }
752 1
753 1
        $query = App::$cur->db->newQuery();
754 4
        if (!$query) {
755 4
            return false;
756 1
        }
757 1
758 1
        if (!isset($this)) {
759 1
            $tableName = static::table();
760
            $colPrefix = static::colPrefix();
761 4
            $indexes = static::indexes();
762 4
        } else {
763
            $tableName = $this->table();
764
            $colPrefix = $this->colPrefix();
765
            $indexes = $this->indexes();
766
        }
767
        if (App::$cur->db->tableExist($tableName)) {
768
            return true;
769
        }
770 4
        $cols = [
771 4
            $colPrefix . 'id' => 'pk'
772
        ];
773
        $className = get_called_class();
774
        if (!empty($className::$cols)) {
775
            foreach ($className::$cols as $colName => $colParams) {
776
                if ($colName == 'date_create') {
777
                    $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
778
                    continue;
779 4
                }
780
                $params = $className::genColParams($colName);
781 4
                if ($params) {
782
                    $cols[$colPrefix . $colName] = $params;
783
                }
784
            }
785
        }
786
        if (empty($cols[$colPrefix . 'date_create'])) {
787
            $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
788
        }
789 4
        $tableIndexes = [];
790 4
        if ($indexes) {
791 4
            foreach ($indexes as $indexName => $index) {
792 4
                $tableIndexes[] = $index['type'] . ' ' . App::$cur->db->table_prefix . $indexName . ' (' . implode(',', $index['cols']) . ')';
793
            }
794
        }
795
796
        $query->createTable($tableName, $cols, $tableIndexes);
797
        return true;
798
    }
799
800 1
    /**
801 1
     * Return table name
802
     *
803
     * @return string
804
     */
805
    public static function table() {
806
        return strtolower(str_replace('\\', '_', get_called_class()));
807
    }
808
809
    /**
810
     * Return table index col name
811
     *
812
     * @return string
813
     */
814
    public static function index() {
815
816
        return static::colPrefix() . 'id';
817
    }
818
819
    /**
820
     * Return col prefix
821
     *
822
     * @return string
823
     */
824
    public static function colPrefix() {
825
        $classPath = explode('\\', get_called_class());
826
        $classPath = array_slice($classPath, 1);
827
        return strtolower(implode('_', $classPath)) . '_';
828
    }
829
830
    /**
831
     * return relations list
832
     *
833
     * @return string
834
     */
835
    public static function relations() {
836
        return [];
837 4
    }
838 4
839
    /**
840
     * views list
841 4
     *
842 4
     * @return array
843 4
     */
844
    public static $views = [];
845 4
846 1
    /**
847 1
     * Return name of col with object name
848 4
     *
849
     * @return string
850 4
     */
851 4
    public static function nameCol() {
852 4
        return 'name';
853
    }
854
855
    /**
856
     * Return object name
857
     *
858
     * @return string
859
     */
860
    public function name() {
861
        return $this->{$this->nameCol()} ? $this->{$this->nameCol()} : '№' . $this->pk();
862
    }
863
864
    /**
865
     * Get single object from data base
866
     *
867
     * @param mixed $param
868
     * @param string $col
869 4
     * @param array $options
870 4
     * @return boolean|static
871 4
     */
872 1
    public static function get($param, $col = null, $options = []) {
873 1
        if (static::$storage['type'] == 'moduleConfig') {
874 4
            return static::getFromModuleStorage($param, $col, $options);
875
        }
876 3
        if (!empty($col)) {
877 3
            static::fixPrefix($col);
878 4
        }
879 4
880 4
        if (is_array($param)) {
881
            static::fixPrefix($param, 'first');
882
        }
883 4
        foreach (static::$relJoins as $join) {
884 4
            App::$cur->db->join($join[0], $join[1]);
885
        }
886
        static::$relJoins = [];
887
        foreach (static::$needJoin as $rel) {
888 4
            $relations = static::relations();
889
            if (isset($relations[$rel])) {
890
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
891
                switch ($type) {
892 4
                    case 'to':
893 4
                        $relCol = $relations[$rel]['col'];
894
                        static::fixPrefix($relCol);
895
                        App::$cur->db->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
896
                        break;
897
                    case 'one':
898
                        $col = $relations[$rel]['col'];
899
                        $relations[$rel]['model']::fixPrefix($col);
900
                        App::$cur->db->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
901 4
                        break;
902
                }
903
            }
904 4
        }
905
        static::$needJoin = [];
906
        if (is_array($param)) {
907
            App::$cur->db->where($param);
908
        } else {
909
            if ($col === null) {
910
911
                $col = static::index();
912
            }
913
            if ($param !== null) {
914
                $cols = static::cols();
915
                if (!isset($cols[$col]) && isset($cols[static::colPrefix() . $col])) {
916
                    $col = static::colPrefix() . $col;
917
                }
918
                App::$cur->db->where($col, $param);
919
            } else {
920
                return false;
921
            }
922
        }
923
        if (!App::$cur->db->where) {
924
            return false;
925
        }
926
        try {
927
            $result = App::$cur->db->select(static::table());
928
        } catch (PDOException $exc) {
929
            if ($exc->getCode() == '42S02') {
930
                static::createTable();
931
            } else {
932
                throw $exc;
933
            }
934
            $result = App::$cur->db->select(static::table());
935
        }
936
        if (!$result) {
937
            return false;
938
        }
939
        return $result->fetch(get_called_class());
940
    }
941
942
    /**
943
     * Old method
944
     *
945
     * @param type $options
946
     * @return Array
947
     */
948
    public static function get_list($options = [], $debug = false) {
949
        $query = App::$cur->db->newQuery();
950
        if (!$query) {
951
            return [];
952
        }
953
        if (!empty($options['where'])) {
954
            $query->where($options['where']);
955
        }
956
        if (!empty($options['cols'])) {
957
            $query->cols = $options['cols'];
958
        }
959
        if (!empty($options['group'])) {
960
            $query->group($options['group']);
961
        }
962
        if (!empty($options['having'])) {
963
            $query->having($options['having']);
964
        }
965
        if (!empty($options['order'])) {
966
            $query->order($options['order']);
967
        }
968
        if (!empty($options['join'])) {
969
            $query->join($options['join']);
970
        }
971
        if (!empty($options['distinct'])) {
972
            $query->distinct = $options['distinct'];
973
        }
974
975
        foreach (static::$relJoins as $join) {
976
            $query->join($join[0], $join[1]);
977
        }
978
        static::$relJoins = [];
979 View Code Duplication
        foreach (static::$needJoin as $rel) {
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...
980
            $relations = static::relations();
981
            if (isset($relations[$rel])) {
982
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
983
                switch ($type) {
984
                    case 'to':
985
                        $relCol = $relations[$rel]['col'];
986
                        static::fixPrefix($relCol);
987
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
988
                        break;
989
                    case 'one':
990
                        $col = $relations[$rel]['col'];
991
                        $relations[$rel]['model']::fixPrefix($col);
992
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
993
                        break;
994
                }
995
            }
996
        }
997
        static::$needJoin = [];
998
999 View Code Duplication
        if (!empty($options['limit'])) {
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...
1000
            $limit = (int)$options['limit'];
1001
        } else {
1002
            $limit = 0;
1003
        }
1004 View Code Duplication
        if (!empty($options['start'])) {
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...
1005
            $start = (int)$options['start'];
1006
        } else {
1007
            $start = 0;
1008
        }
1009
        if ($limit || $start) {
1010
            $query->limit($start, $limit);
1011
        }
1012
        if (isset($options['key'])) {
1013
            $key = $options['key'];
1014
        } else {
1015
            $key = static::index();
1016
        }
1017
1018
        if ($debug) {
1019
            $query->operation = 'SELECT';
1020
            $query->table = static::table();
1021
            return $query->buildQuery();
1022
        }
1023
        try {
1024
            $query->operation = 'SELECT';
1025
            $query->table = static::table();
1026
            $queryArr = $query->buildQuery();
1027
            $result = $query->query($queryArr);
1028
        } catch (PDOException $exc) {
1029
            if ($exc->getCode() == '42S02') {
1030
                static::createTable();
1031
                $result = $query->query($queryArr);
1032
            } else {
1033
                throw $exc;
1034
            }
1035
        }
1036
1037
        if (!empty($options['array'])) {
1038
            return $result->getArray($key);
1039
        }
1040
        $list = $result->getObjects(get_called_class(), $key);
1041 View Code Duplication
        if (!empty($options['forSelect'])) {
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...
1042
            $return = [];
1043
            foreach ($list as $key => $item) {
1044
                $return[$key] = $item->name();
1045
            }
1046
            return $return;
1047
        }
1048
        return $list;
1049
    }
1050
1051
    /**
1052
     * Return list of objects from data base
1053
     *
1054
     * @param array $options
1055
     * @return static[]
1056
     */
1057
    public static function getList($options = [], $debug = false) {
1058
        if (static::$storage['type'] != 'db') {
1059
            return static::getListFromModuleStorage($options);
1060
        }
1061
        if (!empty($options['where'])) {
1062
            static::fixPrefix($options['where'], 'first');
1063
        }
1064
        if (!empty($options['group'])) {
1065
            static::fixPrefix($options['group'], 'first');
1066
        }
1067
        if (!empty($options['order'])) {
1068
            static::fixPrefix($options['order'], 'first');
1069
        }
1070
        if (!empty($options['having'])) {
1071
            static::fixPrefix($options['having'], 'first');
1072
        }
1073
        return static::get_list($options, $debug);
1074
    }
1075
1076
    /**
1077
     * Get single item from module storage
1078
     *
1079
     * @param array $param
1080
     * @param string $col
1081
     * @param array $options
1082
     * @return boolean|\Model
1083
     */
1084
    public static function getFromModuleStorage($param = null, $col = null, $options = []) {
1085
        if ($col === null) {
1086
1087
            $col = static::index();
1088
        }
1089
        if ($param == null) {
1090
            return false;
1091
        }
1092
        $classPath = explode('\\', get_called_class());
1093 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
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...
1094
            $moduleConfig = Config::share($classPath[0]);
1095
        } else {
1096
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1097
        }
1098
        $appType = App::$cur->type;
1099 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
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...
1100
            if (!empty($options['appType'])) {
1101
                $appType = $options['appType'];
1102
            }
1103
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1104
        } else {
1105
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1106
        }
1107
        if (!empty($storage[$classPath[1]])) {
1108
            $items = $storage[$classPath[1]];
1109
            $class = get_called_class();
1110
            $where = is_array($param) ? $param : [$col, $param];
1111
            foreach ($items as $key => $item) {
1112
                if (!Model::checkWhere($item, $where)) {
1113
                    continue;
1114
                }
1115
                if (!empty($options['array'])) {
1116
                    return $item;
1117
                }
1118
                $item = new $class($item);
1119
                $item->appType = $appType;
1120
                return $item;
1121
            }
1122
        }
1123
        return false;
1124
    }
1125
1126
    /**
1127
     * Return list items from module storage
1128
     *
1129
     * @param array $options
1130
     * @return array
1131
     */
1132
    public static function getListFromModuleStorage($options = []) {
1133
        $classPath = explode('\\', get_called_class());
1134 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
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...
1135
            $moduleConfig = Config::share($classPath[0]);
1136
        } else {
1137
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1138
        }
1139 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
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...
1140
            if (empty($options['appType'])) {
1141
                $appType = App::$cur->type;
1142
            } else {
1143
                $appType = $options['appType'];
1144
            }
1145
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1146
        } else {
1147
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1148
        }
1149
        if (!empty($storage[$classPath[1]])) {
1150
            $items = [];
1151
            $class = get_called_class();
1152
            if (isset($options['key'])) {
1153
                $arrayKey = $options['key'];
1154
            } else {
1155
                $arrayKey = static::index();
1156
            }
1157
            foreach ($storage[$classPath[1]] as $key => $item) {
1158
                if (!empty($options['where']) && !Model::checkWhere($item, $options['where'])) {
1159
                    continue;
1160
                }
1161
                $items[$item[$arrayKey]] = new $class($item);
1162
            }
1163
            if (!empty($options['order'])) {
1164
                usort($items, function ($a, $b) use ($options) {
1165
                    if ($a->{$options['order'][0]} > $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1166
                        return 1;
1167
                    } elseif ($a->{$options['order'][0]} < $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1168
                        return -1;
1169
                    } elseif ($a->{$options['order'][0]} == $b->{$options['order'][0]} && $a->id > $b->id) {
1170
                        return 1;
1171
                    } elseif ($a->{$options['order'][0]} == $b->{$options['order'][0]} && $a->id < $b->id) {
1172
                        return -1;
1173
                    }
1174
                    return 0;
1175
                });
1176
            }
1177 View Code Duplication
            if (!empty($options['forSelect'])) {
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...
1178
                $return = [];
1179
                foreach ($items as $key => $item) {
1180
                    $return[$key] = $item->name();
1181
                }
1182
                return $return;
1183
            }
1184
            return $items;
1185
        }
1186
        return [];
1187
    }
1188
1189
    /**
1190
     * Return count of records from module storage
1191
     *
1192
     * @param array $options
1193
     * @return int
1194
     */
1195
    public static function getCountFromModuleStorage($options = []) {
1196
1197
        $classPath = explode('\\', get_called_class());
1198
        $count = 0;
1199
        if (empty($options['appType'])) {
1200
            $appType = App::$cur->type;
1201
        } else {
1202
            $appType = $options['appType'];
1203
        }
1204 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
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...
1205
            $moduleConfig = Config::share($classPath[0]);
1206
        } else {
1207
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1208
        }
1209
        if (!empty($moduleConfig['storage'][$appType][$classPath[1]])) {
1210
            $items = $moduleConfig['storage'][$appType][$classPath[1]];
1211
            if (empty($options['where'])) {
1212
                return count($items);
1213
            }
1214
            foreach ($items as $key => $item) {
1215
                if (!empty($options['where'])) {
1216
                    if (Model::checkWhere($item, $options['where'])) {
1217
                        $count++;
1218
                    }
1219
                } else {
1220
                    $count++;
1221
                }
1222
            }
1223
        }
1224
        return $count;
1225
    }
1226
1227
    /**
1228
     * Check where for module storage query
1229
     *
1230
     * @param array $item
1231
     * @param array|string $where
1232
     * @param string $value
1233
     * @param string $operation
1234
     * @param string $concatenation
1235
     * @return boolean
1236
     */
1237
    public static function checkWhere($item = [], $where = '', $value = '', $operation = '=', $concatenation = 'AND') {
1238
1239
        if (is_array($where)) {
1240
            if (is_array($where[0])) {
1241
                $result = true;
1242
                foreach ($where as $key => $whereItem) {
1243
                    $concatenation = empty($whereItem[3]) ? 'AND' : strtoupper($whereItem[3]);
1244
                    switch ($concatenation) {
1245 View Code Duplication
                        case 'AND':
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...
1246
                            $result = $result && forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1247
                            break;
1248 View Code Duplication
                        case 'OR':
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...
1249
                            $result = $result || forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1250
                            break;
1251
                    }
1252
                }
1253
1254
                return $result;
1255
            } else {
1256
                return forward_static_call_array(['Model', 'checkWhere'], array_merge([$item], $where));
1257
            }
1258
        }
1259
        if (!isset($item[$where]) && !$value) {
1260
            return true;
1261
        }
1262
        if (!isset($item[$where]) && $value) {
1263
            return false;
1264
        }
1265
        if ($item[$where] == $value) {
1266
            return true;
1267
        }
1268
        return false;
1269
    }
1270
1271
    /**
1272
     * Return count of records from data base
1273
     *
1274
     * @param array $options
1275
     * @return array|int
1276
     */
1277
    public static function getCount($options = []) {
1278
        if (static::$storage['type'] == 'moduleConfig') {
1279
            return static::getCountFromModuleStorage($options);
1280
        }
1281
        $query = App::$cur->db->newQuery();
1282
        if (!$query) {
1283
            return 0;
1284
        }
1285
        if (!empty($options['where'])) {
1286
            static::fixPrefix($options['where'], 'first');
1287
        }
1288
        if (!empty($options['group'])) {
1289
            static::fixPrefix($options['group'], 'first');
1290
        }
1291
        if (!empty($options['order'])) {
1292
            static::fixPrefix($options['order'], 'first');
1293
        }
1294
        if (!empty($options['where'])) {
1295
            $query->where($options['where']);
1296
        }
1297
        if (!empty($options['join'])) {
1298
            $query->join($options['join']);
1299
        }
1300
        if (!empty($options['order'])) {
1301
            $query->order($options['order']);
1302
        }
1303 View Code Duplication
        if (!empty($options['limit'])) {
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...
1304
            $limit = (int)$options['limit'];
1305
        } else {
1306
            $limit = 0;
1307
        }
1308 View Code Duplication
        if (!empty($options['start'])) {
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...
1309
            $start = (int)$options['start'];
1310
        } else {
1311
            $start = 0;
1312
        }
1313
        if ($limit || $start) {
1314
            $query->limit($start, $limit);
1315
        }
1316
1317
        foreach (static::$relJoins as $join) {
1318
            $query->join($join[0], $join[1]);
1319
        }
1320
        static::$relJoins = [];
1321 View Code Duplication
        foreach (static::$needJoin as $rel) {
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...
1322
            $relations = static::relations();
1323
            if (isset($relations[$rel])) {
1324
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
1325
                switch ($type) {
1326
                    case 'to':
1327
                        $relCol = $relations[$rel]['col'];
1328
                        static::fixPrefix($relCol);
1329
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
1330
                        break;
1331
                    case 'one':
1332
                        $col = $relations[$rel]['col'];
1333
                        $relations[$rel]['model']::fixPrefix($col);
1334
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
1335
                        break;
1336
                }
1337
            }
1338
        }
1339
        static::$needJoin = [];
1340
        $cols = 'COUNT(';
1341
1342
        if (!empty($options['distinct'])) {
1343
            if (is_bool($options['distinct'])) {
1344
                $cols .= 'DISTINCT *';
1345
            } else {
1346
                $cols .= "DISTINCT {$options['distinct']}";
1347
            }
1348
        } else {
1349
            $cols .= '*';
1350
        }
1351
        $cols .= ') as `count`' . (!empty($options['cols']) ? ',' . $options['cols'] : '');
1352
        $query->cols = $cols;
1353
        if (!empty($options['group'])) {
1354
            $query->group($options['group']);
1355
        }
1356
        try {
1357
            $result = $query->select(static::table());
1358
        } catch (PDOException $exc) {
1359
            if ($exc->getCode() == '42S02') {
1360
                static::createTable();
1361
            } else {
1362
                throw $exc;
1363
            }
1364
            $result = $query->select(static::table());
1365 4
        }
1366 4
        if (!empty($options['group'])) {
1367
            $count = $result->getArray();
1368
            return $count;
1369
        } else {
1370
            $count = $result->fetch();
1371
            return $count['count'];
1372 4
        }
1373
    }
1374 4
1375
    /**
1376
     * Update records in data base
1377
     *
1378
     * @param array $params
1379
     * @param array $where
1380
     * @return false|null
1381
     */
1382 1
    public static function update($params, $where = []) {
1383
        static::fixPrefix($params);
1384 1
1385 1
        $cols = self::cols();
1386 1
1387 1
        $values = [];
1388
        foreach ($cols as $col => $param) {
1389 1
            if (isset($params[$col])) {
1390
                $values[$col] = $params[$col];
1391
            }
1392 1
        }
1393
        if (empty($values)) {
1394
            return false;
1395 1
        }
1396 1
1397
        if (!empty($where)) {
1398
            static::fixPrefix($where, 'first');
1399 1
1400
            App::$cur->db->where($where);
1401 1
        }
1402 1
        App::$cur->db->update(static::table(), $values);
1403
    }
1404
1405 1
    /**
1406
     * Return primary key of object
1407
     *
1408 1
     * @return mixed
1409
     */
1410
    public function pk() {
1411
        return $this->{$this->index()};
1412
    }
1413
1414
    /**
1415
     * Before save trigger
1416 1
     */
1417 1
    public function beforeSave() {
1418 1
1419 1
    }
1420
1421 1
    /**
1422 1
     * Save object to module storage
1423 1
     *
1424
     * @param array $options
1425
     * @return boolean
1426 1
     */
1427 1
    public function saveModuleStorage($options) {
1428 1
1429
        $col = static::index();
1430
        $id = $this->pk();
1431 1
        $appType = '';
1432
        $classPath = explode('\\', get_called_class());
1433
1434 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
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...
1435
            $moduleConfig = Config::share($classPath[0]);
1436
        } else {
1437
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1438
        }
1439
1440 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
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...
1441
            if (empty($options['appType'])) {
1442
                $appType = App::$cur->type;
1443
            } else {
1444
                $appType = $options['appType'];
1445
            }
1446
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1447
        } else {
1448
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1449
        }
1450
        if (empty($storage[$classPath[1]])) {
1451
            $storage[$classPath[1]] = [];
1452
        }
1453
        if ($id) {
1454 View Code Duplication
            foreach ($storage[$classPath[1]] as $key => $item) {
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...
1455
                if ($item[$col] == $id) {
1456
                    $storage[$classPath[1]][$key] = $this->_params;
1457
                    break;
1458
                }
1459
            }
1460
        } else {
1461
            $id = !empty($storage['scheme'][$classPath[1]]['ai']) ? $storage['scheme'][$classPath[1]]['ai'] : 1;
1462
            $this->$col = $id;
1463
            $storage['scheme'][$classPath[1]]['ai'] = $id + 1;
1464
            $storage[$classPath[1]][] = $this->_params;
1465
        }
1466 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
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...
1467
            $moduleConfig['storage'][$appType] = $storage;
1468
        } else {
1469
            $moduleConfig['storage'] = $storage;
1470
        }
1471 View Code Duplication
        if (empty(static::$storage['options']['share'])) {
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...
1472
            Config::save('module', $moduleConfig, $classPath[0]);
1473
        } else {
1474
            Config::save('share', $moduleConfig, $classPath[0]);
1475
        }
1476
        return true;
1477
    }
1478
1479
    /**
1480
     * Update tree path category
1481
     */
1482
    public function changeCategoryTree() {
1483
        $class = get_class($this);
1484
        $itemModel = $class::$treeCategory;
1485
        $oldPath = $this->tree_path;
1486
        $this->tree_path = $this->getCatalogTree($this);
1487
        $itemsTable = \App::$cur->db->table_prefix . $itemModel::table();
1488
        $itemTreeCol = $itemModel::colPrefix() . 'tree_path';
1489
1490
        $categoryTreeCol = $this->colPrefix() . 'tree_path';
1491
        $categoryTable = \App::$cur->db->table_prefix . $this->table();
1492
        if ($oldPath) {
1493
            \App::$cur->db->query('UPDATE
1494
                ' . $categoryTable . ' 
1495
                    SET 
1496
                        ' . $categoryTreeCol . ' = REPLACE(' . $categoryTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1497
                    WHERE ' . $categoryTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1498
1499
            \App::$cur->db->query('UPDATE
1500
                ' . $itemsTable . '
1501
                    SET 
1502 4
                        ' . $itemTreeCol . ' = REPLACE(' . $itemTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1503
                    WHERE ' . $itemTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1504 4
        }
1505 1
        $itemModel::update([$itemTreeCol => $this->tree_path . $this->id . '/'], [$itemModel::colPrefix() . $this->index(), $this->id]);
1506
    }
1507 4
1508 4
    /**
1509
     * Return tree path
1510
     *
1511 4
     * @param \Model $catalog
1512
     * @return string
1513
     */
1514 4
    public function getCatalogTree($catalog) {
1515 3
        $catalogClass = get_class($catalog);
1516 3
        $catalogParent = $catalogClass::get($catalog->parent_id);
1517 4
        if ($catalog && $catalogParent) {
1518 4
            if ($catalogParent->tree_path) {
1519
                return $catalogParent->tree_path . $catalogParent->id . '/';
1520 4
            } else {
1521 4
                return $this->getCatalogTree($catalogParent) . $catalogParent->id . '/';
1522 4
            }
1523 4
        }
1524 4
        return '/';
1525 4
    }
1526 4
1527 4
    /**
1528
     * Update tree path item
1529
     */
1530 4
    public function changeItemTree() {
1531
        $class = get_class($this);
1532 4
        $categoryModel = $class::$categoryModel;
1533
        $category = $categoryModel::get($this->{$categoryModel::index()});
1534
        if ($category) {
1535
            $this->tree_path = $category->tree_path . $category->pk() . '/';
1536 4
        } else {
1537 3
            $this->tree_path = '/';
1538 3
        }
1539 3
    }
1540 3
1541 3
    /**
1542
     * Save object to data base
1543
     *
1544
     * @param array $options
1545 3
     * @return boolean|int
1546 4
     */
1547 4
    public function save($options = []) {
1548
1549 4
        if (static::$storage['type'] == 'moduleConfig') {
1550 4
            return static::saveModuleStorage($options);
1551
        }
1552 4
        $class = get_class($this);
1553 4
        if ($class::$categoryModel) {
1554
            $this->changeItemTree();
1555
        }
1556
        if ($class::$treeCategory) {
1557
            $this->changeCategoryTree();
1558
        }
1559 4
        if (!empty($this->_changedParams) && $this->pk()) {
1560 4
            Inji::$inst->event('modelItemParamsChanged-' . get_called_class(), $this);
1561 4
        }
1562 4
        $this->beforeSave();
1563 4
        $values = [];
1564 4
1565
        foreach ($this->cols() as $col => $param) {
1566
            if (in_array($col, array_keys($this->_params)) && (!$this->pk() || ($this->pk() && in_array($col, array_keys($this->_changedParams))))) {
1567
                $values[$col] = $this->_params[$col];
1568
            }
1569
        }
1570 4
        if (!$this->pk()) {
1571
            foreach ($class::$cols as $colName => $params) {
1572 4
                $class::fixPrefix($colName);
1573
                if (isset($params['default']) && !isset($values[$colName])) {
1574
                    $this->_params[$colName] = $values[$colName] = $params['default'];
1575
                }
1576
            }
1577 1
        }
1578
1579 1
        if (empty($values) && empty($options['empty'])) {
1580
            return false;
1581
        }
1582
1583
        if ($this->pk()) {
1584
            $new = false;
1585
            if ($this->get($this->_params[$this->index()])) {
1586
                App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1587
                App::$cur->db->update($this->table(), $values);
1588
            } else {
1589
1590
                $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1591
            }
1592
        } else {
1593
            $new = true;
1594
            //print_r($this->_params);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% 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...
1595
            $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1596
        }
1597
        $this->logChanges($new);
1598
        App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1599
        try {
1600
            $result = App::$cur->db->select($this->table());
1601
        } catch (PDOException $exc) {
1602
            if ($exc->getCode() == '42S02') {
1603
                $this->createTable();
1604
            }
1605
            $result = App::$cur->db->select($this->table());
1606
        }
1607
        $this->_params = $result->fetch();
1608
        if ($new) {
1609
            Inji::$inst->event('modelCreatedItem-' . get_called_class(), $this);
1610
        }
1611
        $this->afterSave();
1612
        return $this->{$this->index()};
1613
    }
1614
1615
    /**
1616
     * After save trigger
1617
     */
1618
    public function afterSave() {
1619
1620
    }
1621
1622
    /**
1623
     * Before delete trigger
1624
     */
1625
    public function beforeDelete() {
1626
1627
    }
1628
1629
    /**
1630
     * Delete item from module storage
1631
     *
1632
     * @param array $options
1633
     * @return boolean
1634
     */
1635
    public function deleteFromModuleStorage($options) {
1636
1637
        $col = static::index();
1638 1
        $id = $this->pk();
1639 1
        $appType = '';
1640
        $classPath = explode('\\', get_called_class());
1641 1 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
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...
1642
            $moduleConfig = Config::share($classPath[0]);
1643
        } else {
1644 1
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1645 1
        }
1646 1
1647 1 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
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...
1648 1
            if (empty($options['appType'])) {
1649 1
                $appType = App::$cur->type;
1650
            } else {
1651
                $appType = $options['appType'];
1652
            }
1653
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1654
        } else {
1655
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1656
        }
1657
        if (empty($storage[$classPath[1]])) {
1658
            $storage[$classPath[1]] = [];
1659
        }
1660 4 View Code Duplication
        foreach ($storage[$classPath[1]] as $key => $item) {
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...
1661 4
1662
            if ($item[$col] == $id) {
1663
                unset($storage[$classPath[1]][$key]);
1664
                break;
1665 4
            }
1666 4
        }
1667 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
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...
1668
            $moduleConfig['storage'][$appType] = $storage;
1669
        } else {
1670
            $moduleConfig['storage'] = $storage;
1671 1
        }
1672 View Code Duplication
        if (empty(static::$storage['options']['share'])) {
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...
1673 1
            Config::save('module', $moduleConfig, $classPath[0]);
1674
        } else {
1675
            Config::save('share', $moduleConfig, $classPath[0]);
1676
        }
1677
        return true;
1678
    }
1679
1680
    /**
1681
     * Delete item from data base
1682
     *
1683
     * @param array $options
1684
     * @return boolean
1685
     */
1686
    public function delete($options = []) {
1687
        $this->beforeDelete();
1688
1689
        if (static::$storage['type'] == 'moduleConfig') {
1690
            return static::deleteFromModuleStorage($options);
1691
        }
1692
        if (!empty($this->_params[$this->index()])) {
1693
            App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1694
            $result = App::$cur->db->delete($this->table());
1695
            if ($result) {
1696 4
                $this->afterDelete();
1697 4
                return $result;
1698 2
            }
1699 4
        }
1700 4
        return false;
1701
    }
1702
1703
    /**
1704
     * Delete items from data base
1705
     *
1706
     * @param array $where
1707
     */
1708 4
    public static function deleteList($where = []) {
1709 4
        if (!empty($where)) {
1710 4
            static::fixPrefix($where, 'first');
1711
            App::$cur->db->where($where);
1712
        }
1713
        App::$cur->db->delete(static::table());
1714
    }
1715
1716
    /**
1717
     * After delete trigger
1718
     */
1719
    public function afterDelete() {
1720 4
1721 4
    }
1722 4
1723 2
    /**
1724 2
     * find relation for col name
1725 2
     *
1726
     * @param string $col
1727
     * @return array|null
1728 2
     */
1729 2
    public static function findRelation($col) {
1730
1731 2
        foreach (static::relations() as $relName => $rel) {
1732
            if ($rel['col'] == $col) {
1733
                return $relName;
1734
            }
1735
        }
1736
        return null;
1737
    }
1738
1739
    /**
1740
     * Set params for model
1741
     *
1742
     * @param array $params
1743
     */
1744
    public function setParams($params) {
1745
        foreach ($params as $paramName => $value) {
1746
            $this->$paramName = $value;
1747
        }
1748
    }
1749
1750
    /**
1751
     * Return relation
1752
     *
1753
     * @param string $relName
1754
     * @return array|boolean
1755 2
     */
1756
    public static function getRelation($relName) {
1757
        $relations = static::relations();
1758
        return !empty($relations[$relName]) ? $relations[$relName] : false;
1759
    }
1760
1761
    /**
1762
     * Load relation
1763
     *
1764
     * @param string $name
1765
     * @param array $params
1766
     * @return null|array|integer|\Model
1767
     */
1768
    public function loadRelation($name, $params = []) {
1769
        $relation = static::getRelation($name);
1770
        if ($relation) {
1771
            if (!isset($relation['type'])) {
1772
                $type = 'to';
1773
            } else {
1774
                $type = $relation['type'];
1775
            }
1776
            $getCol = null;
1777
            $getParams = [];
1778
            switch ($type) {
1779 2
                case 'relModel':
1780
                    if (!$this->pk()) {
1781
                        return [];
1782
                    }
1783 2
                    $fixedCol = $relation['model']::index();
1784 2
                    $relation['relModel']::fixPrefix($fixedCol);
1785
                    $join = [$relation['relModel']::table(), $relation['relModel']::colPrefix() . $this->index() . ' = ' . $this->pk() . ' and ' . $relation['relModel']::colPrefix() . $relation['model']::index() . ' = ' . $relation['model']::index(), 'INNER'];
1786
                    $getType = 'getList';
1787 2
                    $options = [
1788 2
                        'join' => [$join],
1789 2
                        'where' => (isset($params['where'])) ? $params['where'] : ((isset($relation['where'])) ? $relation['where'] : null),
1790 2
                        'array' => (!empty($params['array'])) ? true : false,
1791 2
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1792
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1793
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1794
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1795
                    ];
1796
                    break;
1797 2
                case 'many':
1798 2
                    if (!$this->{$this->index()}) {
1799 2
                        return [];
1800
                    }
1801
                    $getType = 'getList';
1802
                    $options = [
1803 2
                        'join' => (isset($relation['join'])) ? $relation['join'] : null,
1804
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1805 4
                        'array' => (!empty($params['array'])) ? true : false,
1806
                        'forSelect' => (!empty($params['forSelect'])) ? true : false,
1807
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1808
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1809
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1810
                        'appType' => (isset($params['appType'])) ? $params['appType'] : ((isset($relation['appType'])) ? $relation['appType'] : null),
1811
                        'where' => []
1812
                    ];
1813
                    $options['where'][] = [$relation['col'], $this->{$this->index()}];
1814
                    if (!empty($relation['where'])) {
1815
                        $options['where'] = array_merge($options['where'], [$relation['where']]);
1816
                    }
1817
                    if (!empty($params['where'])) {
1818
                        $options['where'] = array_merge($options['where'], [$params['where']]);
1819
                    }
1820
                    break;
1821
                case 'one':
1822
                    $getType = 'get';
1823
                    $options = [$relation['col'], $this->pk()];
1824
                    break;
1825
                default:
1826
                    if ($this->$relation['col'] === null) {
1827
                        return null;
1828
                    }
1829
                    $getType = 'get';
1830
                    $options = $this->$relation['col'];
1831
                    $getParams['appType'] = $this->appType;
1832
            }
1833
            if (!empty($params['count'])) {
1834
                if (class_exists($relation['model'])) {
1835
                    return $relation['model']::getCount($options);
1836
                }
1837
                return 0;
1838
            } else {
1839
                if (class_exists($relation['model'])) {
1840
                    $this->loadedRelations[$name][json_encode($params)] = $relation['model']::$getType($options, $getCol, $getParams);
1841
                } else {
1842
                    $this->loadedRelations[$name][json_encode($params)] = [];
1843
                }
1844
            }
1845
            return $this->loadedRelations[$name][json_encode($params)];
1846
        }
1847
        return null;
1848
    }
1849
1850
    /**
1851
     * Add relation item
1852
     *
1853
     * @param string $relName
1854
     * @param \Model $objectId
1855
     * @return \Model|boolean
1856
     */
1857
    public function addRelation($relName, $objectId) {
1858
        $relation = $this->getRelation($relName);
1859
        if ($relation) {
1860
            $rel = $relation['relModel']::get([[$relation['model']::index(), $objectId], [$this->index(), $this->pk()]]);
1861
            if (!$rel) {
1862
                $rel = new $relation['relModel']([
1863
                    $relation['model']::index() => $objectId,
1864
                    $this->index() => $this->pk()
1865
                ]);
1866
                $rel->save();
1867
            }
1868
            return $rel;
1869
        }
1870
        return false;
1871
    }
1872
1873
    /**
1874
     * Check user access for form
1875
     *
1876
     * @param string $formName
1877
     * @return boolean
1878
     */
1879
    public function checkFormAccess($formName) {
1880
        if ($formName == 'manage' && !Users\User::$cur->isAdmin()) {
1881
            return false;
1882 4
        }
1883 4
        return true;
1884 4
    }
1885 4
1886 4
    /**
1887
     * Check access for model
1888 4
     *
1889 2
     * @param string $mode
1890
     * @param \Users\User $user
1891 4
     * @return boolean
1892
     */
1893
    public function checkAccess($mode = 'write', $user = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $mode 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...
1894
        if (!$user) {
1895
            $user = \Users\User::$cur;
1896
        }
1897
        return $user->isAdmin();
1898
    }
1899
1900
    /**
1901
     * Param and relation with params getter
1902
     *
1903
     * @param string $name
1904
     * @param array $params
1905
     * @return \Value|mixed
1906
     */
1907
    public function __call($name, $params) {
1908
        $fixedName = $name;
1909
        static::fixPrefix($fixedName);
1910 View Code Duplication
        if (isset($this->_params[$fixedName])) {
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...
1911
            return new Value($this, $fixedName);
1912
        } elseif (isset($this->_params[$name])) {
1913
            return new Value($this, $name);
1914
        }
1915
        return call_user_func_array([$this, 'loadRelation'], array_merge([$name], $params));
1916
    }
1917
1918
    /**
1919
     * Param and relation getter
1920
     *
1921
     * @param string $name
1922
     * @return mixed
1923
     */
1924
    public function __get($name) {
1925
        $fixedName = $name;
1926
        static::fixPrefix($fixedName);
1927
        if (isset($this->_params[$fixedName])) {
1928
            return $this->_params[$fixedName];
1929
        }
1930
        if (isset($this->loadedRelations[$name][json_encode([])])) {
1931
            return $this->loadedRelations[$name][json_encode([])];
1932
        }
1933
        return $this->loadRelation($name);
1934
    }
1935
1936
    /**
1937
     * Return model value in object
1938
     *
1939
     * @param string $name
1940
     * @return \Value|null
1941
     */
1942
    public function value($name) {
1943
        $fixedName = $name;
1944
        static::fixPrefix($fixedName);
1945 View Code Duplication
        if (isset($this->_params[$fixedName])) {
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...
1946
            return new Value($this, $fixedName);
1947
        } elseif ($this->_params[$name]) {
1948
            return new Value($this, $name);
1949
        }
1950
        return null;
1951
    }
1952
1953
    /**
1954
     * Return manager filters
1955
     *
1956
     * @return array
1957
     */
1958 4
    public static function managerFilters() {
1959 4
        return [];
1960 4
    }
1961 4
1962 4
    /**
1963
     * Return validators for cols
1964
     *
1965 4
     * @return array
1966 2
     */
1967 2
    public static function validators() {
1968 4
        return [];
1969 4
    }
1970 4
1971
    /**
1972
     * Return validator by name
1973 4
     *
1974 2
     * @param string $name
1975 2
     * @return array
1976 4
     */
1977 1
    public static function validator($name) {
1978 1
        $validators = static::validators();
1979 4
        if (!empty($validators[$name])) {
1980 4
            return $validators[$name];
1981 4
        }
1982 4
        return [];
1983 3
    }
1984 3
1985 4
    public function genViewLink() {
1986 4
        $className = get_class($this);
1987
        $link = substr($className, 0, strpos($className, '\\'));
1988
        $link .= '/view/';
1989
        $link .= str_replace('\\', '%5C', substr($className, strpos($className, '\\') + 1));
1990
        $link .= "/{$this->id}";
1991
        return $link;
1992
    }
1993
1994
    public function extract($model) {
1995
        $params = [];
1996
        if (empty($this->_params[$model::index()])) {
1997
            return false;
1998
        }
1999
        $params['id'] = $this->_params[$model::index()];
2000
        $indexes = array_keys($this->_params);
2001
        foreach ($model::$cols as $colName => $colParams) {
2002
            if (in_array($model::colPrefix() . $colName, $indexes)) {
2003
                $params[$model::colPrefix() . $colName] = $this->_params[$model::colPrefix() . $colName];
2004
            }
2005
        }
2006
        if (!$params) {
2007
            return FALSE;
2008
        }
2009
        return new $model($params);
2010
    }
2011
2012
    /**
2013
     * Set handler for model params
2014
     *
2015
     * @param string $name
2016
     * @param mixed $value
2017
     */
2018
    public function __set($name, $value) {
2019
        static::fixPrefix($name);
2020
        $className = get_called_class();
2021
        $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $name);
2022
        if (!$value && !empty(static::$cols[$shortName]) && in_array('emptyValue', array_keys(static::$cols[$shortName]))) {
2023
            $value = static::$cols[$shortName]['emptyValue'];
2024
        }
2025
        if (is_null($value) && empty(static::$cols[$shortName]['null'])) {
2026
            $value = '';
2027
        }
2028
        if (!empty($className::$cols[$shortName])) {
2029
            switch ($className::$cols[$shortName]['type']) {
2030
                case 'decimal':
2031
                    $value = (float)$value;
2032
                    break;
2033
                case 'number':
2034
                    $value = (int)$value;
2035
                    break;
2036
                case 'bool':
2037
                    $value = (bool)$value;
2038
                    break;
2039
            }
2040
        }
2041 View Code Duplication
        if (in_array($name, array_keys($this->_params)) && $this->_params[$name] != $value && !in_array($name, array_keys($this->_changedParams))) {
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...
2042
            $this->_changedParams[$name] = $this->_params[$name];
2043
        }
2044
        $this->_params[$name] = $value;
2045 View Code Duplication
        if (in_array($name, array_keys($this->_params)) && in_array($name, array_keys($this->_changedParams)) && $this->_changedParams[$name] == $value) {
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...
2046
            unset($this->_changedParams[$name]);
2047
        }
2048
    }
2049
2050
    /**
2051
     * Isset handler for model params
2052
     *
2053
     * @param string $name
2054
     * @return boolean
2055
     */
2056
    public function __isset($name) {
2057
        static::fixPrefix($name);
2058
        return isset($this->_params[$name]);
2059
    }
2060
2061
    /**
2062
     * Convert object to string
2063
     *
2064
     * @return string
2065
     */
2066
    public function __toString() {
2067
        return $this->name();
2068
    }
2069
}