Test Failed
Push — master ( 2a8a67...5ddd1f )
by Alexey
04:25
created

Model::save()   F

Complexity

Conditions 24
Paths 445

Size

Total Lines 71
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 96

Importance

Changes 0
Metric Value
cc 24
eloc 49
nc 445
nop 1
dl 0
loc 71
ccs 22
cts 44
cp 0.5
crap 96
rs 3.9341
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
    public static $loaded = [];
14
15
    /**
16
     * Object storage type
17
     *
18
     * @var array
19
     */
20
    public static $storage = ['type' => 'db'];
21
22
    /**
23
     * Object name
24
     *
25
     * @var string
26
     */
27
    public static $objectName = '';
28
29
    /**
30
     * App type for separate data storage
31
     *
32
     * @var string
33
     */
34
    public $appType = 'app';
35
36
    /**
37
     * Object current params
38
     *
39
     * @var array
40
     */
41
    public $_params = [];
42
43
    /**
44
     * List of changed params in current instance
45
     *
46
     * @var array
47
     */
48
    public $_changedParams = [];
49
50
    /**
51
     * Loaded relations
52
     *
53
     * @var array
54
     */
55
    public $loadedRelations = [];
56
57
    /**
58
     * Model name where this model uses as category
59
     *
60
     * @var string
61
     */
62
    public static $treeCategory = '';
63
64
    /**
65
     * Model name who uses as category in this model
66
     *
67
     * @var string
68
     */
69
    public static $categoryModel = '';
70
71
    /**
72
     * Col labels
73
     *
74
     * @var array
75
     */
76
    public static $labels = [];
77
78
    /**
79
     * Model forms
80
     *
81
     * @var array
82
     */
83
    public static $forms = [];
84
85
    /**
86
     * Model cols
87
     *
88
     * @var array
89
     */
90
    public static $cols = [];
91
92
    /**
93
     * Options group for display inforamtion from model
94
     *
95
     * @var array
96
     */
97
    public static $view = [];
98
99
    /**
100
     * List of relations need loaded with item
101
     *
102
     * @var array
103
     */
104
    public static $needJoin = [];
105
106
    /**
107
     * List of joins who need to laod
108
     *
109
     * @var array
110
     */
111
    public static $relJoins = [];
112
113
    /**
114
     * Set params when model create
115
     *
116 4
     * @param array $params
117 4
     */
118 4
    public function __construct($params = []) {
119
        $this->setParams($params);
120
    }
121
122
    public static $logging = true;
123
124
    /**
125
     * return object name
126
     *
127
     * @return string
128
     */
129
    public static function objectName() {
130
        return static::$objectName;
131
    }
132
133
    /**
134
     * Retrn col value with col params and relations path
135
     *
136
     * @param Model $object
137
     * @param string $valuePath
138
     * @param boolean $convert
139
     * @param boolean $manageHref
140
     * @return string
141
     */
142
    public static function getColValue($object, $valuePath, $convert = false, $manageHref = false) {
143
        if (is_array($object)) {
144
            $object = array_shift($object);
145
        }
146
        if (strpos($valuePath, ':')) {
147
            $rel = substr($valuePath, 0, strpos($valuePath, ':'));
148
            $param = substr($valuePath, strpos($valuePath, ':') + 1);
149
            if (!$object->$rel) {
150
                $modelName = get_class($object);
151
                $relations = $modelName::relations();
152
                if (empty($relations[$rel]['type']) || $relations[$rel]['type'] == 'one') {
153
                    return $object->{$relations[$rel]['col']};
154
                }
155
                return 0;
156
            }
157
            if (strpos($valuePath, ':')) {
158
                return self::getColValue($object->$rel, $param, $convert, $manageHref);
159
            } else {
160
                return $convert ? Model::resloveTypeValue($object->$rel, $param, $manageHref) : $object->$rel->$param;
161
            }
162
        } else {
163
            return $convert ? Model::resloveTypeValue($object, $valuePath, $manageHref) : $object->$valuePath;
164
        }
165
    }
166
167
    /**
168
     * Retrun value for view
169
     *
170
     * @param Model $item
171
     * @param string $colName
172
     * @param boolean $manageHref
173
     * @param array $params
0 ignored issues
show
Bug introduced by
There is no parameter named $params. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

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