Test Failed
Push — master ( afbf72...42b272 )
by Alexey
04:43
created

Model::afterDelete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Log
5
 *
6
 * @author Alexey Krupskiy <[email protected]>
7
 * @link http://inji.ru/
8
 * @copyright 2015 Alexey Krupskiy
9
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
10
 */
11
class Model {
12
13
    /**
14
     * Object storage type
15
     *
16
     * @var array
17
     */
18
    public static $storage = ['type' => 'db'];
19
20
    /**
21
     * Object name
22
     *
23
     * @var string
24
     */
25
    public static $objectName = '';
26
27
    /**
28
     * App type for separate data storage
29
     *
30
     * @var string
31
     */
32
    public $appType = 'app';
33
34
    /**
35
     * Object current params
36
     *
37
     * @var array
38
     */
39
    public $_params = [];
40
41
    /**
42
     * List of changed params in current instance
43
     *
44
     * @var array
45
     */
46
    public $_changedParams = [];
47
48
    /**
49
     * Loaded relations
50
     *
51
     * @var array
52
     */
53
    public $loadedRelations = [];
54
55
    /**
56
     * Model name where this model uses as category
57
     *
58
     * @var string
59
     */
60
    public static $treeCategory = '';
61
62
    /**
63
     * Model name who uses as category in this model
64
     *
65
     * @var string
66
     */
67
    public static $categoryModel = '';
68
69
    /**
70
     * Col labels
71
     *
72
     * @var array
73
     */
74
    public static $labels = [];
75
76
    /**
77
     * Model forms
78
     *
79
     * @var array
80
     */
81
    public static $forms = [];
82
83
    /**
84
     * Model cols
85
     *
86
     * @var array
87
     */
88
    public static $cols = [];
89
90
    /**
91
     * Options group for display inforamtion from model
92
     *
93
     * @var array
94
     */
95
    public static $view = [];
96
97
    /**
98
     * List of relations need loaded with item
99
     *
100
     * @var array
101
     */
102
    public static $needJoin = [];
103
104
    /**
105
     * List of joins who need to laod
106
     *
107
     * @var array
108
     */
109
    public static $relJoins = [];
110
111
    /**
112
     * Set params when model create
113
     *
114
     * @param array $params
115
     */
116 4
    public function __construct($params = []) {
117 4
        $this->setParams($params);
118 4
    }
119
120
    public static $logging = true;
121
122
    /**
123
     * return object name
124
     *
125
     * @return string
126
     */
127
    public static function objectName() {
128
        return static::$objectName;
129
    }
130
131
    /**
132
     * Retrn col value with col params and relations path
133
     *
134
     * @param Model $object
135
     * @param string $valuePath
136
     * @param boolean $convert
137
     * @param boolean $manageHref
138
     * @return string
139
     */
140
    public static function getColValue($object, $valuePath, $convert = false, $manageHref = false) {
141
        if (strpos($valuePath, ':')) {
142
            $rel = substr($valuePath, 0, strpos($valuePath, ':'));
143
            $param = substr($valuePath, strpos($valuePath, ':') + 1);
144
            if (!$object->$rel) {
145
                $modelName = get_class($object);
146
                $relations = $modelName::relations();
147
                if (empty($relations[$rel]['type']) || $relations[$rel]['type'] == 'one') {
148
                    return $object->{$relations[$rel]['col']};
149
                }
150
                return 0;
151
            }
152
            if (strpos($valuePath, ':')) {
153
                return self::getColValue($object->$rel, $param, $convert, $manageHref);
154
            } else {
155
                return $convert ? Model::resloveTypeValue($object->$rel, $param, $manageHref) : $object->$rel->$param;
156
            }
157
        } else {
158
            return $convert ? Model::resloveTypeValue($object, $valuePath, $manageHref) : $object->$valuePath;
159
        }
160
    }
161
162
    /**
163
     * Retrun value for view
164
     *
165
     * @param Model $item
166
     * @param string $colName
167
     * @param boolean $manageHref
168
     * @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...
169
     * @return string
170
     */
171
    public static function resloveTypeValue($item, $colName, $manageHref = false, $colInfo = []) {
172
        $modelName = get_class($item);
173
        if (!$colInfo) {
174
            $colInfo = $modelName::getColInfo($colName);
175
        }
176
        $type = !empty($colInfo['colParams']['type']) ? $colInfo['colParams']['type'] : 'string';
177
        $value = '';
178
        switch ($type) {
179
            case 'autocomplete':
180
                $options = $colInfo['colParams']['options'];
181 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...
182
                    $snippets = \App::$cur->Ui->getSnippets('autocomplete');
183
                    if (isset($snippets[$options['snippet']])) {
184
                        $value = $snippets[$options['snippet']]['getValueText']($item->$colName, $options['snippetParams']);
185
                    }
186
                }
187
                break;
188
            case 'select':
189
                switch ($colInfo['colParams']['source']) {
190
                    case 'model':
191
                        $sourceValue = '';
192
                        if ($item->$colName) {
193
                            $sourceValue = $colInfo['colParams']['model']::get($item->$colName);
194
                        }
195
                        $value = $sourceValue ? $sourceValue->name() : 'Не задано';
196
                        break;
197
                    case 'array':
198
                        $value = !empty($colInfo['colParams']['sourceArray'][$item->$colName]) ? $colInfo['colParams']['sourceArray'][$item->$colName] : 'Не задано';
199
                        if (is_array($value) && $value['text']) {
200
                            $value = $value['text'];
201
                        }
202
                        break;
203
                    case 'bool':
204
                        return $item->$colName ? 'Да' : 'Нет';
205
                    case 'method':
206 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...
207
                            $values = call_user_func_array([App::$cur->$colInfo['colParams']['module'], $colInfo['colParams']['method']], $colInfo['colParams']['params']);
208
                        } else {
209
                            $values = \App::$cur->{$colInfo['colParams']['module']}->$colInfo['colParams']['method']();
210
                        }
211
                        $value = !empty($values[$item->$colName]) ? $values[$item->$colName] : 'Не задано';
212
                        break;
213
                    case 'void':
214
                        if (!empty($modelName::$cols[$colName]['value']['type']) && $modelName::$cols[$colName]['value']['type'] == 'moduleMethod') {
215
                            return \App::$cur->{$modelName::$cols[$colName]['value']['module']}->{$modelName::$cols[$colName]['value']['method']}($item, $colName, $modelName::$cols[$colName]);
216
                        }
217
                        break;
218
                    case 'relation':
219
                        if (strpos($colInfo['colParams']['relation'], ':')) {
220
                            $relationPath = explode(':', $colInfo['colParams']['relation']);
221
                            $relationName = array_pop($relationPath);
222
                            $curItem = $item;
223
                            foreach ($relationPath as $path) {
224
                                $curItem = $curItem->$path;
225
                            }
226
                            $itemModel = get_class($curItem);
227
                            $relation = $itemModel::getRelation($relationName);
228
                            $relModel = $relation['model'];
229
                        } else {
230
                            $relation = static::getRelation($colInfo['colParams']['relation']);
231
                            $relModel = $relation['model'];
232
                        }
233
                        $relValue = $relModel::get($item->$colName);
234
                        $relModel = strpos($relModel, '\\') === 0 ? substr($relModel, 1) : $relModel;
235
                        if ($manageHref) {
236
                            $value = $relValue ? "<a href='/admin/" . str_replace('\\', '/view/', $relModel) . "/" . $relValue->pk() . "'>" . $relValue->name() . "</a>" : 'Не задано';
237
                        } else {
238
                            $value = $relValue ? $relValue->name() : 'Не задано';
239
                        }
240
                        break;
241
                }
242
                break;
243
            case 'image':
244
                $file = Files\File::get($item->$colName);
245
                if ($file) {
246
                    $photoId = Tools::randomString();
247
                    $value = '<a href = "' . $file->path . '" id="' . $photoId . '" rel="fgall[allimg]"><img src="' . $file->path . '?resize=60x120" /></a>';
248
                    $value .= '<script>inji.onLoad(function(){$("[rel]").fancybox();});</script>';
249
                } else {
250
                    $value = '<img src="/static/system/images/no-image.png?resize=60x120" />';
251
                }
252
                break;
253
            case 'file':
254
                $file = Files\File::get($item->$colName);
255
                if ($file) {
256
                    $value = '<a href="' . $file->path . '">' . $file->name . '.' . $file->type->ext . '</a>';
257
                } else {
258
                    $value = 'Файл не загружен';
259
                }
260
                break;
261
            case 'bool':
262
                $value = $item->$colName ? 'Да' : 'Нет';
263
                break;
264
            case 'void':
265
                if (!empty($colInfo['colParams']['value']['type']) && $colInfo['colParams']['value']['type'] == 'moduleMethod') {
266
                    return \App::$cur->{$colInfo['colParams']['value']['module']}->{$colInfo['colParams']['value']['method']}($item, $colName, $colInfo['colParams']);
267
                }
268
                break;
269
            case 'map':
270
                if ($item->$colName && json_decode($item->$colName, true)) {
271
                    $addres = json_decode($item->$colName, true);
272
                    $name = $addres['address'] ? $addres['address'] : 'lat:' . $addres['lat'] . ': lng:' . $addres['lng'];
273
                    \App::$cur->libs->loadLib('yandexMap');
274
                    ob_start();
275
                    $uid = Tools::randomString();
276
                    ?>
277
                    <div id='map<?= $uid; ?>_container' style="display:none;">
278
                        <script>/*
279
                             <div id='map<?= $uid; ?>' style="width: 100%; height: 500px"></div>
280
                             <script>
281
                             var myMap<?= $uid; ?>;
282
                             var myMap<?= $uid; ?>CurPin;
283
                             inji.onLoad(function () {
284
                             ymaps.ready(init<?= $uid; ?>);
285
                             function init<?= $uid; ?>() {
286
                             var myPlacemark;
287
                             myMap<?= $uid; ?> = new ymaps.Map("map<?= $uid; ?>", {
288
                             center: ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"],
289
                             zoom: 13
290
                             });
291
                             myCoords = ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"];
292
                             myMap<?= $uid; ?>CurPin = new ymaps.Placemark(myCoords,
293
                             {iconContent: "<?= $addres['address']; ?>"},
294
                             {preset: 'islands#greenStretchyIcon'}
295
                             );
296
                             myMap<?= $uid; ?>.geoObjects.add(myMap<?= $uid; ?>CurPin, 0);
297
                             }
298
                             window['init<?= $uid; ?>'] = init<?= $uid; ?>;
299
                             });
300
                             */</script>
301
                    </div>
302
                    <?php
303
                    $content = ob_get_contents();
304
                    ob_end_clean();
305
                    $onclick = 'inji.Ui.modals.show("' . addcslashes($addres['address'], '"') . '", $("#map' . $uid . '_container script").html().replace(/^\/\*/g, "").replace(/\*\/$/g, "")+"</script>","mapmodal' . $uid . '","modal-lg");';
306
                    $onclick .= 'return false;';
307
                    $value = "<a href ='#' onclick='{$onclick}' >{$name}</a>";
308
                    $value .= $content;
309
                } else {
310
                    $value = 'Местоположение не заданно';
311
                }
312
313
                break;
314
            case 'dynamicType':
315
                switch ($colInfo['colParams']['typeSource']) {
316
                    case 'selfMethod':
317
                        $type = $item->{$colInfo['colParams']['selfMethod']}();
318
                        if (is_array($type)) {
319
                            $value = static::resloveTypeValue($item, $colName, $manageHref, ['colParams' => $type]);
320
                        } else {
321
                            $value = static::resloveTypeValue($item, $colName, $manageHref, ['colParams' => ['type' => $type]]);
322
                        }
323
                        break;
324
                }
325
                break;
326
            default:
327
                $value = $item->$colName;
328
        }
329
        return $value;
330
    }
331
332
    /**
333
     * Fix col prefix
334
     *
335
     * @param mixed $array
336
     * @param string $searchtype
337
     * @param string $rootModel
338
     * @return null
339
     */
340
    public static function fixPrefix(&$array, $searchtype = 'key', $rootModel = '') {
341
        if (!$rootModel) {
342
            $rootModel = get_called_class();
343
        }
344
        $cols = static::cols();
345
        if (!$array) {
346
            return;
347
        }
348
        if (!is_array($array)) {
349 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...
350
                static::createCol($array);
351
                $cols = static::cols(true);
352
            }
353
            if (!isset($cols[$array]) && isset($cols[static::colPrefix() . $array])) {
354
                $array = static::colPrefix() . $array;
355
            } else {
356
                static::checkForJoin($array, $rootModel);
357
            }
358
            return;
359
        }
360
        switch ($searchtype) {
361
            case 'key':
362
                foreach ($array as $key => $item) {
363 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...
364
                        static::createCol($key);
365
                        $cols = static::cols(true);
366
                    }
367
                    if (!isset($cols[$key]) && isset($cols[static::colPrefix() . $key])) {
368
                        $array[static::colPrefix() . $key] = $item;
369
                        unset($array[$key]);
370
                        $key = static::colPrefix() . $key;
371
                    }
372
                    if (is_array($array[$key])) {
373
                        static::fixPrefix($array[$key], 'key', $rootModel);
374
                    } else {
375
                        static::checkForJoin($key, $rootModel);
376
                    }
377
                }
378
                break;
379
            case 'first':
380
                if (isset($array[0]) && is_string($array[0])) {
381
                    if (!isset($cols[static::colPrefix() . $array[0]]) && isset(static::$cols[$array[0]])) {
382 4
                        static::createCol($array[0]);
383 4
                        $cols = static::cols(true);
384 4
                    }
385 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...
386 4
                        $array[0] = static::colPrefix() . $array[0];
387 4
                    } else {
388
                        static::checkForJoin($array[0], $rootModel);
389
                    }
390 4
                } elseif (isset($array[0]) && is_array($array[0])) {
391 4
                    foreach ($array as &$item) {
392 2
                        static::fixPrefix($item, 'first', $rootModel);
393 2
                    }
394 2
                }
395 4
                break;
396 4
        }
397 4
    }
398 4
399
    /**
400 4
     * @param boolean $new
401
     */
402
    public function logChanges($new) {
403 1
        if (!App::$cur->db->connect || !App::$cur->dashboard) {
404
            return false;
405
        }
406
        $class = get_class($this);
407
        if (!Model::$logging || !$class::$logging) {
408
            return false;
409
        }
410
        $user_id = class_exists('Users\User') ? \Users\User::$cur->id : 0;
411
        if (!$new && !empty($this->_changedParams)) {
412
            $activity = new Dashboard\Activity([
413
                'user_id' => $user_id,
414
                'module' => substr($class, 0, strpos($class, '\\')),
415
                'model' => $class,
416
                'item_id' => $this->pk(),
417
                'type' => 'changes'
418
            ]);
419
            $changes_text = [];
420
            foreach ($this->_changedParams as $fullColName => $oldValue) {
421 1
                $colName = substr($fullColName, strlen($class::colPrefix()));
422 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...
423 1
                    continue;
424
                }
425
                $oldValueText = $oldValue;
426
                if (isset($class::$cols[$colName]) && $class::$cols[$colName]['type'] === 'select') {
427 1
                    switch ($class::$cols[$colName]['source']) {
428 1
                        case 'array':
429 1
                            $oldValueText = isset($class::$cols[$colName]['sourceArray'][$oldValue]) ? $class::$cols[$colName]['sourceArray'][$oldValue] : $oldValue;
430
                            break;
431 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...
432 1
                            $relation = $class::getRelation($class::$cols[$colName]['relation']);
433 1
                            $relModel = $relation['model'];
434 1
                            $rel = $relModel::get($oldValue);
435 1
                            if ($rel) {
436 1
                                $oldValueText = $rel->name();
437 1
                            }
438
                    }
439 1
                }
440
                $newValueText = $this->$colName;
441
                if (isset($class::$cols[$colName]) && $class::$cols[$colName]['type'] === 'select') {
442
                    switch ($class::$cols[$colName]['source']) {
443
                        case 'array':
444 4
                            $newValueText = isset($class::$cols[$colName]['sourceArray'][$this->$colName]) ? $class::$cols[$colName]['sourceArray'][$this->$colName] : $this->$colName;
445 4
                            break;
446 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...
447
                            $relation = $class::getRelation($class::$cols[$colName]['relation']);
448 4
                            $relModel = $relation['model'];
449 4
                            $rel = $relModel::get($this->$colName);
450 4
                            if ($rel) {
451
                                $newValueText = $rel->name();
452 2
                            }
453 2
                    }
454
                }
455
                if (strlen($oldValueText) + strlen($newValueText) < 200) {
456
                    $changes_text[] = (!empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName) . ": \"{$oldValueText}\" => \"{$newValueText}\"";
457
                } else {
458
                    $changes_text[] = !empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName;
459
                }
460
            }
461
            if (!$changes_text) {
462
                return false;
463
            }
464
            $activity->changes_text = implode(', ', $changes_text);
465
            $activity->save();
466
            foreach ($this->_changedParams as $fullColName => $oldValue) {
467
                $colName = substr($fullColName, strlen($class::colPrefix()));
468 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...
469
                    continue;
470
                }
471
                $colName = substr($fullColName, strlen($class::colPrefix()));
472
                $change = new Dashboard\Activity\Change([
473
                    'activity_id' => $activity->id,
474
                    'col' => $colName,
475
                    'old' => $oldValue,
476
                    'new' => $this->$colName
477
                ]);
478
                $change->save();
479
            }
480
        } elseif ($new) {
481
            $activity = new Dashboard\Activity([
482
                'user_id' => $user_id,
483
                'module' => substr($class, 0, strpos($class, '\\')),
484
                'model' => $class,
485
                'item_id' => $this->pk(),
486
                'type' => 'new'
487
            ]);
488
            $activity->save();
489
        }
490
        return true;
491
    }
492 2
493 2
    /**
494 2
     * Check model relations path and load need relations
495 2
     *
496 2
     * @param string $col
497 2
     * @param string $rootModel
498
     */
499 2
    public static function checkForJoin(&$col, $rootModel) {
500 2
501 2
        if (strpos($col, ':') !== false) {
502 2
            $relations = static::relations();
503
            if (isset($relations[substr($col, 0, strpos($col, ':'))])) {
504
                $rel = substr($col, 0, strpos($col, ':'));
505
                $col = substr($col, strpos($col, ':') + 1);
506
507
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
508
                switch ($type) {
509 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...
510
                        $relCol = $relations[$rel]['col'];
511 4
                        static::fixPrefix($relCol);
512
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
513 4
                        break;
514
                    case 'one':
515 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...
516
                        $relCol = $relations[$rel]['col'];
517
                        $relations[$rel]['model']::fixPrefix($relCol);
518
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
519
                        break;
520
                }
521
                $relations[$rel]['model']::fixPrefix($col, 'key', $rootModel);
522
            }
523
        }
524
    }
525
526
    /**
527
     * Return full col information
528
     *
529
     * @param string $col
530
     * @return array
531
     */
532
    public static function getColInfo($col) {
533
        return static::parseColRecursion($col);
534
    }
535
536 4
    /**
537
     * Information extractor for col relations path
538
     *
539
     * @param string $info
540
     * @return array
541
     */
542
    public static function parseColRecursion($info) {
543
        if (is_string($info)) {
544
            $info = ['col' => $info, 'rawCol' => $info, 'modelName' => '', 'label' => '', 'joins' => []];
545
        }
546
        if (strpos($info['col'], ':') !== false) {
547
            $relations = static::relations();
548
            if (isset($relations[substr($info['col'], 0, strpos($info['col'], ':'))])) {
549
                $rel = substr($info['col'], 0, strpos($info['col'], ':'));
550
                $info['col'] = substr($info['col'], strpos($info['col'], ':') + 1);
551
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
552
                switch ($type) {
553 View Code Duplication
                    case 'to':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
554
                        $relCol = $relations[$rel]['col'];
555
                        static::fixPrefix($relCol);
556
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
557
                        break;
558 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...
559
                        $relCol = $relations[$rel]['col'];
560
                        $relations[$rel]['model']::fixPrefix($relCol);
561
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
562
                        break;
563
                }
564
                $info = $relations[$rel]['model']::parseColRecursion($info);
565
            }
566
        } else {
567
            $cols = static::cols();
568 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...
569
                $info['label'] = static::$labels[$info['col']];
570
            }
571
572
            if (isset(static::$cols[$info['col']])) {
573
                $info['colParams'] = static::$cols[$info['col']];
574
            } elseif (isset(static::$cols[str_replace(static::colPrefix(), '', $info['col'])])) {
575
                $info['colParams'] = static::$cols[str_replace(static::colPrefix(), '', $info['col'])];
576
            } else {
577
                $info['colParams'] = [];
578
            }
579 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...
580
                $info['col'] = static::colPrefix() . $info['col'];
581
            }
582
            $info['modelName'] = get_called_class();
583
        }
584 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...
585
            $info['label'] = static::$labels[$info['rawCol']];
586
        }
587
        return $info;
588
    }
589
590
    /**
591
     * Return actual cols from data base
592
     *
593
     * @param boolean $refresh
594
     * @return array
595
     */
596
    public static function cols($refresh = false) {
597
        if (static::$storage['type'] == 'moduleConfig') {
598
            return [];
599
        }
600 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...
601
            Model::$cols[static::table()] = App::$cur->db->getTableCols(static::table());
602
        }
603 View Code Duplication
        if (!Model::$cols[static::table()]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
604
            static::createTable();
605
            Model::$cols[static::table()] = App::$cur->db->getTableCols(static::table());
606
        }
607
        return Model::$cols[static::table()];
608 4
    }
609 4
610 1
    /**
611
     * Return cols indexes for create tables
612 4
     *
613 4
     * @return array
614 4
     */
615 4
    public static function indexes() {
616
        return [];
617
    }
618
619 4
    /**
620
     * Generate params string for col by name
621
     *
622
     * @param string $colName
623
     * @return false|string
624
     */
625
    public static function genColParams($colName) {
626
        if (empty(static::$cols[$colName]) || static::$storage['type'] == 'moduleConfig') {
627 3
            return false;
628 3
        }
629
        $null = ' NULL';
630
        if (empty(static::$cols[$colName]['null'])) {
631
            $null = ' NOT NULL';
632
        }
633
634
        $params = false;
635
        switch (static::$cols[$colName]['type']) {
636
            case 'select':
637 4
                switch (static::$cols[$colName]['source']) {
638 4
                    case 'relation':
639 1
                        $params = 'int(11) UNSIGNED' . $null;
640
                        break;
641 4
                    default:
642 4
                        $params = 'varchar(255)' . $null;
643 4
                }
644 4
                break;
645
            case 'image':
646 4
            case 'file':
647 4
                $params = 'int(11) UNSIGNED' . $null;
648 4
                break;
649 4
            case 'number':
650 4
                $params = 'int(11)' . $null;
651 4
                break;
652 4
            case 'text':
653 1
            case 'email':
654 1
                $params = 'varchar(255)' . $null;
655 4
                break;
656 4
            case 'html':
657 4
            case 'textarea':
658 4
            case 'json':
659 1
            case 'password':
660 1
            case 'dynamicType':
661 4
            case 'map':
662
                $params = 'text' . $null;
663
                break;
664 4
            case 'bool':
665 4
                $params = 'tinyint(1) UNSIGNED' . $null;
666 3
                break;
667 3
            case 'decimal':
668 3
                $params = 'decimal(8, 2)' . $null;
669 3
                break;
670 3
            case 'time':
671 3
                $params = 'time' . $null;
672 3
                break;
673 3
            case 'date':
674 1
                $params = 'date' . $null;
675 1
                break;
676 3
            case 'dateTime':
677 1
                $params = 'timestamp' . $null;
678 1
                break;
679 3
        }
680
        return $params;
681
    }
682 3
683 1
    /**
684 1
     * Create new col in data base
685 3
     *
686 2
     * @param string $colName
687 2
     * @return boolean|integer
688 4
     */
689 4
    public static function createCol($colName) {
690
        $cols = static::cols(true);
691
        if (!empty($cols[static::colPrefix() . $colName])) {
692
            return true;
693
        }
694
        $params = static::genColParams($colName);
695
        if ($params === false) {
696
            return false;
697
        }
698 2
        return App::$cur->db->addCol(static::table(), static::colPrefix() . $colName, $params);
699 2
    }
700 2
701
    public static function createTable() {
702
        if (static::$storage['type'] == 'moduleConfig') {
703 2
            return true;
704 2
        }
705 2
        if (!App::$cur->db) {
706
            return false;
707
        }
708
709
        $query = App::$cur->db->newQuery();
710 4
        if (!$query) {
711 4
            return false;
712
        }
713
714 4
        if (!isset($this)) {
715
            $tableName = static::table();
716
            $colPrefix = static::colPrefix();
717
            $indexes = static::indexes();
718 4
        } else {
719 4
            $tableName = $this->table();
720
            $colPrefix = $this->colPrefix();
721
            $indexes = $this->indexes();
722
        }
723 4
        if (App::$cur->db->tableExist($tableName)) {
724 4
            return true;
725 4
        }
726 4
        $cols = [
727 4
            $colPrefix . 'id' => 'pk'
728
        ];
729
        $className = get_called_class();
730
        if (!empty($className::$cols)) {
731
            foreach ($className::$cols as $colName => $colParams) {
732 4
                if ($colName == 'date_create') {
733
                    $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
734
                    continue;
735
                }
736 4
                $params = $className::genColParams($colName);
737 4
                if ($params) {
738 4
                    $cols[$colPrefix . $colName] = $params;
739 4
                }
740 4
            }
741 4
        }
742 4
        if (empty($cols[$colPrefix . 'date_create'])) {
743 4
            $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
744
        }
745 4
        $tableIndexes = [];
746 4
        if ($indexes) {
747 4
            foreach ($indexes as $indexName => $index) {
748 4
                $tableIndexes[] = $index['type'] . ' ' . App::$cur->db->table_prefix . $indexName . ' (' . implode(',', $index['cols']) . ')';
749 4
            }
750 4
        }
751 4
752 1
        $query->createTable($tableName, $cols, $tableIndexes);
753 1
        return true;
754 4
    }
755 4
756 1
    /**
757 1
     * Return table name
758 1
     *
759 1
     * @return string
760
     */
761 4
    public static function table() {
762 4
        return strtolower(str_replace('\\', '_', get_called_class()));
763
    }
764
765
    /**
766
     * Return table index col name
767
     *
768
     * @return string
769
     */
770 4
    public static function index() {
771 4
772
        return static::colPrefix() . 'id';
773
    }
774
775
    /**
776
     * Return col prefix
777
     *
778
     * @return string
779 4
     */
780
    public static function colPrefix() {
781 4
        $classPath = explode('\\', get_called_class());
782
        $classPath = array_slice($classPath, 1);
783
        return strtolower(implode('_', $classPath)) . '_';
784
    }
785
786
    /**
787
     * return relations list
788
     *
789 4
     * @return string
790 4
     */
791 4
    public static function relations() {
792 4
        return [];
793
    }
794
795
    /**
796
     * views list
797
     *
798
     * @return array
799
     */
800 1
    public static $views = [];
801 1
802
    /**
803
     * Return name of col with object name
804
     *
805
     * @return string
806
     */
807
    public static function nameCol() {
808
        return 'name';
809
    }
810
811
    /**
812
     * Return object name
813
     *
814
     * @return string
815
     */
816
    public function name() {
817
        return $this->{$this->nameCol()} ? $this->{$this->nameCol()} : '№' . $this->pk();
818
    }
819
820
    /**
821
     * Get single object from data base
822
     *
823
     * @param mixed $param
824
     * @param string $col
825
     * @param array $options
826
     * @return boolean|static
827
     */
828
    public static function get($param, $col = null, $options = []) {
829
        if (static::$storage['type'] == 'moduleConfig') {
830
            return static::getFromModuleStorage($param, $col, $options);
831
        }
832
        if (!empty($col)) {
833
            static::fixPrefix($col);
834
        }
835
836
        if (is_array($param)) {
837 4
            static::fixPrefix($param, 'first');
838 4
        }
839
        foreach (static::$relJoins as $join) {
840
            App::$cur->db->join($join[0], $join[1]);
841 4
        }
842 4
        static::$relJoins = [];
843 4
        foreach (static::$needJoin as $rel) {
844
            $relations = static::relations();
845 4
            if (isset($relations[$rel])) {
846 1
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
847 1
                switch ($type) {
848 4
                    case 'to':
849
                        $relCol = $relations[$rel]['col'];
850 4
                        static::fixPrefix($relCol);
851 4
                        App::$cur->db->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
852 4
                        break;
853
                    case 'one':
854
                        $col = $relations[$rel]['col'];
855
                        $relations[$rel]['model']::fixPrefix($col);
856
                        App::$cur->db->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
857
                        break;
858
                }
859
            }
860
        }
861
        static::$needJoin = [];
862
        if (is_array($param)) {
863
            App::$cur->db->where($param);
864
        } else {
865
            if ($col === null) {
866
867
                $col = static::index();
868
            }
869 4
            if ($param !== null) {
870 4
                $cols = static::cols();
871 4
                if (!isset($cols[$col]) && isset($cols[static::colPrefix() . $col])) {
872 1
                    $col = static::colPrefix() . $col;
873 1
                }
874 4
                App::$cur->db->where($col, $param);
875
            } else {
876 3
                return false;
877 3
            }
878 4
        }
879 4
        if (!App::$cur->db->where) {
880 4
            return false;
881
        }
882
        try {
883 4
            $result = App::$cur->db->select(static::table());
884 4
        } catch (PDOException $exc) {
885
            if ($exc->getCode() == '42S02') {
886
                static::createTable();
887
            } else {
888 4
                throw $exc;
889
            }
890
            $result = App::$cur->db->select(static::table());
891
        }
892 4
        if (!$result) {
893 4
            return false;
894
        }
895
        return $result->fetch(get_called_class());
896
    }
897
898
    /**
899
     * Old method
900
     *
901 4
     * @param type $options
902
     * @return Array
903
     */
904 4
    public static function get_list($options = [], $debug = false) {
905
        $query = App::$cur->db->newQuery();
906
        if (!$query) {
907
            return [];
908
        }
909
        if (!empty($options['where'])) {
910
            $query->where($options['where']);
911
        }
912
        if (!empty($options['cols'])) {
913
            $query->cols = $options['cols'];
914
        }
915
        if (!empty($options['group'])) {
916
            $query->group($options['group']);
917
        }
918
        if (!empty($options['having'])) {
919
            $query->having($options['having']);
920
        }
921
        if (!empty($options['order'])) {
922
            $query->order($options['order']);
923
        }
924
        if (!empty($options['join'])) {
925
            $query->join($options['join']);
926
        }
927
        if (!empty($options['distinct'])) {
928
            $query->distinct = $options['distinct'];
929
        }
930
931
        foreach (static::$relJoins as $join) {
932
            $query->join($join[0], $join[1]);
933
        }
934
        static::$relJoins = [];
935 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...
936
            $relations = static::relations();
937
            if (isset($relations[$rel])) {
938
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
939
                switch ($type) {
940
                    case 'to':
941
                        $relCol = $relations[$rel]['col'];
942
                        static::fixPrefix($relCol);
943
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
944
                        break;
945
                    case 'one':
946
                        $col = $relations[$rel]['col'];
947
                        $relations[$rel]['model']::fixPrefix($col);
948
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
949
                        break;
950
                }
951
            }
952
        }
953
        static::$needJoin = [];
954
955 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...
956
            $limit = (int) $options['limit'];
957
        } else {
958
            $limit = 0;
959
        }
960 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...
961
            $start = (int) $options['start'];
962
        } else {
963
            $start = 0;
964
        }
965
        if ($limit || $start) {
966
            $query->limit($start, $limit);
967
        }
968
        if (isset($options['key'])) {
969
            $key = $options['key'];
970
        } else {
971
            $key = static::index();
972
        }
973
974
        if ($debug) {
975
            $query->operation = 'SELECT';
976
            $query->table = static::table();
977
            return $query->buildQuery();
978
        }
979
        try {
980
            $query->operation = 'SELECT';
981
            $query->table = static::table();
982
            $queryArr = $query->buildQuery();
983
            $result = $query->query($queryArr);
984
        } catch (PDOException $exc) {
985
            if ($exc->getCode() == '42S02') {
986
                static::createTable();
987
                $result = $query->query($queryArr);
988
            } else {
989
                throw $exc;
990
            }
991
        }
992
993
        if (!empty($options['array'])) {
994
            return $result->getArray($key);
995
        }
996
        $list = $result->getObjects(get_called_class(), $key);
997 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...
998
            $return = [];
999
            foreach ($list as $key => $item) {
1000
                $return[$key] = $item->name();
1001
            }
1002
            return $return;
1003
        }
1004
        return $list;
1005
    }
1006
1007
    /**
1008
     * Return list of objects from data base
1009
     *
1010
     * @param array $options
1011
     * @return static[]
1012
     */
1013
    public static function getList($options = [], $debug = false) {
1014
        if (static::$storage['type'] != 'db') {
1015
            return static::getListFromModuleStorage($options);
1016
        }
1017
        if (!empty($options['where'])) {
1018
            static::fixPrefix($options['where'], 'first');
1019
        }
1020
        if (!empty($options['group'])) {
1021
            static::fixPrefix($options['group'], 'first');
1022
        }
1023
        if (!empty($options['order'])) {
1024
            static::fixPrefix($options['order'], 'first');
1025
        }
1026
        if (!empty($options['having'])) {
1027
            static::fixPrefix($options['having'], 'first');
1028
        }
1029
        return static::get_list($options, $debug);
1030
    }
1031
1032
    /**
1033
     * Get single item from module storage
1034
     *
1035
     * @param array $param
1036
     * @param string $col
1037
     * @param array $options
1038
     * @return boolean|\Model
1039
     */
1040
    public static function getFromModuleStorage($param = null, $col = null, $options = []) {
1041
        if ($col === null) {
1042
1043
            $col = static::index();
1044
        }
1045
        if ($param == null) {
1046
            return false;
1047
        }
1048
        $classPath = explode('\\', get_called_class());
1049 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...
1050
            $moduleConfig = Config::share($classPath[0]);
1051
        } else {
1052
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1053
        }
1054
        $appType = App::$cur->type;
1055 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...
1056
            if (!empty($options['appType'])) {
1057
                $appType = $options['appType'];
1058
            }
1059
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1060
        } else {
1061
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1062
        }
1063
        if (!empty($storage[$classPath[1]])) {
1064
            $items = $storage[$classPath[1]];
1065
            $class = get_called_class();
1066
            $where = is_array($param) ? $param : [$col, $param];
1067
            foreach ($items as $key => $item) {
1068
                if (!Model::checkWhere($item, $where)) {
1069
                    continue;
1070
                }
1071
                if (!empty($options['array'])) {
1072
                    return $item;
1073
                }
1074
                $item = new $class($item);
1075
                $item->appType = $appType;
1076
                return $item;
1077
            }
1078
        }
1079
        return false;
1080
    }
1081
1082
    /**
1083
     * Return list items from module storage
1084
     *
1085
     * @param array $options
1086
     * @return array
1087
     */
1088
    public static function getListFromModuleStorage($options = []) {
1089
        $classPath = explode('\\', get_called_class());
1090 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...
1091
            $moduleConfig = Config::share($classPath[0]);
1092
        } else {
1093
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1094
        }
1095 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...
1096
            if (empty($options['appType'])) {
1097
                $appType = App::$cur->type;
1098
            } else {
1099
                $appType = $options['appType'];
1100
            }
1101
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1102
        } else {
1103
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1104
        }
1105
        if (!empty($storage[$classPath[1]])) {
1106
            $items = [];
1107
            $class = get_called_class();
1108
            if (isset($options['key'])) {
1109
                $arrayKey = $options['key'];
1110
            } else {
1111
                $arrayKey = static::index();
1112
            }
1113
            foreach ($storage[$classPath[1]] as $key => $item) {
1114
                if (!empty($options['where']) && !Model::checkWhere($item, $options['where'])) {
1115
                    continue;
1116
                }
1117
                $items[$item[$arrayKey]] = new $class($item);
1118
            }
1119
            if (!empty($options['order'])) {
1120
                usort($items, function ($a, $b) use ($options) {
1121
                    if ($a->{$options['order'][0]} > $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1122
                        return 1;
1123
                    } elseif ($a->{$options['order'][0]} < $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1124
                        return -1;
1125
                    } elseif ($a->{$options['order'][0]} == $b->{$options['order'][0]} && $a->id > $b->id) {
1126
                        return 1;
1127
                    } elseif ($a->{$options['order'][0]} == $b->{$options['order'][0]} && $a->id < $b->id) {
1128
                        return -1;
1129
                    }
1130
                    return 0;
1131
                });
1132
            }
1133 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...
1134
                $return = [];
1135
                foreach ($items as $key => $item) {
1136
                    $return[$key] = $item->name();
1137
                }
1138
                return $return;
1139
            }
1140
            return $items;
1141
        }
1142
        return [];
1143
    }
1144
1145
    /**
1146
     * Return count of records from module storage
1147
     *
1148
     * @param array $options
1149
     * @return int
1150
     */
1151
    public static function getCountFromModuleStorage($options = []) {
1152
1153
        $classPath = explode('\\', get_called_class());
1154
        $count = 0;
1155
        if (empty($options['appType'])) {
1156
            $appType = App::$cur->type;
1157
        } else {
1158
            $appType = $options['appType'];
1159
        }
1160 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...
1161
            $moduleConfig = Config::share($classPath[0]);
1162
        } else {
1163
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1164
        }
1165
        if (!empty($moduleConfig['storage'][$appType][$classPath[1]])) {
1166
            $items = $moduleConfig['storage'][$appType][$classPath[1]];
1167
            if (empty($options['where'])) {
1168
                return count($items);
1169
            }
1170
            foreach ($items as $key => $item) {
1171
                if (!empty($options['where'])) {
1172
                    if (Model::checkWhere($item, $options['where'])) {
1173
                        $count++;
1174
                    }
1175
                } else {
1176
                    $count++;
1177
                }
1178
            }
1179
        }
1180
        return $count;
1181
    }
1182
1183
    /**
1184
     * Check where for module storage query
1185
     *
1186
     * @param array $item
1187
     * @param array|string $where
1188
     * @param string $value
1189
     * @param string $operation
1190
     * @param string $concatenation
1191
     * @return boolean
1192
     */
1193
    public static function checkWhere($item = [], $where = '', $value = '', $operation = '=', $concatenation = 'AND') {
1194
1195
        if (is_array($where)) {
1196
            if (is_array($where[0])) {
1197
                $result = true;
1198
                foreach ($where as $key => $whereItem) {
1199
                    $concatenation = empty($whereItem[3]) ? 'AND' : strtoupper($whereItem[3]);
1200
                    switch ($concatenation) {
1201 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...
1202
                            $result = $result && forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1203
                            break;
1204 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...
1205
                            $result = $result || forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1206
                            break;
1207
                    }
1208
                }
1209
1210
                return $result;
1211
            } else {
1212
                return forward_static_call_array(['Model', 'checkWhere'], array_merge([$item], $where));
1213
            }
1214
        }
1215
        if (!isset($item[$where]) && !$value) {
1216
            return true;
1217
        }
1218
        if (!isset($item[$where]) && $value) {
1219
            return false;
1220
        }
1221
        if ($item[$where] == $value) {
1222
            return true;
1223
        }
1224
        return false;
1225
    }
1226
1227
    /**
1228
     * Return count of records from data base
1229
     *
1230
     * @param array $options
1231
     * @return array|int
1232
     */
1233
    public static function getCount($options = []) {
1234
        if (static::$storage['type'] == 'moduleConfig') {
1235
            return static::getCountFromModuleStorage($options);
1236
        }
1237
        $query = App::$cur->db->newQuery();
1238
        if (!$query) {
1239
            return 0;
1240
        }
1241
        if (!empty($options['where'])) {
1242
            static::fixPrefix($options['where'], 'first');
1243
        }
1244
        if (!empty($options['group'])) {
1245
            static::fixPrefix($options['group'], 'first');
1246
        }
1247
        if (!empty($options['order'])) {
1248
            static::fixPrefix($options['order'], 'first');
1249
        }
1250
        if (!empty($options['where'])) {
1251
            $query->where($options['where']);
1252
        }
1253
        if (!empty($options['join'])) {
1254
            $query->join($options['join']);
1255
        }
1256
        if (!empty($options['order'])) {
1257
            $query->order($options['order']);
1258
        }
1259 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...
1260
            $limit = (int) $options['limit'];
1261
        } else {
1262
            $limit = 0;
1263
        }
1264 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...
1265
            $start = (int) $options['start'];
1266
        } else {
1267
            $start = 0;
1268
        }
1269
        if ($limit || $start) {
1270
            $query->limit($start, $limit);
1271
        }
1272
1273
        foreach (static::$relJoins as $join) {
1274
            $query->join($join[0], $join[1]);
1275
        }
1276
        static::$relJoins = [];
1277 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...
1278
            $relations = static::relations();
1279
            if (isset($relations[$rel])) {
1280
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
1281
                switch ($type) {
1282
                    case 'to':
1283
                        $relCol = $relations[$rel]['col'];
1284
                        static::fixPrefix($relCol);
1285
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
1286
                        break;
1287
                    case 'one':
1288
                        $col = $relations[$rel]['col'];
1289
                        $relations[$rel]['model']::fixPrefix($col);
1290
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
1291
                        break;
1292
                }
1293
            }
1294
        }
1295
        static::$needJoin = [];
1296
        $cols = 'COUNT(';
1297
1298
        if (!empty($options['distinct'])) {
1299
            if (is_bool($options['distinct'])) {
1300
                $cols .= 'DISTINCT *';
1301
            } else {
1302
                $cols .= "DISTINCT {$options['distinct']}";
1303
            }
1304
        } else {
1305
            $cols .= '*';
1306
        }
1307
        $cols .= ') as `count`' . (!empty($options['cols']) ? ',' . $options['cols'] : '');
1308
        $query->cols = $cols;
1309
        if (!empty($options['group'])) {
1310
            $query->group($options['group']);
1311
        }
1312
        try {
1313
            $result = $query->select(static::table());
1314
        } catch (PDOException $exc) {
1315
            if ($exc->getCode() == '42S02') {
1316
                static::createTable();
1317
            } else {
1318
                throw $exc;
1319
            }
1320
            $result = $query->select(static::table());
1321
        }
1322
        if (!empty($options['group'])) {
1323
            $count = $result->getArray();
1324
            return $count;
1325
        } else {
1326
            $count = $result->fetch();
1327
            return $count['count'];
1328
        }
1329
    }
1330
1331
    /**
1332
     * Update records in data base
1333
     *
1334
     * @param array $params
1335
     * @param array $where
1336
     * @return false|null
1337
     */
1338
    public static function update($params, $where = []) {
1339
        static::fixPrefix($params);
1340
1341
        $cols = self::cols();
1342
1343
        $values = [];
1344
        foreach ($cols as $col => $param) {
1345
            if (isset($params[$col])) {
1346
                $values[$col] = $params[$col];
1347
            }
1348
        }
1349
        if (empty($values)) {
1350
            return false;
1351
        }
1352
1353
        if (!empty($where)) {
1354
            static::fixPrefix($where, 'first');
1355
1356
            App::$cur->db->where($where);
1357
        }
1358
        App::$cur->db->update(static::table(), $values);
1359
    }
1360
1361
    /**
1362
     * Return primary key of object
1363
     *
1364
     * @return mixed
1365 4
     */
1366 4
    public function pk() {
1367
        return $this->{$this->index()};
1368
    }
1369
1370
    /**
1371
     * Before save trigger
1372 4
     */
1373
    public function beforeSave() {
1374 4
1375
    }
1376
1377
    /**
1378
     * Save object to module storage
1379
     *
1380
     * @param array $options
1381
     * @return boolean
1382 1
     */
1383
    public function saveModuleStorage($options) {
1384 1
1385 1
        $col = static::index();
1386 1
        $id = $this->pk();
1387 1
        $appType = '';
1388
        $classPath = explode('\\', get_called_class());
1389 1
1390 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...
1391
            $moduleConfig = Config::share($classPath[0]);
1392 1
        } else {
1393
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1394
        }
1395 1
1396 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...
1397
            if (empty($options['appType'])) {
1398
                $appType = App::$cur->type;
1399 1
            } else {
1400
                $appType = $options['appType'];
1401 1
            }
1402 1
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1403
        } else {
1404
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1405 1
        }
1406
        if (empty($storage[$classPath[1]])) {
1407
            $storage[$classPath[1]] = [];
1408 1
        }
1409
        if ($id) {
1410 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...
1411
                if ($item[$col] == $id) {
1412
                    $storage[$classPath[1]][$key] = $this->_params;
1413
                    break;
1414
                }
1415
            }
1416 1
        } else {
1417 1
            $id = !empty($storage['scheme'][$classPath[1]]['ai']) ? $storage['scheme'][$classPath[1]]['ai'] : 1;
1418 1
            $this->$col = $id;
1419 1
            $storage['scheme'][$classPath[1]]['ai'] = $id + 1;
1420
            $storage[$classPath[1]][] = $this->_params;
1421 1
        }
1422 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...
1423 1
            $moduleConfig['storage'][$appType] = $storage;
1424
        } else {
1425
            $moduleConfig['storage'] = $storage;
1426 1
        }
1427 1 View Code Duplication
        if (empty(static::$storage['options']['share'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1428 1
            Config::save('module', $moduleConfig, $classPath[0]);
1429
        } else {
1430
            Config::save('share', $moduleConfig, $classPath[0]);
1431 1
        }
1432
        return true;
1433
    }
1434
1435
    /**
1436
     * Update tree path category
1437
     */
1438
    public function changeCategoryTree() {
1439
        $class = get_class($this);
1440
        $itemModel = $class::$treeCategory;
1441
        $oldPath = $this->tree_path;
1442
        $this->tree_path = $this->getCatalogTree($this);
1443
        $itemsTable = \App::$cur->db->table_prefix . $itemModel::table();
1444
        $itemTreeCol = $itemModel::colPrefix() . 'tree_path';
1445
1446
        $categoryTreeCol = $this->colPrefix() . 'tree_path';
1447
        $categoryTable = \App::$cur->db->table_prefix . $this->table();
1448
        if ($oldPath) {
1449
            \App::$cur->db->query('UPDATE
1450
                ' . $categoryTable . ' 
1451
                    SET 
1452
                        ' . $categoryTreeCol . ' = REPLACE(' . $categoryTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1453
                    WHERE ' . $categoryTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1454
1455
            \App::$cur->db->query('UPDATE
1456
                ' . $itemsTable . '
1457
                    SET 
1458
                        ' . $itemTreeCol . ' = REPLACE(' . $itemTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1459
                    WHERE ' . $itemTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1460
        }
1461
        $itemModel::update([$itemTreeCol => $this->tree_path . $this->id . '/'], [$itemModel::colPrefix() . $this->index(), $this->id]);
1462
    }
1463
1464
    /**
1465
     * Return tree path
1466
     *
1467
     * @param \Model $catalog
1468
     * @return string
1469
     */
1470
    public function getCatalogTree($catalog) {
1471
        $catalogClass = get_class($catalog);
1472
        $catalogParent = $catalogClass::get($catalog->parent_id);
1473
        if ($catalog && $catalogParent) {
1474
            if ($catalogParent->tree_path) {
1475
                return $catalogParent->tree_path . $catalogParent->id . '/';
1476
            } else {
1477
                return $this->getCatalogTree($catalogParent) . $catalogParent->id . '/';
1478
            }
1479
        }
1480
        return '/';
1481
    }
1482
1483
    /**
1484
     * Update tree path item
1485
     */
1486
    public function changeItemTree() {
1487
        $class = get_class($this);
1488
        $categoryModel = $class::$categoryModel;
1489
        $category = $categoryModel::get($this->{$categoryModel::index()});
1490
        if ($category) {
1491
            $this->tree_path = $category->tree_path . $category->pk() . '/';
1492
        } else {
1493
            $this->tree_path = '/';
1494
        }
1495
    }
1496
1497
    /**
1498
     * Save object to data base
1499
     *
1500
     * @param array $options
1501
     * @return boolean|int
1502 4
     */
1503
    public function save($options = []) {
1504 4
1505 1
        if (static::$storage['type'] == 'moduleConfig') {
1506
            return static::saveModuleStorage($options);
1507 4
        }
1508 4
        $class = get_class($this);
1509
        if ($class::$categoryModel) {
1510
            $this->changeItemTree();
1511 4
        }
1512
        if ($class::$treeCategory) {
1513
            $this->changeCategoryTree();
1514 4
        }
1515 3
        if (!empty($this->_changedParams) && $this->pk()) {
1516 3
            Inji::$inst->event('modelItemParamsChanged-' . get_called_class(), $this);
1517 4
        }
1518 4
        $this->beforeSave();
1519
        $values = [];
1520 4
1521 4
        foreach ($this->cols() as $col => $param) {
1522 4
            if (in_array($col, array_keys($this->_params)) && (!$this->pk() || ($this->pk() && in_array($col, array_keys($this->_changedParams))))) {
1523 4
                $values[$col] = $this->_params[$col];
1524 4
            }
1525 4
        }
1526 4
        if (!$this->pk()) {
1527 4
            foreach ($class::$cols as $colName => $params) {
1528
                $class::fixPrefix($colName);
1529
                if (isset($params['default']) && !isset($values[$colName])) {
1530 4
                    $this->_params[$colName] = $values[$colName] = $params['default'];
1531
                }
1532 4
            }
1533
        }
1534
1535
        if (empty($values) && empty($options['empty'])) {
1536 4
            return false;
1537 3
        }
1538 3
1539 3
        if ($this->pk()) {
1540 3
            $new = false;
1541 3
            if ($this->get($this->_params[$this->index()])) {
1542
                App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1543
                App::$cur->db->update($this->table(), $values);
1544
            } else {
1545 3
1546 4
                $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1547 4
            }
1548
        } else {
1549 4
            $new = true;
1550 4
            //print_r($this->_params);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
1551
            $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1552 4
        }
1553 4
        $this->logChanges($new);
1554
        App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1555
        try {
1556
            $result = App::$cur->db->select($this->table());
1557
        } catch (PDOException $exc) {
1558
            if ($exc->getCode() == '42S02') {
1559 4
                $this->createTable();
1560 4
            }
1561 4
            $result = App::$cur->db->select($this->table());
1562 4
        }
1563 4
        $this->_params = $result->fetch();
1564 4
        if ($new) {
1565
            Inji::$inst->event('modelCreatedItem-' . get_called_class(), $this);
1566
        }
1567
        $this->afterSave();
1568
        return $this->{$this->index()};
1569
    }
1570 4
1571
    /**
1572 4
     * After save trigger
1573
     */
1574
    public function afterSave() {
1575
1576
    }
1577 1
1578
    /**
1579 1
     * Before delete trigger
1580
     */
1581
    public function beforeDelete() {
1582
1583
    }
1584
1585
    /**
1586
     * Delete item from module storage
1587
     *
1588
     * @param array $options
1589
     * @return boolean
1590
     */
1591
    public function deleteFromModuleStorage($options) {
1592
1593
        $col = static::index();
1594
        $id = $this->pk();
1595
        $appType = '';
1596
        $classPath = explode('\\', get_called_class());
1597 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...
1598
            $moduleConfig = Config::share($classPath[0]);
1599
        } else {
1600
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1601
        }
1602
1603 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...
1604
            if (empty($options['appType'])) {
1605
                $appType = App::$cur->type;
1606
            } else {
1607
                $appType = $options['appType'];
1608
            }
1609
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1610
        } else {
1611
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1612
        }
1613
        if (empty($storage[$classPath[1]])) {
1614
            $storage[$classPath[1]] = [];
1615
        }
1616 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...
1617
1618
            if ($item[$col] == $id) {
1619
                unset($storage[$classPath[1]][$key]);
1620
                break;
1621
            }
1622
        }
1623 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...
1624
            $moduleConfig['storage'][$appType] = $storage;
1625
        } else {
1626
            $moduleConfig['storage'] = $storage;
1627
        }
1628 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...
1629
            Config::save('module', $moduleConfig, $classPath[0]);
1630
        } else {
1631
            Config::save('share', $moduleConfig, $classPath[0]);
1632
        }
1633
        return true;
1634
    }
1635
1636
    /**
1637
     * Delete item from data base
1638 1
     *
1639 1
     * @param array $options
1640
     * @return boolean
1641 1
     */
1642
    public function delete($options = []) {
1643
        $this->beforeDelete();
1644 1
1645 1
        if (static::$storage['type'] == 'moduleConfig') {
1646 1
            return static::deleteFromModuleStorage($options);
1647 1
        }
1648 1
        if (!empty($this->_params[$this->index()])) {
1649 1
            App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1650
            $result = App::$cur->db->delete($this->table());
1651
            if ($result) {
1652
                $this->afterDelete();
1653
                return $result;
1654
            }
1655
        }
1656
        return false;
1657
    }
1658
1659
    /**
1660 4
     * Delete items from data base
1661 4
     *
1662
     * @param array $where
1663
     */
1664
    public static function deleteList($where = []) {
1665 4
        if (!empty($where)) {
1666 4
            static::fixPrefix($where, 'first');
1667
            App::$cur->db->where($where);
1668
        }
1669
        App::$cur->db->delete(static::table());
1670
    }
1671 1
1672
    /**
1673 1
     * After delete trigger
1674
     */
1675
    public function afterDelete() {
1676
1677
    }
1678
1679
    /**
1680
     * find relation for col name
1681
     *
1682
     * @param string $col
1683
     * @return array|null
1684
     */
1685
    public static function findRelation($col) {
1686
1687
        foreach (static::relations() as $relName => $rel) {
1688
            if ($rel['col'] == $col) {
1689
                return $relName;
1690
            }
1691
        }
1692
        return null;
1693
    }
1694
1695
    /**
1696 4
     * Set params for model
1697 4
     *
1698 2
     * @param array $params
1699 4
     */
1700 4
    public function setParams($params) {
1701
        foreach ($params as $paramName => $value) {
1702
            $this->$paramName = $value;
1703
        }
1704
    }
1705
1706
    /**
1707
     * Return relation
1708 4
     *
1709 4
     * @param string $relName
1710 4
     * @return array|boolean
1711
     */
1712
    public static function getRelation($relName) {
1713
        $relations = static::relations();
1714
        return !empty($relations[$relName]) ? $relations[$relName] : false;
1715
    }
1716
1717
    /**
1718
     * Load relation
1719
     *
1720 4
     * @param string $name
1721 4
     * @param array $params
1722 4
     * @return null|array|integer|\Model
1723 2
     */
1724 2
    public function loadRelation($name, $params = []) {
1725 2
        $relation = static::getRelation($name);
1726
        if ($relation) {
1727
            if (!isset($relation['type'])) {
1728 2
                $type = 'to';
1729 2
            } else {
1730
                $type = $relation['type'];
1731 2
            }
1732
            $getCol = null;
1733
            $getParams = [];
1734
            switch ($type) {
1735
                case 'relModel':
1736
                    if (!$this->pk()) {
1737
                        return [];
1738
                    }
1739
                    $fixedCol = $relation['model']::index();
1740
                    $relation['relModel']::fixPrefix($fixedCol);
1741
                    $join = [$relation['relModel']::table(), $relation['relModel']::colPrefix() . $this->index() . ' = ' . $this->pk() . ' and ' . $relation['relModel']::colPrefix() . $relation['model']::index() . ' = ' . $relation['model']::index(), 'INNER'];
1742
                    $getType = 'getList';
1743
                    $options = [
1744
                        'join' => [$join],
1745
                        'where' => (isset($params['where'])) ? $params['where'] : ((isset($relation['where'])) ? $relation['where'] : null),
1746
                        'array' => (!empty($params['array'])) ? true : false,
1747
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1748
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1749
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1750
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1751
                    ];
1752
                    break;
1753
                case 'many':
1754
                    if (!$this->{$this->index()}) {
1755 2
                        return [];
1756
                    }
1757
                    $getType = 'getList';
1758
                    $options = [
1759
                        'join' => (isset($relation['join'])) ? $relation['join'] : null,
1760
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1761
                        'array' => (!empty($params['array'])) ? true : false,
1762
                        'forSelect' => (!empty($params['forSelect'])) ? true : false,
1763
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1764
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1765
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1766
                        'appType' => (isset($params['appType'])) ? $params['appType'] : ((isset($relation['appType'])) ? $relation['appType'] : null),
1767
                        'where' => []
1768
                    ];
1769
                    $options['where'][] = [$relation['col'], $this->{$this->index()}];
1770
                    if (!empty($relation['where'])) {
1771
                        $options['where'] = array_merge($options['where'], [$relation['where']]);
1772
                    }
1773
                    if (!empty($params['where'])) {
1774
                        $options['where'] = array_merge($options['where'], [$params['where']]);
1775
                    }
1776
                    break;
1777
                case 'one':
1778
                    $getType = 'get';
1779 2
                    $options = [$relation['col'], $this->pk()];
1780
                    break;
1781
                default:
1782
                    if ($this->$relation['col'] === null) {
1783 2
                        return null;
1784 2
                    }
1785
                    $getType = 'get';
1786
                    $options = $this->$relation['col'];
1787 2
                    $getParams['appType'] = $this->appType;
1788 2
            }
1789 2
            if (!empty($params['count'])) {
1790 2
                if (class_exists($relation['model'])) {
1791 2
                    return $relation['model']::getCount($options);
1792
                }
1793
                return 0;
1794
            } else {
1795
                if (class_exists($relation['model'])) {
1796
                    $this->loadedRelations[$name][json_encode($params)] = $relation['model']::$getType($options, $getCol, $getParams);
1797 2
                } else {
1798 2
                    $this->loadedRelations[$name][json_encode($params)] = [];
1799 2
                }
1800
            }
1801
            return $this->loadedRelations[$name][json_encode($params)];
1802
        }
1803 2
        return null;
1804
    }
1805 4
1806
    /**
1807
     * Add relation item
1808
     *
1809
     * @param string $relName
1810
     * @param \Model $objectId
1811
     * @return \Model|boolean
1812
     */
1813
    public function addRelation($relName, $objectId) {
1814
        $relation = $this->getRelation($relName);
1815
        if ($relation) {
1816
            $rel = $relation['relModel']::get([[$relation['model']::index(), $objectId], [$this->index(), $this->pk()]]);
1817
            if (!$rel) {
1818
                $rel = new $relation['relModel']([
1819
                    $relation['model']::index() => $objectId,
1820
                    $this->index() => $this->pk()
1821
                ]);
1822
                $rel->save();
1823
            }
1824
            return $rel;
1825
        }
1826
        return false;
1827
    }
1828
1829
    /**
1830
     * Check user access for form
1831
     *
1832
     * @param string $formName
1833
     * @return boolean
1834
     */
1835
    public function checkFormAccess($formName) {
1836
        if ($formName == 'manage' && !Users\User::$cur->isAdmin()) {
1837
            return false;
1838
        }
1839
        return true;
1840
    }
1841
1842
    /**
1843
     * Check access for model
1844
     *
1845
     * @param string $mode
1846
     * @param \Users\User $user
1847
     * @return boolean
1848
     */
1849
    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...
1850
        if (!$user) {
1851
            $user = \Users\User::$cur;
1852
        }
1853
        return $user->isAdmin();
1854
    }
1855
1856
    /**
1857
     * Param and relation with params getter
1858
     *
1859
     * @param string $name
1860
     * @param array $params
1861
     * @return \Value|mixed
1862
     */
1863
    public function __call($name, $params) {
1864
        $fixedName = $name;
1865
        static::fixPrefix($fixedName);
1866 View Code Duplication
        if (isset($this->_params[$fixedName])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1867
            return new Value($this, $fixedName);
1868
        } elseif (isset($this->_params[$name])) {
1869
            return new Value($this, $name);
1870
        }
1871
        return call_user_func_array([$this, 'loadRelation'], array_merge([$name], $params));
1872
    }
1873
1874
    /**
1875
     * Param and relation getter
1876
     *
1877
     * @param string $name
1878
     * @return mixed
1879
     */
1880
    public function __get($name) {
1881
        $fixedName = $name;
1882 4
        static::fixPrefix($fixedName);
1883 4
        if (isset($this->_params[$fixedName])) {
1884 4
            return $this->_params[$fixedName];
1885 4
        }
1886 4
        if (isset($this->loadedRelations[$name][json_encode([])])) {
1887
            return $this->loadedRelations[$name][json_encode([])];
1888 4
        }
1889 2
        return $this->loadRelation($name);
1890
    }
1891 4
1892
    /**
1893
     * Return model value in object
1894
     *
1895
     * @param string $name
1896
     * @return \Value|null
1897
     */
1898
    public function value($name) {
1899
        $fixedName = $name;
1900
        static::fixPrefix($fixedName);
1901 View Code Duplication
        if (isset($this->_params[$fixedName])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1902
            return new Value($this, $fixedName);
1903
        } elseif ($this->_params[$name]) {
1904
            return new Value($this, $name);
1905
        }
1906
        return null;
1907
    }
1908
1909
    /**
1910
     * Return manager filters
1911
     *
1912
     * @return array
1913
     */
1914
    public static function managerFilters() {
1915
        return [];
1916
    }
1917
1918
    /**
1919
     * Return validators for cols
1920
     *
1921
     * @return array
1922
     */
1923
    public static function validators() {
1924
        return [];
1925
    }
1926
1927
    /**
1928
     * Return validator by name
1929
     *
1930
     * @param string $name
1931
     * @return array
1932
     */
1933
    public static function validator($name) {
1934
        $validators = static::validators();
1935
        if (!empty($validators[$name])) {
1936
            return $validators[$name];
1937
        }
1938
        return [];
1939
    }
1940
1941
    public function genViewLink() {
1942
        $className = get_class($this);
1943
        $link = substr($className, 0, strpos($className, '\\'));
1944
        $link .= '/view/';
1945
        $link .= str_replace('\\', '%5C', substr($className, strpos($className, '\\') + 1));
1946
        $link .= "/{$this->id}";
1947
        return $link;
1948
    }
1949
1950
    public function extract($model) {
1951
        $params = [];
1952
        if (empty($this->_params[$model::index()])) {
1953
            return false;
1954
        }
1955
        $params['id'] = $this->_params[$model::index()];
1956
        $indexes = array_keys($this->_params);
1957
        foreach ($model::$cols as $colName => $colParams) {
1958 4
            if (in_array($model::colPrefix() . $colName, $indexes)) {
1959 4
                $params[$model::colPrefix() . $colName] = $this->_params[$model::colPrefix() . $colName];
1960 4
            }
1961 4
        }
1962 4
        if (!$params) {
1963
            return FALSE;
1964
        }
1965 4
        return new $model($params);
1966 2
    }
1967 2
1968 4
    /**
1969 4
     * Set handler for model params
1970 4
     *
1971
     * @param string $name
1972
     * @param mixed $value
1973 4
     */
1974 2
    public function __set($name, $value) {
1975 2
        static::fixPrefix($name);
1976 4
        $className = get_called_class();
1977 1
        $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $name);
1978 1
        if (!$value && !empty(static::$cols[$shortName]) && in_array('emptyValue', array_keys(static::$cols[$shortName]))) {
1979 4
            $value = static::$cols[$shortName]['emptyValue'];
1980 4
        }
1981 4
        if (is_null($value) && empty(static::$cols[$shortName]['null'])) {
1982 4
            $value = '';
1983 3
        }
1984 3
        if (!empty($className::$cols[$shortName])) {
1985 4
            switch ($className::$cols[$shortName]['type']) {
1986 4
                case 'decimal':
1987
                    $value = (float) $value;
1988
                    break;
1989
                case 'number':
1990
                    $value = (int) $value;
1991
                    break;
1992
                case 'bool':
1993
                    $value = (bool) $value;
1994
                    break;
1995
            }
1996
        }
1997 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...
1998
            $this->_changedParams[$name] = $this->_params[$name];
1999
        }
2000
        $this->_params[$name] = $value;
2001 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...
2002
            unset($this->_changedParams[$name]);
2003
        }
2004
    }
2005
2006
    /**
2007
     * Isset handler for model params
2008
     *
2009
     * @param string $name
2010
     * @return boolean
2011
     */
2012
    public function __isset($name) {
2013
        static::fixPrefix($name);
2014
        return isset($this->_params[$name]);
2015
    }
2016
2017
    /**
2018
     * Convert object to string
2019
     *
2020
     * @return string
2021
     */
2022
    public function __toString() {
2023
        return $this->name();
2024
    }
2025
}