Passed
Push — master ( 7e87e7...214254 )
by Alexey
04:59
created

Model::deleteList()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.3149

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 7
cp 0.5714
crap 2.3149
rs 9.4285
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
     * @return string
169
     */
170
    public static function resloveTypeValue($item, $colName, $manageHref = false) {
171
        $modelName = get_class($item);
172
        $colInfo = $modelName::getColInfo($colName);
173
        $type = !empty($colInfo['colParams']['type']) ? $colInfo['colParams']['type'] : 'string';
174
        $value = '';
175
        switch ($type) {
176
            case 'select':
177
                switch ($colInfo['colParams']['source']) {
178
                    case 'model':
179
                        $sourceValue = '';
180
                        if ($item->$colName) {
181
                            $sourceValue = $colInfo['colParams']['model']::get($item->$colName);
182
                        }
183
                        $value = $sourceValue ? $sourceValue->name() : 'Не задано';
184
                        break;
185
                    case 'array':
186
                        $value = !empty($colInfo['colParams']['sourceArray'][$item->$colName]) ? $colInfo['colParams']['sourceArray'][$item->$colName] : 'Не задано';
187
                        if (is_array($value) && $value['text']) {
188
                            $value = $value['text'];
189
                        }
190
                        break;
191
                    case 'bool':
192
                        return $item->$colName ? 'Да' : 'Нет';
193
                    case 'method':
194
                        if (!empty($colInfo['colParams']['params'])) {
195
                            $values = call_user_func_array([App::$cur->$colInfo['colParams']['module'], $colInfo['colParams']['method']], $colInfo['colParams']['params']);
196
                        } else {
197
                            $values = $colInfo['colParams']['module']->$colInfo['colParams']['method']();
198
                        }
199
                        $value = !empty($values[$item->$colName]) ? $values[$item->$colName] : 'Не задано';
200
                        break;
201
                    case 'void':
202
                        if (!empty($modelName::$cols[$colName]['value']['type']) && $modelName::$cols[$colName]['value']['type'] == 'moduleMethod') {
203
                            return \App::$cur->{$modelName::$cols[$colName]['value']['module']}->{$modelName::$cols[$colName]['value']['method']}($item, $colName, $modelName::$cols[$colName]);
204
                        }
205
                        break;
206
                    case 'relation':
207
                        $relations = $colInfo['modelName']::relations();
208
                        $relValue = $relations[$colInfo['colParams']['relation']]['model']::get($item->$colName);
209
                        $relModel = $relations[$colInfo['colParams']['relation']]['model'];
210
                        $relModel = strpos($relModel, '\\') === 0 ? substr($relModel, 1) : $relModel;
211
                        if ($manageHref) {
212
                            $value = $relValue ? "<a href='/admin/" . str_replace('\\', '/view/', $relModel) . "/" . $relValue->pk() . "'>" . $relValue->name() . "</a>" : 'Не задано';
213
                        } else {
214
                            $value = $relValue ? $relValue->name() : 'Не задано';
215
                        }
216
                        break;
217
                }
218
                break;
219
            case 'image':
220
                $file = Files\File::get($item->$colName);
221
                if ($file) {
222
                    $photoId = Tools::randomString();
223
                    $value = '<a href = "' . $file->path . '" id="' . $photoId . '"><img src="' . $file->path . '?resize=60x120" /></a>';
224
                    $value .='<script>inji.onLoad(function(){$("#' . $photoId . '").fancybox();});</script>';
225
                } else {
226
                    $value = '<img src="/static/system/images/no-image.png?resize=60x120" />';
227
                }
228
                break;
229
            case 'file':
230
                $file = Files\File::get($item->$colName);
231
                if ($file) {
232
                    $value = '<a href="' . $file->path . '">' . $file->name . '.' . $file->type->ext . '</a>';
233
                } else {
234
                    $value = 'Файл не загружен';
235
                }
236
                break;
237
            case 'bool':
238
                $value = $item->$colName ? 'Да' : 'Нет';
239
                break;
240
            case 'void':
241
                if (!empty($colInfo['colParams']['value']['type']) && $colInfo['colParams']['value']['type'] == 'moduleMethod') {
242
                    return \App::$cur->{$colInfo['colParams']['value']['module']}->{$colInfo['colParams']['value']['method']}($item, $colName, $colInfo['colParams']);
243
                }
244
                break;
245 View Code Duplication
            case 'map':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
246
                if ($item->$colName && json_decode($item->$colName, true)) {
247
                    $addres = json_decode($item->$colName, true);
248
                    $name = $addres['address'] ? $addres['address'] : 'lat:' . $addres['lat'] . ': lng:' . $addres['lng'];
249
                    \App::$cur->libs->loadLib('yandexMap');
250
                    ob_start();
251
                    $uid = Tools::randomString();
252
                    ?>
253
                    <div id='map<?= $uid; ?>_container' style="display:none;"><script>/*
254
                     <div id='map<?= $uid; ?>' style="width: 100%; height: 500px"></div>
255
                     <script>
256
                     var myMap<?= $uid; ?>;
257
                     var myMap<?= $uid; ?>CurPin;
258
                     inji.onLoad(function () {
259
                     ymaps.ready(init<?= $uid; ?>);
260
                     function init<?= $uid; ?>() {
261
                     var myPlacemark;
262
                     myMap<?= $uid; ?> = new ymaps.Map("map<?= $uid; ?>", {
263
                     center: ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"],
264
                     zoom: 13
265
                     });
266
                     myCoords = ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"];
267
                     myMap<?= $uid; ?>CurPin = new ymaps.Placemark(myCoords,
268
                     {iconContent: "<?= $addres['address']; ?>"},
269
                     {preset: 'islands#greenStretchyIcon'}
270
                     );
271
                     myMap<?= $uid; ?>.geoObjects.add(myMap<?= $uid; ?>CurPin, 0);
272
                     }
273
                     window['init<?= $uid; ?>'] = init<?= $uid; ?>;
274
                     });
275
                     */</script>
276
                    </div>
277
                    <?php
278
                    $content = ob_get_contents();
279
                    ob_end_clean();
280
                    $onclick = 'inji.Ui.modals.show("' . addcslashes($addres['address'], '"') . '", $("#map' . $uid . '_container script").html().replace(/^\/\*/g, "").replace(/\*\/$/g, "")+"</script>","mapmodal' . $uid . '","modal-lg");';
281
                    $onclick .= 'return false;';
282
                    $value = "<a href ='#' onclick='{$onclick}' >{$name}</a>";
283
                    $value .= $content;
284
                } else {
285
                    $value = 'Местоположение не заданно';
286
                }
287
288
                break;
289
            case 'dynamicType':
290
                switch ($colInfo['colParams']['typeSource']) {
291
                    case 'selfMethod':
292
                        $type = $item->{$colInfo['colParams']['selfMethod']}();
293
                        if (is_array($type)) {
294 View Code Duplication
                            if (strpos($type['relation'], ':')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
295
                                $relationPath = explode(':', $type['relation']);
296
                                $relationName = array_pop($relationPath);
297
                                $curItem = $item;
298
                                foreach ($relationPath as $path) {
299
                                    $curItem = $curItem->$path;
300
                                }
301
                                $itemModel = get_class($curItem);
302
                                $relation = $itemModel::getRelation($relationName);
303
                                $sourceModel = $relation['model'];
304
                            } else {
305
                                $relation = static::getRelation($type['relation']);
306
                                $sourceModel = $relation['model'];
307
                            }
308
                            $value = $sourceModel::get($item->$colName);
309
                            if ($value) {
310
                                $value = $value->name();
311
                            } else {
312
                                $value = $item->$colName;
313
                            }
314
                        } else {
315
                            switch ($type) {
316 View Code Duplication
                                case 'map':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
317
                                    if ($item->$colName && json_decode($item->$colName, true)) {
318
                                        $addres = json_decode($item->$colName, true);
319
                                        $name = $addres['address'] ? $addres['address'] : 'lat:' . $addres['lat'] . ': lng:' . $addres['lng'];
320
                                        \App::$cur->libs->loadLib('yandexMap');
321
                                        ob_start();
322
                                        $uid = Tools::randomString();
323
                                        ?>
324
                                        <div id='map<?= $uid; ?>_container' style="display:none;"><script>/*
325
                                                                                 <div id='map<?= $uid; ?>' style="width: 100%; height: 500px"></div>
326
                                                                                 <script>
327
                                                                                 var myMap<?= $uid; ?>;
328
                                                                                 var myMap<?= $uid; ?>CurPin;
329
                                                                                 inji.onLoad(function () {
330
                                                                                 ymaps.ready(init<?= $uid; ?>);
331
                                                                                 function init<?= $uid; ?>() {
332
                                                                                 var myPlacemark;
333
                                                                                 myMap<?= $uid; ?> = new ymaps.Map("map<?= $uid; ?>", {
334
                                                                                 center: ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"],
335
                                                                                 zoom: 13
336
                                                                                 });
337
                                                                                 myCoords = ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"];
338
                                                                                 myMap<?= $uid; ?>CurPin = new ymaps.Placemark(myCoords,
339
                                                                                 {iconContent: "<?= $addres['address']; ?>"},
340
                                                                                 {preset: 'islands#greenStretchyIcon'}
341
                                                                                 );
342
                                                                                 myMap<?= $uid; ?>.geoObjects.add(myMap<?= $uid; ?>CurPin, 0);
343
                                                                                 }
344
                                                                                 window['init<?= $uid; ?>'] = init<?= $uid; ?>;
345
                                                                                 });
346
                                                                                 */</script>
347
                                        </div>
348
                                        <?php
349
                                        $content = ob_get_contents();
350
                                        ob_end_clean();
351
                                        $onclick = 'inji.Ui.modals.show("' . addcslashes($addres['address'], '"') . '", $("#map' . $uid . '_container script").html().replace(/^\/\*/g, "").replace(/\*\/$/g, "")+"</script>","mapmodal' . $uid . '","modal-lg");';
352
                                        $onclick .= 'return false;';
353
                                        $value = "<a href ='#' onclick='{$onclick}' >{$name}</a>";
354
                                        $value .= $content;
355
                                    } else {
356
                                        $value = 'Местоположение не заданно';
357
                                    }
358
359
                                    break;
360
                                default:
361
                                    $value = $item->$colName;
362
                            }
363
                        }
364
                        break;
365
                }
366
                break;
367
            default:
368
                $value = $item->$colName;
369
                break;
370
        }
371
        return $value;
372
    }
373
374
    /**
375
     * Fix col prefix
376
     * 
377
     * @param mixed $array
378
     * @param string $searchtype
379
     * @param string $rootModel
380
     * @return null
381
     */
382 4
    public static function fixPrefix(&$array, $searchtype = 'key', $rootModel = '') {
383 4
        if (!$rootModel) {
384 4
            $rootModel = get_called_class();
385 4
        }
386 4
        $cols = static::cols();
387 4
        if (!$array) {
388 4
            return;
389
        }
390 4
        if (!is_array($array)) {
391 4 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...
392 2
                static::createCol($array);
393 2
                $cols = static::cols(true);
394 2
            }
395 4
            if (!isset($cols[$array]) && isset($cols[static::colPrefix() . $array])) {
396 4
                $array = static::colPrefix() . $array;
397 4
            } else {
398 4
                static::checkForJoin($array, $rootModel);
399
            }
400 4
            return;
401
        }
402
        switch ($searchtype) {
403 2
            case 'key':
404 2
                foreach ($array as $key => $item) {
405 2 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...
406
                        static::createCol($key);
407
                        $cols = static::cols(true);
408
                    }
409 2
                    if (!isset($cols[$key]) && isset($cols[static::colPrefix() . $key])) {
410 2
                        $array[static::colPrefix() . $key] = $item;
411 2
                        unset($array[$key]);
412 2
                        $key = static::colPrefix() . $key;
413 2
                    }
414 2
                    if (is_array($array[$key])) {
415
                        static::fixPrefix($array[$key], 'key', $rootModel);
416
                    } else {
417 2
                        static::checkForJoin($key, $rootModel);
418
                    }
419 2
                }
420 2
                break;
421 1
            case 'first':
422 1
                if (isset($array[0]) && is_string($array[0])) {
423 1
                    if (!isset($cols[static::colPrefix() . $array[0]]) && isset(static::$cols[$array[0]])) {
424
                        static::createCol($array[0]);
425
                        $cols = static::cols(true);
426
                    }
427 1 View Code Duplication
                    if (!isset($cols[$array[0]]) && isset($cols[static::colPrefix() . $array[0]])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
428 1
                        $array[0] = static::colPrefix() . $array[0];
429 1
                    } else {
430
                        static::checkForJoin($array[0], $rootModel);
431
                    }
432 1
                } elseif (isset($array[0]) && is_array($array[0])) {
433 1
                    foreach ($array as &$item) {
434 1
                        static::fixPrefix($item, 'first', $rootModel);
435 1
                    }
436 1
                }
437 1
                break;
438
        }
439 2
    }
440
441
    /**
442
     * @param boolean $new
443
     */
444 4
    public function logChanges($new) {
445 4
        if (!App::$cur->db->connect || !App::$cur->dashboard) {
446
            return false;
447
        }
448 4
        $class = get_class($this);
449 4
        if (!$class::$logging) {
450 4
            return false;
451
        }
452 2
        $user_id = class_exists('Users\User') ? \Users\User::$cur->id : 0;
453 2
        if (!$new && !empty($this->_changedParams)) {
454
            $activity = new Dashboard\Activity([
455
                'user_id' => $user_id,
456
                'module' => substr($class, 0, strpos($class, '\\')),
457
                'model' => $class,
458
                'item_id' => $this->pk(),
459
                'type' => 'changes'
460
            ]);
461
            $changes_text = [];
462
            foreach ($this->_changedParams as $fullColName => $oldValue) {
463
                $colName = substr($fullColName, strlen($class::colPrefix()));
464 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...
465
                    continue;
466
                }
467
                if (strlen($oldValue) + strlen($this->_params[$fullColName]) < 200) {
468
                    $changes_text[] = (!empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName) . ": \"{$oldValue}\" => \"{$this->$colName}\"";
469
                } else {
470
                    $changes_text[] = !empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName;
471
                }
472
            }
473
            $activity->changes_text = implode(', ', $changes_text);
474
            $activity->save();
475
            foreach ($this->_changedParams as $fullColName => $oldValue) {
476
                $colName = substr($fullColName, strlen($class::colPrefix()));
477 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...
478
                    continue;
479
                }
480
                $colName = substr($fullColName, strlen($class::colPrefix()));
481
                $change = new Dashboard\Activity\Change([
482
                    'activity_id' => $activity->id,
483
                    'col' => $colName,
484
                    'old' => $oldValue,
485
                    'new' => $this->$colName
486
                ]);
487
                $change->save();
488
            }
489 2
        } elseif ($new) {
490 2
            $activity = new Dashboard\Activity([
491 2
                'user_id' => $user_id,
492 2
                'module' => substr($class, 0, strpos($class, '\\')),
493 2
                'model' => $class,
494 2
                'item_id' => $this->pk(),
495
                'type' => 'new'
496 2
            ]);
497 2
            $activity->save();
498 2
        }
499 2
        return true;
500
    }
501
502
    /**
503
     * Check model relations path and load need relations
504
     * 
505
     * @param string $col
506
     * @param string $rootModel
507
     */
508 4
    public static function checkForJoin(&$col, $rootModel) {
509
510 4
        if (strpos($col, ':') !== false) {
511
            $relations = static::relations();
512
            if (isset($relations[substr($col, 0, strpos($col, ':'))])) {
513
                $rel = substr($col, 0, strpos($col, ':'));
514
                $col = substr($col, strpos($col, ':') + 1);
515
516
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
517
                switch ($type) {
518 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...
519
                        $relCol = $relations[$rel]['col'];
520
                        static::fixPrefix($relCol);
521
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
522
                        break;
523
                    case 'one':
524 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...
525
                        $relCol = $relations[$rel]['col'];
526
                        $relations[$rel]['model']::fixPrefix($relCol);
527
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
528
                        break;
529
                }
530
                $relations[$rel]['model']::fixPrefix($col, 'key', $rootModel);
531
            }
532
        }
533 4
    }
534
535
    /**
536
     * Return full col information
537
     * 
538
     * @param string $col
539
     * @return array
540
     */
541
    public static function getColInfo($col) {
542
        return static::parseColRecursion($col);
543
    }
544
545
    /**
546
     * Information extractor for col relations path
547
     * 
548
     * @param string $info
549
     * @return array
550
     */
551
    public static function parseColRecursion($info) {
552
        if (is_string($info)) {
553
            $info = ['col' => $info, 'rawCol' => $info, 'modelName' => '', 'label' => '', 'joins' => []];
554
        }
555
        if (strpos($info['col'], ':') !== false) {
556
            $relations = static::relations();
557
            if (isset($relations[substr($info['col'], 0, strpos($info['col'], ':'))])) {
558
                $rel = substr($info['col'], 0, strpos($info['col'], ':'));
559
                $info['col'] = substr($info['col'], strpos($info['col'], ':') + 1);
560
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
561
                switch ($type) {
562 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...
563
                        $relCol = $relations[$rel]['col'];
564
                        static::fixPrefix($relCol);
565
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
566
                        break;
567 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...
568
                        $relCol = $relations[$rel]['col'];
569
                        $relations[$rel]['model']::fixPrefix($relCol);
570
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
571
                        break;
572
                }
573
                $info = $relations[$rel]['model']::parseColRecursion($info);
574
            }
575
        } else {
576
            $cols = static::cols();
577 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...
578
                $info['label'] = static::$labels[$info['col']];
579
            }
580
581
            if (isset(static::$cols[$info['col']])) {
582
                $info['colParams'] = static::$cols[$info['col']];
583
            } elseif (isset(static::$cols[str_replace(static::colPrefix(), '', $info['col'])])) {
584
                $info['colParams'] = static::$cols[str_replace(static::colPrefix(), '', $info['col'])];
585
            } else {
586
                $info['colParams'] = [];
587
            }
588 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...
589
                $info['col'] = static::colPrefix() . $info['col'];
590
            }
591
            $info['modelName'] = get_called_class();
592
        }
593 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...
594
            $info['label'] = static::$labels[$info['rawCol']];
595
        }
596
        return $info;
597
    }
598
599
    /**
600
     * Return actual cols from data base
601
     * 
602
     * @param boolean $refresh
603
     * @return array
604
     */
605 4
    public static function cols($refresh = false) {
606 4
        if (static::$storage['type'] == 'moduleConfig') {
607 1
            return [];
608
        }
609 4 View Code Duplication
        if (empty(Model::$cols[static::table()]) || $refresh) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
610 4
            Model::$cols[static::table()] = App::$cur->db->getTableCols(static::table());
611 4
        }
612 4 View Code Duplication
        if (!Model::$cols[static::table()]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
613
            static::createTable();
614
            Model::$cols[static::table()] = App::$cur->db->getTableCols(static::table());
615
        }
616 4
        return Model::$cols[static::table()];
617
    }
618
619
    /**
620
     * Return cols indexes for create tables
621
     * 
622
     * @return array
623
     */
624 3
    public static function indexes() {
625 3
        return [];
626
    }
627
628
    /**
629
     * Generate params string for col by name
630
     * 
631
     * @param string $colName
632
     * @return false|string
633
     */
634 4
    public static function genColParams($colName) {
635 4
        if (empty(static::$cols[$colName]) || static::$storage['type'] == 'moduleConfig') {
636 1
            return false;
637
        }
638
639 4
        $params = false;
640 4
        switch (static::$cols[$colName]['type']) {
641 4
            case 'select':
642 4
                switch (static::$cols[$colName]['source']) {
643 4
                    case 'relation':
644 4
                        $params = 'int(11) UNSIGNED NOT NULL';
645 4
                        break;
646 1
                    default:
647 1
                        $params = 'varchar(255) NOT NULL';
648 4
                }
649 4
                break;
650 4
            case 'image':
651 4
            case 'file':
652 1
                $params = 'int(11) UNSIGNED NOT NULL';
653 1
                break;
654 4
            case 'number':
655
                $params = 'int(11) NOT NULL';
656
                break;
657 4
            case 'text':
658 4
            case 'email':
659 3
                $params = 'varchar(255) NOT NULL';
660 3
                break;
661 3
            case 'html':
662 3
            case 'textarea':
663 3
            case 'json':
664 3
            case 'password':
665 3
            case 'dynamicType':
666 3
            case 'map':
667 1
                $params = 'text NOT NULL';
668 1
                break;
669 3
            case 'bool':
670 1
                $params = 'tinyint(1) UNSIGNED NOT NULL';
671 1
                break;
672 3
            case 'decimal':
673
                $params = 'decimal(8, 2) NOT NULL';
674
                break;
675 3
            case 'date':
676 1
                $params = 'date NOT NULL DEFAULT 0';
677 1
                break;
678 3
            case 'dateTime':
679 2
                $params = 'timestamp NOT NULL DEFAULT 0';
680 2
                break;
681 4
        }
682 4
        return $params;
683
    }
684
685
    /**
686
     * Create new col in data base
687
     * 
688
     * @param string $colName
689
     * @return boolean|integer
690
     */
691 2
    public static function createCol($colName) {
692 2
        $params = static::genColParams($colName);
693 2
        if ($params === false) {
694 2
            return false;
695
        }
696
        return App::$cur->db->addCol(static::table(), static::colPrefix() . $colName, $params);
697
    }
698
699 4
    public static function createTable() {
700 4
        if (static::$storage['type'] == 'moduleConfig') {
701
            return true;
702
        }
703 4
        if (!App::$cur->db) {
704
            return false;
705
        }
706
707 4
        $query = App::$cur->db->newQuery();
708 4
        if (!$query) {
709
            return false;
710
        }
711
712 4
        if (!isset($this)) {
713 4
            $tableName = static::table();
714 4
            $colPrefix = static::colPrefix();
715 4
            $indexes = static::indexes();
716 4
        } else {
717
            $tableName = $this->table();
718
            $colPrefix = $this->colPrefix();
719
            $indexes = $this->indexes();
720
        }
721 4
        if (App::$cur->db->tableExist($tableName)) {
722
            return true;
723
        }
724
        $cols = [
725 4
            $colPrefix . 'id' => 'pk'
726 4
        ];
727 4
        $className = get_called_class();
728 4
        if (!empty($className::$cols)) {
729 4
            foreach ($className::$cols as $colName => $colParams) {
730 4
                if ($colName == 'date_create') {
731 4
                    $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
732 4
                    continue;
733
                }
734 4
                $params = $className::genColParams($colName);
735 4
                if ($params) {
736 4
                    $cols[$colPrefix . $colName] = $params;
737 4
                }
738 4
            }
739 4
        }
740 4
        if (empty($cols[$colPrefix . 'date_create'])) {
741 1
            $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
742 1
        }
743 4
        $tableIndexes = [];
744 4
        if ($indexes) {
745 1
            foreach ($indexes as $indexName => $index) {
746 1
                $tableIndexes[] = $index['type'] . ' ' . App::$cur->db->table_prefix . $indexName . ' (' . implode(',', $index['cols']) . ')';
747 1
            }
748 1
        }
749
750 4
        $query->createTable($tableName, $cols, $tableIndexes);
751 4
        return true;
752
    }
753
754
    /**
755
     * Return table name
756
     * 
757
     * @return string
758
     */
759 4
    public static function table() {
760 4
        return strtolower(str_replace('\\', '_', get_called_class()));
761
    }
762
763
    /**
764
     * Return table index col name
765
     * 
766
     * @return string
767
     */
768 4
    public static function index() {
769
770 4
        return static::colPrefix() . 'id';
771
    }
772
773
    /**
774
     * Return col prefix
775
     * 
776
     * @return string
777
     */
778 4
    public static function colPrefix() {
779 4
        $classPath = explode('\\', get_called_class());
780 4
        $classPath = array_slice($classPath, 1);
781 4
        return strtolower(implode('_', $classPath)) . '_';
782
    }
783
784
    /**
785
     * return relations list
786
     * 
787
     * @return string
788
     */
789 1
    public static function relations() {
790 1
        return [];
791
    }
792
793
    /**
794
     * views list
795
     * 
796
     * @return array
797
     */
798
    public static $views = [];
799
800
    /**
801
     * Return name of col with object name
802
     * 
803
     * @return string
804
     */
805
    public static function nameCol() {
806
        return 'name';
807
    }
808
809
    /**
810
     * Return object name
811
     * 
812
     * @return string
813
     */
814
    public function name() {
815
        return $this->{$this->nameCol()} ? $this->{$this->nameCol()} : '№' . $this->pk();
816
    }
817
818
    /**
819
     * Get single object from data base
820
     * 
821
     * @param mixed $param
822
     * @param string $col
823
     * @param array $options
824
     * @return boolean|\Model
825
     */
826 4
    public static function get($param, $col = null, $options = []) {
827 4
        if (static::$storage['type'] == 'moduleConfig') {
828
            return static::getFromModuleStorage($param, $col, $options);
829
        }
830 4
        if (!empty($col)) {
831 4
            static::fixPrefix($col);
832 4
        }
833
834 4
        if (is_array($param)) {
835 1
            static::fixPrefix($param, 'first');
836 1
        }
837 4
        foreach (static::$relJoins as $join) {
838
            App::$cur->db->join($join[0], $join[1]);
839 4
        }
840 4
        static::$relJoins = [];
841 4
        foreach (static::$needJoin as $rel) {
842
            $relations = static::relations();
843
            if (isset($relations[$rel])) {
844
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
845
                switch ($type) {
846
                    case 'to':
847
                        $relCol = $relations[$rel]['col'];
848
                        static::fixPrefix($relCol);
849
                        App::$cur->db->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
850
                        break;
851
                    case 'one':
852
                        $col = $relations[$rel]['col'];
853
                        $relations[$rel]['model']::fixPrefix($col);
854
                        App::$cur->db->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
855
                        break;
856
                }
857
            }
858 4
        }
859 4
        static::$needJoin = [];
860 4
        if (is_array($param)) {
861 1
            App::$cur->db->where($param);
862 1
        } else {
863 4
            if ($col === null) {
864
865 3
                $col = static::index();
866 3
            }
867 4
            if ($param !== null) {
868 4
                $cols = static::cols();
869 4
                if (!isset($cols[$col]) && isset($cols[static::colPrefix() . $col])) {
870
                    $col = static::colPrefix() . $col;
871
                }
872 4
                App::$cur->db->where($col, $param);
873 4
            } else {
874
                return false;
875
            }
876
        }
877 4
        if (!App::$cur->db->where) {
878
            return false;
879
        }
880
        try {
881 4
            $result = App::$cur->db->select(static::table());
882 4
        } catch (PDOException $exc) {
883
            if ($exc->getCode() == '42S02') {
884
                static::createTable();
885
            }
886
            $result = App::$cur->db->select(static::table());
887
        }
888 4
        if (!$result) {
889
            return false;
890
        }
891 4
        return $result->fetch(get_called_class());
892
    }
893
894
    /**
895
     * Old method
896
     * 
897
     * @param type $options
898
     * @return Array
899
     */
900
    public static function get_list($options = []) {
901
        $query = App::$cur->db->newQuery();
902
        if (!$query) {
903
            return [];
904
        }
905
        if (!empty($options['where'])) {
906
            $query->where($options['where']);
907
        }
908
        if (!empty($options['cols'])) {
909
            $query->cols = $options['cols'];
910
        }
911
        if (!empty($options['group'])) {
912
            $query->group($options['group']);
913
        }
914
        if (!empty($options['having'])) {
915
            $query->having($options['having']);
916
        }
917
        if (!empty($options['order'])) {
918
            $query->order($options['order']);
919
        }
920
        if (!empty($options['join'])) {
921
            $query->join($options['join']);
922
        }
923
        if (!empty($options['distinct'])) {
924
            $query->distinct = $options['distinct'];
925
        }
926
927
        foreach (static::$relJoins as $join) {
928
            $query->join($join[0], $join[1]);
929
        }
930
        static::$relJoins = [];
931 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...
932
            $relations = static::relations();
933
            if (isset($relations[$rel])) {
934
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
935
                switch ($type) {
936
                    case 'to':
937
                        $relCol = $relations[$rel]['col'];
938
                        static::fixPrefix($relCol);
939
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
940
                        break;
941
                    case 'one':
942
                        $col = $relations[$rel]['col'];
943
                        $relations[$rel]['model']::fixPrefix($col);
944
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
945
                        break;
946
                }
947
            }
948
        }
949
        static::$needJoin = [];
950
951 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...
952
            $limit = (int) $options['limit'];
953
        } else {
954
            $limit = 0;
955
        }
956 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...
957
            $start = (int) $options['start'];
958
        } else {
959
            $start = 0;
960
        }
961
        if ($limit || $start) {
962
            $query->limit($start, $limit);
963
        }
964
        if (isset($options['key'])) {
965
            $key = $options['key'];
966
        } else {
967
            $key = static::index();
968
        }
969
        try {
970
            $query->operation = 'SELECT';
971
            $query->table = static::table();
972
            $queryArr = $query->buildQuery();
973
            $result = $query->query($queryArr);
974
        } catch (PDOException $exc) {
975
            if ($exc->getCode() == '42S02') {
976
                static::createTable();
977
                $result = $query->query($queryArr);
978
            } else {
979
                throw $exc;
980
            }
981
        }
982
983
        if (!empty($options['array'])) {
984
            return $result->getArray($key);
985
        }
986
        $list = $result->getObjects(get_called_class(), $key);
987 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...
988
            $return = [];
989
            foreach ($list as $key => $item) {
990
                $return[$key] = $item->name();
991
            }
992
            return $return;
993
        }
994
        return $list;
995
    }
996
997
    /**
998
     * Return list of objects from data base
999
     * 
1000
     * @param type $options
1001
     * @return type
1002
     */
1003
    public static function getList($options = []) {
1004
        if (static::$storage['type'] != 'db') {
1005
            return static::getListFromModuleStorage($options);
1006
        }
1007
        if (!empty($options['where'])) {
1008
            static::fixPrefix($options['where'], 'first');
1009
        }
1010
        if (!empty($options['group'])) {
1011
            static::fixPrefix($options['group'], 'first');
1012
        }
1013
        if (!empty($options['order'])) {
1014
            static::fixPrefix($options['order'], 'first');
1015
        }
1016
        if (!empty($options['having'])) {
1017
            static::fixPrefix($options['having'], 'first');
1018
        }
1019
        return static::get_list($options);
1020
    }
1021
1022
    /**
1023
     * Get single item from module storage
1024
     * 
1025
     * @param array $param
1026
     * @param string $col
1027
     * @param array $options
1028
     * @return boolean|\Model
1029
     */
1030
    public static function getFromModuleStorage($param = null, $col = null, $options = []) {
1031
        if ($col === null) {
1032
1033
            $col = static::index();
1034
        }
1035
        if ($param == null) {
1036
            return false;
1037
        }
1038
        $classPath = explode('\\', get_called_class());
1039 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...
1040
            $moduleConfig = Config::share($classPath[0]);
1041
        } else {
1042
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1043
        }
1044
        $appType = App::$cur->type;
1045 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...
1046
            if (!empty($options['appType'])) {
1047
                $appType = $options['appType'];
1048
            }
1049
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1050
        } else {
1051
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1052
        }
1053
        if (!empty($storage[$classPath[1]])) {
1054
            $items = $storage[$classPath[1]];
1055
            $class = get_called_class();
1056
            $where = is_array($param) ? $param : [$col, $param];
1057
            foreach ($items as $key => $item) {
1058
                if (!Model::checkWhere($item, $where)) {
1059
                    continue;
1060
                }
1061
                if (!empty($options['array'])) {
1062
                    return $item;
1063
                }
1064
                $item = new $class($item);
1065
                $item->appType = $appType;
1066
                return $item;
1067
            }
1068
        }
1069
        return false;
1070
    }
1071
1072
    /**
1073
     * Return list items from module storage
1074
     * 
1075
     * @param array $options
1076
     * @return array
1077
     */
1078
    public static function getListFromModuleStorage($options = []) {
1079
        $classPath = explode('\\', get_called_class());
1080 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...
1081
            $moduleConfig = Config::share($classPath[0]);
1082
        } else {
1083
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1084
        }
1085 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...
1086
            if (empty($options['appType'])) {
1087
                $appType = App::$cur->type;
1088
            } else {
1089
                $appType = $options['appType'];
1090
            }
1091
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1092
        } else {
1093
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1094
        }
1095
        if (!empty($storage[$classPath[1]])) {
1096
            $items = [];
1097
            $class = get_called_class();
1098
            if (isset($options['key'])) {
1099
                $arrayKey = $options['key'];
1100
            } else {
1101
                $arrayKey = static::index();
1102
            }
1103
            foreach ($storage[$classPath[1]] as $key => $item) {
1104
                if (!empty($options['where']) && !Model::checkWhere($item, $options['where'])) {
1105
                    continue;
1106
                }
1107
                $items[$item[$arrayKey]] = new $class($item);
1108
            }
1109
            if (!empty($options['order'])) {
1110
                usort($items, function($a, $b) use($options) {
1111
                    if ($a->{$options['order'][0]} > $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1112
                        return 1;
1113
                    } elseif ($a->{$options['order'][0]} < $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1114
                        return -1;
1115
                    }
1116
                    return 0;
1117
                });
1118
            }
1119 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...
1120
                $return = [];
1121
                foreach ($items as $key => $item) {
1122
                    $return[$key] = $item->name();
1123
                }
1124
                return $return;
1125
            }
1126
            return $items;
1127
        }
1128
        return [];
1129
    }
1130
1131
    /**
1132
     * Return count of records from module storage
1133
     * 
1134
     * @param array $options
1135
     * @return int
1136
     */
1137
    public static function getCountFromModuleStorage($options = []) {
1138
1139
        $classPath = explode('\\', get_called_class());
1140
        $count = 0;
1141
        if (empty($options['appType'])) {
1142
            $appType = App::$cur->type;
1143
        } else {
1144
            $appType = $options['appType'];
1145
        }
1146 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...
1147
            $moduleConfig = Config::share($classPath[0]);
1148
        } else {
1149
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1150
        }
1151
        if (!empty($moduleConfig['storage'][$appType][$classPath[1]])) {
1152
            $items = $moduleConfig['storage'][$appType][$classPath[1]];
1153
            if (empty($options['where'])) {
1154
                return count($items);
1155
            }
1156
            foreach ($items as $key => $item) {
1157
                if (!empty($options['where'])) {
1158
                    if (Model::checkWhere($item, $options['where'])) {
1159
                        $count++;
1160
                    }
1161
                } else {
1162
                    $count++;
1163
                }
1164
            }
1165
        }
1166
        return $count;
1167
    }
1168
1169
    /**
1170
     * Check where for module storage query
1171
     * 
1172
     * @param array $item
1173
     * @param array|string $where
1174
     * @param string $value
1175
     * @param string $operation
1176
     * @param string $concatenation
1177
     * @return boolean
1178
     */
1179
    public static function checkWhere($item = [], $where = '', $value = '', $operation = '=', $concatenation = 'AND') {
1180
1181
        if (is_array($where)) {
1182
            if (is_array($where[0])) {
1183
                $result = true;
1184
                foreach ($where as $key => $whereItem) {
1185
                    $concatenation = empty($whereItem[3]) ? 'AND' : strtoupper($whereItem[3]);
1186
                    switch ($concatenation) {
1187 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...
1188
                            $result = $result && forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1189
                            break;
1190 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...
1191
                            $result = $result || forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1192
                            break;
1193
                    }
1194
                }
1195
1196
                return $result;
1197
            } else {
1198
                return forward_static_call_array(['Model', 'checkWhere'], array_merge([$item], $where));
1199
            }
1200
        }
1201
        if (!isset($item[$where]) && !$value) {
1202
            return true;
1203
        }
1204
        if (!isset($item[$where]) && $value) {
1205
            return false;
1206
        }
1207
        if ($item[$where] == $value) {
1208
            return true;
1209
        }
1210
        return false;
1211
    }
1212
1213
    /**
1214
     * Return count of records from data base
1215
     * 
1216
     * @param array $options
1217
     * @return array|int
1218
     */
1219
    public static function getCount($options = []) {
1220
        if (static::$storage['type'] == 'moduleConfig') {
1221
            return static::getCountFromModuleStorage($options);
1222
        }
1223
        $query = App::$cur->db->newQuery();
1224
        if (!$query) {
1225
            return 0;
1226
        }
1227
        if (!empty($options['where'])) {
1228
            static::fixPrefix($options['where'], 'first');
1229
        }
1230
        if (!empty($options['group'])) {
1231
            static::fixPrefix($options['group'], 'first');
1232
        }
1233
        if (!empty($options['where'])) {
1234
            $query->where($options['where']);
1235
        }
1236
        if (!empty($options['join'])) {
1237
            $query->join($options['join']);
1238
        }
1239
        if (!empty($options['order'])) {
1240
            $query->order($options['order']);
1241
        }
1242 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...
1243
            $limit = (int) $options['limit'];
1244
        } else {
1245
            $limit = 0;
1246
        }
1247 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...
1248
            $start = (int) $options['start'];
1249
        } else {
1250
            $start = 0;
1251
        }
1252
        if ($limit || $start) {
1253
            $query->limit($start, $limit);
1254
        }
1255
1256
        foreach (static::$relJoins as $join) {
1257
            $query->join($join[0], $join[1]);
1258
        }
1259
        static::$relJoins = [];
1260 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...
1261
            $relations = static::relations();
1262
            if (isset($relations[$rel])) {
1263
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
1264
                switch ($type) {
1265
                    case 'to':
1266
                        $relCol = $relations[$rel]['col'];
1267
                        static::fixPrefix($relCol);
1268
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
1269
                        break;
1270
                    case 'one':
1271
                        $col = $relations[$rel]['col'];
1272
                        $relations[$rel]['model']::fixPrefix($col);
1273
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
1274
                        break;
1275
                }
1276
            }
1277
        }
1278
        static::$needJoin = [];
1279
        $cols = 'COUNT(';
1280
1281
        if (!empty($options['distinct'])) {
1282
            if (is_bool($options['distinct'])) {
1283
                $cols .= 'DISTINCT *';
1284
            } else {
1285
                $cols .= "DISTINCT {$options['distinct']}";
1286
            }
1287
        } else {
1288
            $cols .= '*';
1289
        }
1290
        $cols .=') as `count`' . (!empty($options['cols']) ? ',' . $options['cols'] : '');
1291
        $query->cols = $cols;
1292
        if (!empty($options['group'])) {
1293
            $query->group($options['group']);
1294
        }
1295
        try {
1296
            $result = $query->select(static::table());
1297
        } catch (PDOException $exc) {
1298
            if ($exc->getCode() == '42S02') {
1299
                static::createTable();
1300
            }
1301
            $result = $query->select(static::table());
1302
        }
1303
        if (!empty($options['group'])) {
1304
            $count = $result->getArray();
1305
            return $count;
1306
        } else {
1307
            $count = $result->fetch();
1308
            return $count['count'];
1309
        }
1310
    }
1311
1312
    /**
1313
     * Update records in data base
1314
     * 
1315
     * @param array $params
1316
     * @param array $where
1317
     * @return false|null
1318
     */
1319
    public static function update($params, $where = []) {
1320
        static::fixPrefix($params);
1321
1322
        $cols = self::cols();
1323
1324
        $values = [];
1325
        foreach ($cols as $col => $param) {
1326
            if (isset($params[$col])) {
1327
                $values[$col] = $params[$col];
1328
            }
1329
        }
1330
        if (empty($values)) {
1331
            return false;
1332
        }
1333
1334
        if (!empty($where)) {
1335
            static::fixPrefix($where, 'first');
1336
1337
            App::$cur->db->where($where);
1338
        }
1339
        App::$cur->db->update(static::table(), $values);
1340
    }
1341
1342
    /**
1343
     * Return primary key of object
1344
     * 
1345
     * @return mixed
1346
     */
1347 4
    public function pk() {
1348 4
        return $this->{$this->index()};
1349
    }
1350
1351
    /**
1352
     * Before save trigger
1353
     */
1354 4
    public function beforeSave() {
1355
        
1356 4
    }
1357
1358
    /**
1359
     * Save object to module storage
1360
     * 
1361
     * @param array $options
1362
     * @return boolean
1363
     */
1364 1
    public function saveModuleStorage($options) {
1365
1366 1
        $col = static::index();
1367 1
        $id = $this->pk();
1368 1
        $appType = '';
1369 1
        $classPath = explode('\\', get_called_class());
1370
1371 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...
1372
            $moduleConfig = Config::share($classPath[0]);
1373
        } else {
1374 1
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1375
        }
1376
1377 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...
1378 1
            if (empty($options['appType'])) {
1379
                $appType = App::$cur->type;
1380
            } else {
1381 1
                $appType = $options['appType'];
1382
            }
1383 1
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1384 1
        } else {
1385
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1386
        }
1387 1
        if (empty($storage[$classPath[1]])) {
1388
            $storage[$classPath[1]] = [];
1389
        }
1390 1
        if ($id) {
1391 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...
1392
                if ($item[$col] == $id) {
1393
                    $storage[$classPath[1]][$key] = $this->_params;
1394
                    break;
1395
                }
1396
            }
1397
        } else {
1398 1
            $id = !empty($storage['scheme'][$classPath[1]]['ai']) ? $storage['scheme'][$classPath[1]]['ai'] : 1;
1399 1
            $this->$col = $id;
1400 1
            $storage['scheme'][$classPath[1]]['ai'] = $id + 1;
1401 1
            $storage[$classPath[1]][] = $this->_params;
1402
        }
1403 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...
1404 1
            $moduleConfig['storage'][$appType] = $storage;
1405 1
        } else {
1406
            $moduleConfig['storage'] = $storage;
1407
        }
1408 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...
1409 1
            Config::save('module', $moduleConfig, $classPath[0]);
1410 1
        } else {
1411
            Config::save('share', $moduleConfig, $classPath[0]);
1412
        }
1413 1
        return true;
1414
    }
1415
1416
    /**
1417
     * Update tree path category
1418
     */
1419
    public function changeCategoryTree() {
1420
        $class = get_class($this);
1421
        $itemModel = $class::$treeCategory;
1422
        $oldPath = $this->tree_path;
1423
        $this->tree_path = $this->getCatalogTree($this);
1424
        $itemsTable = \App::$cur->db->table_prefix . $itemModel::table();
1425
        $itemTreeCol = $itemModel::colPrefix() . 'tree_path';
1426
1427
        $categoryTreeCol = $this->colPrefix() . 'tree_path';
1428
        $categoryTable = \App::$cur->db->table_prefix . $this->table();
1429
        if ($oldPath) {
1430
            \App::$cur->db->query('UPDATE
1431
                ' . $categoryTable . ' 
1432
                    SET 
1433
                        ' . $categoryTreeCol . ' = REPLACE(' . $categoryTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1434
                    WHERE ' . $categoryTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1435
1436
            \App::$cur->db->query('UPDATE
1437
                ' . $itemsTable . '
1438
                    SET 
1439
                        ' . $itemTreeCol . ' = REPLACE(' . $itemTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1440
                    WHERE ' . $itemTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1441
        }
1442
        $itemModel::update([$itemTreeCol => $this->tree_path . $this->id . '/'], [$itemModel::colPrefix() . $this->index(), $this->id]);
1443
    }
1444
1445
    /**
1446
     * Return tree path
1447
     * 
1448
     * @param \Model $catalog
1449
     * @return string
1450
     */
1451
    public function getCatalogTree($catalog) {
1452
        $catalogClass = get_class($catalog);
1453
        $catalogParent = $catalogClass::get($catalog->parent_id);
1454
        if ($catalog && $catalogParent) {
1455
            if ($catalogParent->tree_path) {
1456
                return $catalogParent->tree_path . $catalogParent->id . '/';
1457
            } else {
1458
                return $this->getCatalogTree($catalogParent) . $catalogParent->id . '/';
1459
            }
1460
        }
1461
        return '/';
1462
    }
1463
1464
    /**
1465
     * Update tree path item
1466
     */
1467
    public function changeItemTree() {
1468
        $class = get_class($this);
1469
        $categoryModel = $class::$categoryModel;
1470
        $category = $categoryModel::get($this->{$categoryModel::index()});
1471
        if ($category) {
1472
            $this->tree_path = $category->tree_path . $category->pk() . '/';
1473
        } else {
1474
            $this->tree_path = '/';
1475
        }
1476
    }
1477
1478
    /**
1479
     * Save object to data base
1480
     * 
1481
     * @param array $options
1482
     * @return boolean|int
1483
     */
1484 4
    public function save($options = []) {
1485
1486 4
        if (static::$storage['type'] == 'moduleConfig') {
1487 1
            return static::saveModuleStorage($options);
1488
        }
1489 4
        $class = get_class($this);
1490 4
        if ($class::$categoryModel) {
1491
            $this->changeItemTree();
1492
        }
1493 4
        if ($class::$treeCategory) {
1494
            $this->changeCategoryTree();
1495
        }
1496 4
        if (!empty($this->_changedParams) && $this->pk()) {
1497 3
            Inji::$inst->event('modelItemParamsChanged-' . get_called_class(), $this);
1498 3
        }
1499 4
        $this->beforeSave();
1500 4
        $values = [];
1501
1502 4
        foreach ($this->cols() as $col => $param) {
1503 4
            if (isset($this->_params[$col])) {
1504 4
                $values[$col] = $this->_params[$col];
1505 4
            }
1506 4
        }
1507 4
        foreach ($class::$cols as $colName => $params) {
1508 4
            $class::fixPrefix($colName);
1509 4
            if (isset($params['default']) && !isset($values[$colName])) {
1510
                $this->_params[$colName] = $values[$colName] = $params['default'];
1511
            }
1512 4
        }
1513 4
        if (empty($values) && empty($options['empty'])) {
1514
            return false;
1515
        }
1516
1517 4
        if ($this->pk()) {
1518 3
            $new = false;
1519 3
            if ($this->get($this->_params[$this->index()])) {
1520 3
                App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1521 3
                App::$cur->db->update($this->table(), $values);
1522 3
            } else {
1523
1524
                $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1525
            }
1526 3
        } else {
1527 4
            $new = true;
1528 4
            $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1529
        }
1530 4
        $this->logChanges($new);
1531 4
        App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1532
        try {
1533 4
            $result = App::$cur->db->select($this->table());
1534 4
        } catch (PDOException $exc) {
1535
            if ($exc->getCode() == '42S02') {
1536
                $this->createTable();
1537
            }
1538
            $result = App::$cur->db->select($this->table());
1539
        }
1540 4
        $this->_params = $result->fetch();
1541 4
        if ($new) {
1542 4
            Inji::$inst->event('modelCreatedItem-' . get_called_class(), $this);
1543 4
        }
1544 4
        $this->afterSave();
1545 4
        return $this->{$this->index()};
1546
    }
1547
1548
    /**
1549
     * After save trigger
1550
     */
1551 4
    public function afterSave() {
1552
        
1553 4
    }
1554
1555
    /**
1556
     * Before delete trigger
1557
     */
1558 1
    public function beforeDelete() {
1559
        
1560 1
    }
1561
1562
    /**
1563
     * Delete item from module storage
1564
     * 
1565
     * @param array $options
1566
     * @return boolean
1567
     */
1568
    public function deleteFromModuleStorage($options) {
1569
1570
        $col = static::index();
1571
        $id = $this->pk();
1572
        $appType = '';
1573
        $classPath = explode('\\', get_called_class());
1574 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...
1575
            $moduleConfig = Config::share($classPath[0]);
1576
        } else {
1577
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1578
        }
1579
1580 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...
1581
            if (empty($options['appType'])) {
1582
                $appType = App::$cur->type;
1583
            } else {
1584
                $appType = $options['appType'];
1585
            }
1586
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1587
        } else {
1588
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1589
        }
1590
        if (empty($storage[$classPath[1]])) {
1591
            $storage[$classPath[1]] = [];
1592
        }
1593 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...
1594
1595
            if ($item[$col] == $id) {
1596
                unset($storage[$classPath[1]][$key]);
1597
                break;
1598
            }
1599
        }
1600 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...
1601
            $moduleConfig['storage'][$appType] = $storage;
1602
        } else {
1603
            $moduleConfig['storage'] = $storage;
1604
        }
1605 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...
1606
            Config::save('module', $moduleConfig, $classPath[0]);
1607
        } else {
1608
            Config::save('share', $moduleConfig, $classPath[0]);
1609
        }
1610
        return true;
1611
    }
1612
1613
    /**
1614
     * Delete item from data base
1615
     * 
1616
     * @param array $options
1617
     * @return boolean
1618
     */
1619 1
    public function delete($options = []) {
1620 1
        $this->beforeDelete();
1621
1622 1
        if (static::$storage['type'] == 'moduleConfig') {
1623
            return static::deleteFromModuleStorage($options);
1624
        }
1625 1
        if (!empty($this->_params[$this->index()])) {
1626 1
            App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1627 1
            $result = App::$cur->db->delete($this->table());
1628 1
            if ($result) {
1629 1
                $this->afterDelete();
1630 1
                return $result;
1631
            }
1632
        }
1633
        return false;
1634
    }
1635
1636
    /**
1637
     * Delete items from data base
1638
     * 
1639
     * @param array $where
1640
     */
1641 4
    public static function deleteList($where = []) {
1642 4
        if (!empty($where)) {
1643
            static::fixPrefix($where, 'first');
1644
            App::$cur->db->where($where);
1645
        }
1646 4
        App::$cur->db->delete(static::table());
1647 4
    }
1648
1649
    /**
1650
     * After delete trigger
1651
     */
1652 1
    public function afterDelete() {
1653
        
1654 1
    }
1655
1656
    /**
1657
     * find relation for col name
1658
     * 
1659
     * @param string $col
1660
     * @return array|null
1661
     */
1662
    public static function findRelation($col) {
1663
1664
        foreach (static::relations() as $relName => $rel) {
1665
            if ($rel['col'] == $col) {
1666
                return $relName;
1667
            }
1668
        }
1669
        return null;
1670
    }
1671
1672
    /**
1673
     * Set params for model
1674
     * 
1675
     * @param array $params
1676
     */
1677 4
    public function setParams($params) {
1678 4
        static::fixPrefix($params);
1679 4
        $className = get_called_class();
1680 4
        foreach ($params as $paramName => $value) {
1681 2
            $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $paramName);
1682 2
            if (!empty($className::$cols[$shortName])) {
1683 2
                switch ($className::$cols[$shortName]['type']) {
1684 2
                    case 'decimal':
1685
                        $params[$paramName] = (float) $value;
1686
                        break;
1687 2
                    case 'number':
1688 2
                        $params[$paramName] = (int) $value;
1689 2
                        break;
1690 2
                    case 'bool':
1691 1
                        $params[$paramName] = (bool) $value;
1692 1
                        break;
1693 2
                }
1694 2
            }
1695 4
        }
1696 4
        $this->_params = array_merge($this->_params, $params);
1697 4
    }
1698
1699
    /**
1700
     * Return relation
1701
     * 
1702
     * @param string $relName
1703
     * @return array|boolean
1704
     */
1705 4
    public static function getRelation($relName) {
1706 4
        $relations = static::relations();
1707 4
        return !empty($relations[$relName]) ? $relations[$relName] : false;
1708
    }
1709
1710
    /**
1711
     * Load relation
1712
     * 
1713
     * @param string $name
1714
     * @param array $params
1715
     * @return null|array|integer|\Model
1716
     */
1717 4
    public function loadRelation($name, $params = []) {
1718 4
        $relation = static::getRelation($name);
1719 4
        if ($relation) {
1720 2
            if (!isset($relation['type'])) {
1721 2
                $type = 'to';
1722 2
            } else {
1723
                $type = $relation['type'];
1724
            }
1725 2
            $getCol = null;
1726 2
            $getParams = [];
1727
            switch ($type) {
1728 2
                case 'relModel':
1729
                    if (!$this->pk()) {
1730
                        return [];
1731
                    }
1732
                    $fixedCol = $relation['model']::index();
1733
                    $relation['relModel']::fixPrefix($fixedCol);
1734
                    $ids = array_keys($relation['relModel']::getList(['where' => [$this->index(), $this->pk()], 'array' => true, 'key' => $fixedCol]));
1735
                    if (empty($ids)) {
1736
                        if (empty($params['count'])) {
1737
                            return [];
1738
                        } else {
1739
                            return 0;
1740
                        }
1741
                    }
1742
                    $getType = 'getList';
1743
                    $options = [
1744
                        'where' => [$relation['model']::index(), implode(',', $ids), 'IN'],
1745
                        'array' => (!empty($params['array'])) ? true : false,
1746
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1747
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1748
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1749
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1750
                    ];
1751
                    break;
1752 2
                case 'many':
1753
                    if (!$this->{$this->index()}) {
1754
                        return [];
1755
                    }
1756
                    $getType = 'getList';
1757
                    $options = [
1758
                        'join' => (isset($relation['join'])) ? $relation['join'] : null,
1759
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1760
                        'array' => (!empty($params['array'])) ? true : false,
1761
                        'forSelect' => (!empty($params['forSelect'])) ? true : false,
1762
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1763
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1764
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1765
                        'appType' => (isset($params['appType'])) ? $params['appType'] : ((isset($relation['appType'])) ? $relation['appType'] : null),
1766
                        'where' => []
1767
                    ];
1768
                    $options['where'][] = [$relation['col'], $this->{$this->index()}];
1769
                    if (!empty($relation['where'])) {
1770
                        $options['where'] = array_merge($options['where'], [$relation['where']]);
1771
                    }
1772
                    if (!empty($params['where'])) {
1773
                        $options['where'] = array_merge($options['where'], [$params['where']]);
1774
                    }
1775
                    break;
1776 2
                case 'one':
1777
                    $getType = 'get';
1778
                    $options = [$relation['col'], $this->pk()];
1779
                    break;
1780 2
                default:
1781 2
                    if ($this->$relation['col'] === null) {
1782
                        return null;
1783
                    }
1784 2
                    $getType = 'get';
1785 2
                    $options = $this->$relation['col'];
1786 2
                    $getParams['appType'] = $this->appType;
1787 2
            }
1788 2
            if (!empty($params['count'])) {
1789
                if (class_exists($relation['model'])) {
1790
                    return $relation['model']::getCount($options);
1791
                }
1792
                return 0;
1793
            } else {
1794 2
                if (class_exists($relation['model'])) {
1795 2
                    $this->loadedRelations[$name][json_encode($params)] = $relation['model']::$getType($options, $getCol, $getParams);
1796 2
                } else {
1797
                    $this->loadedRelations[$name][json_encode($params)] = [];
1798
                }
1799
            }
1800 2
            return $this->loadedRelations[$name][json_encode($params)];
1801
        }
1802 4
        return null;
1803
    }
1804
1805
    /**
1806
     * Add relation item
1807
     * 
1808
     * @param string $relName
1809
     * @param \Model $objectId
1810
     * @return \Model|boolean
1811
     */
1812
    public function addRelation($relName, $objectId) {
1813
        $relation = $this->getRelation($relName);
1814
        if ($relation) {
1815
            $rel = $relation['relModel']::get([[$relation['model']::index(), $objectId], [$this->index(), $this->pk()]]);
1816
            if (!$rel) {
1817
                $rel = new $relation['relModel']([
1818
                    $relation['model']::index() => $objectId,
1819
                    $this->index() => $this->pk()
1820
                ]);
1821
                $rel->save();
1822
            }
1823
            return $rel;
1824
        }
1825
        return false;
1826
    }
1827
1828
    /**
1829
     * Check user access for form
1830
     * 
1831
     * @param string $formName
1832
     * @return boolean
1833
     */
1834
    public function checkFormAccess($formName) {
1835
        if ($formName == 'manage' && !Users\User::$cur->isAdmin()) {
1836
            return false;
1837
        }
1838
        return true;
1839
    }
1840
1841
    /**
1842
     * Check access for model
1843
     * 
1844
     * @param string $mode
1845
     * @param \Users\User $user
1846
     * @return boolean
1847
     */
1848
    public function checkAccess($mode = 'write', $user = null) {
1849
        if (!$user) {
1850
            $user = \Users\User::$cur;
1851
        }
1852
        return $user->isAdmin();
1853
    }
1854
1855
    /**
1856
     * Param and relation with params getter
1857
     * 
1858
     * @param string $name
1859
     * @param array $params
1860
     * @return \Value|mixed
1861
     */
1862
    public function __call($name, $params) {
1863
        $fixedName = $name;
1864
        static::fixPrefix($fixedName);
1865 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...
1866
            return new Value($this, $fixedName);
1867
        } elseif (isset($this->_params[$name])) {
1868
            return new Value($this, $name);
1869
        }
1870
        return call_user_func_array([$this, 'loadRelation'], array_merge([$name], $params));
1871
    }
1872
1873
    /**
1874
     * Param and relation getter
1875
     * 
1876
     * @param string $name
1877
     * @return mixed
1878
     */
1879 4
    public function __get($name) {
1880 4
        $fixedName = $name;
1881 4
        static::fixPrefix($fixedName);
1882 4
        if (isset($this->_params[$fixedName])) {
1883 4
            return $this->_params[$fixedName];
1884
        }
1885 4
        if (isset($this->loadedRelations[$name][json_encode([])])) {
1886 2
            return $this->loadedRelations[$name][json_encode([])];
1887
        }
1888 4
        return $this->loadRelation($name);
1889
    }
1890
1891
    /**
1892
     * Return model value in object
1893
     * 
1894
     * @param string $name
1895
     * @return \Value|null
1896
     */
1897
    public function value($name) {
1898
        $fixedName = $name;
1899
        static::fixPrefix($fixedName);
1900 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...
1901
            return new Value($this, $fixedName);
1902
        } elseif ($this->_params[$name]) {
1903
            return new Value($this, $name);
1904
        }
1905
        return null;
1906
    }
1907
1908
    /**
1909
     * Return manager filters
1910
     * 
1911
     * @return array
1912
     */
1913
    public static function managerFilters() {
1914
        return [];
1915
    }
1916
1917
    /**
1918
     * Return validators for cols
1919
     * 
1920
     * @return array
1921
     */
1922
    public static function validators() {
1923
        return [];
1924
    }
1925
1926
    /**
1927
     * Return validator by name
1928
     * 
1929
     * @param string $name
1930
     * @return array
1931
     */
1932
    public static function validator($name) {
1933
        $validators = static::validators();
1934
        if (!empty($validators[$name])) {
1935
            return $validators[$name];
1936
        }
1937
        return [];
1938
    }
1939
1940
    public function genViewLink() {
1941
        $className = get_class($this);
1942
        $link = substr($className, 0, strpos($className, '\\'));
1943
        $link .= '/view/';
1944
        $link .= str_replace('\\', '%5C', substr($className, strpos($className, '\\') + 1));
1945
        $link .= "/{$this->id}";
1946
        return $link;
1947
    }
1948
1949
    /**
1950
     * Set handler for model params
1951
     * 
1952
     * @param string $name
1953
     * @param mixed $value
1954
     */
1955 4
    public function __set($name, $value) {
1956 4
        static::fixPrefix($name);
1957 4
        $className = get_called_class();
1958 4
        $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $name);
1959 4
        if (!empty($className::$cols[$shortName])) {
1960 4
            switch ($className::$cols[$shortName]['type']) {
1961 4
                case 'decimal':
1962
                    $value = (float) $value;
1963
                    break;
1964 4
                case 'number':
1965
                    $value = (int) $value;
1966
                    break;
1967 4
                case 'bool':
1968
                    $value = (bool) $value;
1969
                    break;
1970 4
            }
1971 4
        }
1972 4
        if ((isset($this->_params[$name]) && $this->_params[$name] != $value) && !isset($this->_changedParams[$name])) {
1973 3
            $this->_changedParams[$name] = $this->_params[$name];
1974 3
        }
1975
1976 4
        $this->_params[$name] = $value;
1977 4
    }
1978
1979
    /**
1980
     * Isset handler for model params
1981
     * 
1982
     * @param string $name
1983
     * @return boolean
1984
     */
1985
    public function __isset($name) {
1986
        static::fixPrefix($name);
1987
        return isset($this->_params[$name]);
1988
    }
1989
1990
    /**
1991
     * Convert object to string
1992
     * 
1993
     * @return string
1994
     */
1995
    public function __toString() {
1996
        return $this->name();
1997
    }
1998
}