Passed
Push — master ( c8f806...893e91 )
by Alexey
05:17
created

Model::beforeDelete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Log
5
 *
6
 * @author Alexey Krupskiy <[email protected]>
7
 * @link http://inji.ru/
8
 * @copyright 2015 Alexey Krupskiy
9
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
10
 */
11
class Model {
12
13
    /**
14
     * Object storage type
15
     * 
16
     * @var array 
17
     */
18
    public static $storage = ['type' => 'db'];
19
20
    /**
21
     * Object name
22
     * 
23
     * @var string 
24
     */
25
    public static $objectName = '';
26
27
    /**
28
     * App type for separate data storage
29
     * 
30
     * @var string
31
     */
32
    public $appType = 'app';
33
34
    /**
35
     * Object current params
36
     * 
37
     * @var array
38
     */
39
    public $_params = [];
40
41
    /**
42
     * List of changed params in current instance
43
     * 
44
     * @var array
45
     */
46
    public $_changedParams = [];
47
48
    /**
49
     * Loaded relations
50
     * 
51
     * @var array 
52
     */
53
    public $loadedRelations = [];
54
55
    /**
56
     * Model name where this model uses as category
57
     * 
58
     * @var string
59
     */
60
    public static $treeCategory = '';
61
62
    /**
63
     * Model name who uses as category in this model
64
     * 
65
     * @var string
66
     */
67
    public static $categoryModel = '';
68
69
    /**
70
     * Col labels
71
     * 
72
     * @var array
73
     */
74
    public static $labels = [];
75
76
    /**
77
     * Model forms
78
     * 
79
     * @var array
80
     */
81
    public static $forms = [];
82
83
    /**
84
     * Model cols
85
     * 
86
     * @var array
87
     */
88
    public static $cols = [];
89
90
    /**
91
     * Options group for display inforamtion from model
92
     * 
93
     * @var array
94
     */
95
    public static $view = [];
96
97
    /**
98
     * List of relations need loaded with item
99
     * 
100
     * @var array 
101
     */
102
    public static $needJoin = [];
103
104
    /**
105
     * List of joins who need to laod
106
     * 
107
     * @var array 
108
     */
109
    public static $relJoins = [];
110
111
    /**
112
     * Set params when model create
113
     * 
114
     * @param array $params
115
     */
116 4
    public function __construct($params = []) {
117 4
        $this->setParams($params);
118 4
    }
119
120
    public static $logging = true;
121
122
    /**
123
     * return object name
124
     * 
125
     * @return string
126
     */
127
    public static function objectName() {
128
        return static::$objectName;
129
    }
130
131
    /**
132
     * Retrn col value with col params and relations path
133
     * 
134
     * @param Model $object
135
     * @param string $valuePath
136
     * @param boolean $convert
137
     * @param boolean $manageHref
138
     * @return string
139
     */
140
    public static function getColValue($object, $valuePath, $convert = false, $manageHref = false) {
141
        if (strpos($valuePath, ':')) {
142
            $rel = substr($valuePath, 0, strpos($valuePath, ':'));
143
            $param = substr($valuePath, strpos($valuePath, ':') + 1);
144
            if (!$object->$rel) {
145
                $modelName = get_class($object);
146
                $relations = $modelName::relations();
147
                if (empty($relations[$rel]['type']) || $relations[$rel]['type'] == 'one') {
148
                    return $object->{$relations[$rel]['col']};
149
                }
150
                return 0;
151
            }
152
            if (strpos($valuePath, ':')) {
153
                return self::getColValue($object->$rel, $param, $convert, $manageHref);
154
            } else {
155
                return $convert ? Model::resloveTypeValue($object->$rel, $param, $manageHref) : $object->$rel->$param;
156
            }
157
        } else {
158
            return $convert ? Model::resloveTypeValue($object, $valuePath, $manageHref) : $object->$valuePath;
159
        }
160
    }
161
162
    /**
163
     * Retrun value for view
164
     * 
165
     * @param Model $item
166
     * @param string $colName
167
     * @param boolean $manageHref
168
     * @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
            if (!$changes_text) {
474
                return false;
475
            }
476
            $activity->changes_text = implode(', ', $changes_text);
477
            $activity->save();
478
            foreach ($this->_changedParams as $fullColName => $oldValue) {
479
                $colName = substr($fullColName, strlen($class::colPrefix()));
480 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...
481
                    continue;
482
                }
483
                $colName = substr($fullColName, strlen($class::colPrefix()));
484
                $change = new Dashboard\Activity\Change([
485
                    'activity_id' => $activity->id,
486
                    'col' => $colName,
487
                    'old' => $oldValue,
488
                    'new' => $this->$colName
489
                ]);
490
                $change->save();
491
            }
492 2
        } elseif ($new) {
493 2
            $activity = new Dashboard\Activity([
494 2
                'user_id' => $user_id,
495 2
                'module' => substr($class, 0, strpos($class, '\\')),
496 2
                'model' => $class,
497 2
                'item_id' => $this->pk(),
498
                'type' => 'new'
499 2
            ]);
500 2
            $activity->save();
501 2
        }
502 2
        return true;
503
    }
504
505
    /**
506
     * Check model relations path and load need relations
507
     * 
508
     * @param string $col
509
     * @param string $rootModel
510
     */
511 4
    public static function checkForJoin(&$col, $rootModel) {
512
513 4
        if (strpos($col, ':') !== false) {
514
            $relations = static::relations();
515
            if (isset($relations[substr($col, 0, strpos($col, ':'))])) {
516
                $rel = substr($col, 0, strpos($col, ':'));
517
                $col = substr($col, strpos($col, ':') + 1);
518
519
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
520
                switch ($type) {
521 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...
522
                        $relCol = $relations[$rel]['col'];
523
                        static::fixPrefix($relCol);
524
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
525
                        break;
526
                    case 'one':
527 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...
528
                        $relCol = $relations[$rel]['col'];
529
                        $relations[$rel]['model']::fixPrefix($relCol);
530
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
531
                        break;
532
                }
533
                $relations[$rel]['model']::fixPrefix($col, 'key', $rootModel);
534
            }
535
        }
536 4
    }
537
538
    /**
539
     * Return full col information
540
     * 
541
     * @param string $col
542
     * @return array
543
     */
544
    public static function getColInfo($col) {
545
        return static::parseColRecursion($col);
546
    }
547
548
    /**
549
     * Information extractor for col relations path
550
     * 
551
     * @param string $info
552
     * @return array
553
     */
554
    public static function parseColRecursion($info) {
555
        if (is_string($info)) {
556
            $info = ['col' => $info, 'rawCol' => $info, 'modelName' => '', 'label' => '', 'joins' => []];
557
        }
558
        if (strpos($info['col'], ':') !== false) {
559
            $relations = static::relations();
560
            if (isset($relations[substr($info['col'], 0, strpos($info['col'], ':'))])) {
561
                $rel = substr($info['col'], 0, strpos($info['col'], ':'));
562
                $info['col'] = substr($info['col'], strpos($info['col'], ':') + 1);
563
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
564
                switch ($type) {
565 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...
566
                        $relCol = $relations[$rel]['col'];
567
                        static::fixPrefix($relCol);
568
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
569
                        break;
570 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...
571
                        $relCol = $relations[$rel]['col'];
572
                        $relations[$rel]['model']::fixPrefix($relCol);
573
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
574
                        break;
575
                }
576
                $info = $relations[$rel]['model']::parseColRecursion($info);
577
            }
578
        } else {
579
            $cols = static::cols();
580 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...
581
                $info['label'] = static::$labels[$info['col']];
582
            }
583
584
            if (isset(static::$cols[$info['col']])) {
585
                $info['colParams'] = static::$cols[$info['col']];
586
            } elseif (isset(static::$cols[str_replace(static::colPrefix(), '', $info['col'])])) {
587
                $info['colParams'] = static::$cols[str_replace(static::colPrefix(), '', $info['col'])];
588
            } else {
589
                $info['colParams'] = [];
590
            }
591 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...
592
                $info['col'] = static::colPrefix() . $info['col'];
593
            }
594
            $info['modelName'] = get_called_class();
595
        }
596 View Code Duplication
        if (!empty(static::$labels[$info['rawCol']])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
597
            $info['label'] = static::$labels[$info['rawCol']];
598
        }
599
        return $info;
600
    }
601
602
    /**
603
     * Return actual cols from data base
604
     * 
605
     * @param boolean $refresh
606
     * @return array
607
     */
608 4
    public static function cols($refresh = false) {
609 4
        if (static::$storage['type'] == 'moduleConfig') {
610 1
            return [];
611
        }
612 4 View Code Duplication
        if (empty(Model::$cols[static::table()]) || $refresh) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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

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

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

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

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

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

Loading history...
1604
            $moduleConfig['storage'][$appType] = $storage;
1605
        } else {
1606
            $moduleConfig['storage'] = $storage;
1607
        }
1608 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...
1609
            Config::save('module', $moduleConfig, $classPath[0]);
1610
        } else {
1611
            Config::save('share', $moduleConfig, $classPath[0]);
1612
        }
1613
        return true;
1614
    }
1615
1616
    /**
1617
     * Delete item from data base
1618
     * 
1619
     * @param array $options
1620
     * @return boolean
1621
     */
1622 1
    public function delete($options = []) {
1623 1
        $this->beforeDelete();
1624
1625 1
        if (static::$storage['type'] == 'moduleConfig') {
1626
            return static::deleteFromModuleStorage($options);
1627
        }
1628 1
        if (!empty($this->_params[$this->index()])) {
1629 1
            App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1630 1
            $result = App::$cur->db->delete($this->table());
1631 1
            if ($result) {
1632 1
                $this->afterDelete();
1633 1
                return $result;
1634
            }
1635
        }
1636
        return false;
1637
    }
1638
1639
    /**
1640
     * Delete items from data base
1641
     * 
1642
     * @param array $where
1643
     */
1644 4
    public static function deleteList($where = []) {
1645 4
        if (!empty($where)) {
1646
            static::fixPrefix($where, 'first');
1647
            App::$cur->db->where($where);
1648
        }
1649 4
        App::$cur->db->delete(static::table());
1650 4
    }
1651
1652
    /**
1653
     * After delete trigger
1654
     */
1655 1
    public function afterDelete() {
1656
        
1657 1
    }
1658
1659
    /**
1660
     * find relation for col name
1661
     * 
1662
     * @param string $col
1663
     * @return array|null
1664
     */
1665
    public static function findRelation($col) {
1666
1667
        foreach (static::relations() as $relName => $rel) {
1668
            if ($rel['col'] == $col) {
1669
                return $relName;
1670
            }
1671
        }
1672
        return null;
1673
    }
1674
1675
    /**
1676
     * Set params for model
1677
     * 
1678
     * @param array $params
1679
     */
1680 4
    public function setParams($params) {
1681 4
        static::fixPrefix($params);
1682 4
        $className = get_called_class();
1683 4
        foreach ($params as $paramName => $value) {
1684 2
            $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $paramName);
1685 2
            if (!empty($className::$cols[$shortName])) {
1686 2
                switch ($className::$cols[$shortName]['type']) {
1687 2
                    case 'decimal':
1688
                        $params[$paramName] = (float) $value;
1689
                        break;
1690 2
                    case 'number':
1691 2
                        $params[$paramName] = (int) $value;
1692 2
                        break;
1693 2
                    case 'bool':
1694 1
                        $params[$paramName] = (bool) $value;
1695 1
                        break;
1696 2
                }
1697 2
            }
1698 4
        }
1699 4
        $this->_params = array_merge($this->_params, $params);
1700 4
    }
1701
1702
    /**
1703
     * Return relation
1704
     * 
1705
     * @param string $relName
1706
     * @return array|boolean
1707
     */
1708 4
    public static function getRelation($relName) {
1709 4
        $relations = static::relations();
1710 4
        return !empty($relations[$relName]) ? $relations[$relName] : false;
1711
    }
1712
1713
    /**
1714
     * Load relation
1715
     * 
1716
     * @param string $name
1717
     * @param array $params
1718
     * @return null|array|integer|\Model
1719
     */
1720 4
    public function loadRelation($name, $params = []) {
1721 4
        $relation = static::getRelation($name);
1722 4
        if ($relation) {
1723 2
            if (!isset($relation['type'])) {
1724 2
                $type = 'to';
1725 2
            } else {
1726
                $type = $relation['type'];
1727
            }
1728 2
            $getCol = null;
1729 2
            $getParams = [];
1730
            switch ($type) {
1731 2
                case 'relModel':
1732
                    if (!$this->pk()) {
1733
                        return [];
1734
                    }
1735
                    $fixedCol = $relation['model']::index();
1736
                    $relation['relModel']::fixPrefix($fixedCol);
1737
                    $ids = array_keys($relation['relModel']::getList(['where' => [$this->index(), $this->pk()], 'array' => true, 'key' => $fixedCol]));
1738
                    if (empty($ids)) {
1739
                        if (empty($params['count'])) {
1740
                            return [];
1741
                        } else {
1742
                            return 0;
1743
                        }
1744
                    }
1745
                    $getType = 'getList';
1746
                    $options = [
1747
                        'where' => [$relation['model']::index(), implode(',', $ids), 'IN'],
1748
                        'array' => (!empty($params['array'])) ? true : false,
1749
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1750
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1751
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1752
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1753
                    ];
1754
                    break;
1755 2
                case 'many':
1756
                    if (!$this->{$this->index()}) {
1757
                        return [];
1758
                    }
1759
                    $getType = 'getList';
1760
                    $options = [
1761
                        'join' => (isset($relation['join'])) ? $relation['join'] : null,
1762
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1763
                        'array' => (!empty($params['array'])) ? true : false,
1764
                        'forSelect' => (!empty($params['forSelect'])) ? true : false,
1765
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1766
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1767
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1768
                        'appType' => (isset($params['appType'])) ? $params['appType'] : ((isset($relation['appType'])) ? $relation['appType'] : null),
1769
                        'where' => []
1770
                    ];
1771
                    $options['where'][] = [$relation['col'], $this->{$this->index()}];
1772
                    if (!empty($relation['where'])) {
1773
                        $options['where'] = array_merge($options['where'], [$relation['where']]);
1774
                    }
1775
                    if (!empty($params['where'])) {
1776
                        $options['where'] = array_merge($options['where'], [$params['where']]);
1777
                    }
1778
                    break;
1779 2
                case 'one':
1780
                    $getType = 'get';
1781
                    $options = [$relation['col'], $this->pk()];
1782
                    break;
1783 2
                default:
1784 2
                    if ($this->$relation['col'] === null) {
1785
                        return null;
1786
                    }
1787 2
                    $getType = 'get';
1788 2
                    $options = $this->$relation['col'];
1789 2
                    $getParams['appType'] = $this->appType;
1790 2
            }
1791 2
            if (!empty($params['count'])) {
1792
                if (class_exists($relation['model'])) {
1793
                    return $relation['model']::getCount($options);
1794
                }
1795
                return 0;
1796
            } else {
1797 2
                if (class_exists($relation['model'])) {
1798 2
                    $this->loadedRelations[$name][json_encode($params)] = $relation['model']::$getType($options, $getCol, $getParams);
1799 2
                } else {
1800
                    $this->loadedRelations[$name][json_encode($params)] = [];
1801
                }
1802
            }
1803 2
            return $this->loadedRelations[$name][json_encode($params)];
1804
        }
1805 4
        return null;
1806
    }
1807
1808
    /**
1809
     * Add relation item
1810
     * 
1811
     * @param string $relName
1812
     * @param \Model $objectId
1813
     * @return \Model|boolean
1814
     */
1815
    public function addRelation($relName, $objectId) {
1816
        $relation = $this->getRelation($relName);
1817
        if ($relation) {
1818
            $rel = $relation['relModel']::get([[$relation['model']::index(), $objectId], [$this->index(), $this->pk()]]);
1819
            if (!$rel) {
1820
                $rel = new $relation['relModel']([
1821
                    $relation['model']::index() => $objectId,
1822
                    $this->index() => $this->pk()
1823
                ]);
1824
                $rel->save();
1825
            }
1826
            return $rel;
1827
        }
1828
        return false;
1829
    }
1830
1831
    /**
1832
     * Check user access for form
1833
     * 
1834
     * @param string $formName
1835
     * @return boolean
1836
     */
1837
    public function checkFormAccess($formName) {
1838
        if ($formName == 'manage' && !Users\User::$cur->isAdmin()) {
1839
            return false;
1840
        }
1841
        return true;
1842
    }
1843
1844
    /**
1845
     * Check access for model
1846
     * 
1847
     * @param string $mode
1848
     * @param \Users\User $user
1849
     * @return boolean
1850
     */
1851
    public function checkAccess($mode = 'write', $user = null) {
1852
        if (!$user) {
1853
            $user = \Users\User::$cur;
1854
        }
1855
        return $user->isAdmin();
1856
    }
1857
1858
    /**
1859
     * Param and relation with params getter
1860
     * 
1861
     * @param string $name
1862
     * @param array $params
1863
     * @return \Value|mixed
1864
     */
1865
    public function __call($name, $params) {
1866
        $fixedName = $name;
1867
        static::fixPrefix($fixedName);
1868 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...
1869
            return new Value($this, $fixedName);
1870
        } elseif (isset($this->_params[$name])) {
1871
            return new Value($this, $name);
1872
        }
1873
        return call_user_func_array([$this, 'loadRelation'], array_merge([$name], $params));
1874
    }
1875
1876
    /**
1877
     * Param and relation getter
1878
     * 
1879
     * @param string $name
1880
     * @return mixed
1881
     */
1882 4
    public function __get($name) {
1883 4
        $fixedName = $name;
1884 4
        static::fixPrefix($fixedName);
1885 4
        if (isset($this->_params[$fixedName])) {
1886 4
            return $this->_params[$fixedName];
1887
        }
1888 4
        if (isset($this->loadedRelations[$name][json_encode([])])) {
1889 2
            return $this->loadedRelations[$name][json_encode([])];
1890
        }
1891 4
        return $this->loadRelation($name);
1892
    }
1893
1894
    /**
1895
     * Return model value in object
1896
     * 
1897
     * @param string $name
1898
     * @return \Value|null
1899
     */
1900
    public function value($name) {
1901
        $fixedName = $name;
1902
        static::fixPrefix($fixedName);
1903 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...
1904
            return new Value($this, $fixedName);
1905
        } elseif ($this->_params[$name]) {
1906
            return new Value($this, $name);
1907
        }
1908
        return null;
1909
    }
1910
1911
    /**
1912
     * Return manager filters
1913
     * 
1914
     * @return array
1915
     */
1916
    public static function managerFilters() {
1917
        return [];
1918
    }
1919
1920
    /**
1921
     * Return validators for cols
1922
     * 
1923
     * @return array
1924
     */
1925
    public static function validators() {
1926
        return [];
1927
    }
1928
1929
    /**
1930
     * Return validator by name
1931
     * 
1932
     * @param string $name
1933
     * @return array
1934
     */
1935
    public static function validator($name) {
1936
        $validators = static::validators();
1937
        if (!empty($validators[$name])) {
1938
            return $validators[$name];
1939
        }
1940
        return [];
1941
    }
1942
1943
    public function genViewLink() {
1944
        $className = get_class($this);
1945
        $link = substr($className, 0, strpos($className, '\\'));
1946
        $link .= '/view/';
1947
        $link .= str_replace('\\', '%5C', substr($className, strpos($className, '\\') + 1));
1948
        $link .= "/{$this->id}";
1949
        return $link;
1950
    }
1951
1952
    /**
1953
     * Set handler for model params
1954
     * 
1955
     * @param string $name
1956
     * @param mixed $value
1957
     */
1958 4
    public function __set($name, $value) {
1959 4
        static::fixPrefix($name);
1960 4
        $className = get_called_class();
1961 4
        $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $name);
1962 4
        if (!empty($className::$cols[$shortName])) {
1963 4
            switch ($className::$cols[$shortName]['type']) {
1964 4
                case 'decimal':
1965
                    $value = (float) $value;
1966
                    break;
1967 4
                case 'number':
1968
                    $value = (int) $value;
1969
                    break;
1970 4
                case 'bool':
1971
                    $value = (bool) $value;
1972
                    break;
1973 4
            }
1974 4
        }
1975 4
        if ((isset($this->_params[$name]) && $this->_params[$name] != $value) && !isset($this->_changedParams[$name])) {
1976 3
            $this->_changedParams[$name] = $this->_params[$name];
1977 3
        }
1978
1979 4
        $this->_params[$name] = $value;
1980 4
    }
1981
1982
    /**
1983
     * Isset handler for model params
1984
     * 
1985
     * @param string $name
1986
     * @return boolean
1987
     */
1988
    public function __isset($name) {
1989
        static::fixPrefix($name);
1990
        return isset($this->_params[$name]);
1991
    }
1992
1993
    /**
1994
     * Convert object to string
1995
     * 
1996
     * @return string
1997
     */
1998
    public function __toString() {
1999
        return $this->name();
2000
    }
2001
}