Test Failed
Push — master ( 0e09f4...8b240e )
by Alexey
04:53
created

Model::__toString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Log
5
 *
6
 * @author Alexey Krupskiy <[email protected]>
7
 * @link http://inji.ru/
8
 * @copyright 2015 Alexey Krupskiy
9
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
10
 */
11
class Model {
12
13
    /**
14
     * Object storage type
15
     * 
16
     * @var array 
17
     */
18
    public static $storage = ['type' => 'db'];
19
20
    /**
21
     * Object name
22
     * 
23
     * @var string 
24
     */
25
    public static $objectName = '';
26
27
    /**
28
     * App type for separate data storage
29
     * 
30
     * @var string
31
     */
32
    public $appType = 'app';
33
34
    /**
35
     * Object current params
36
     * 
37
     * @var array
38
     */
39
    public $_params = [];
40
41
    /**
42
     * List of changed params in current instance
43
     * 
44
     * @var array
45
     */
46
    public $_changedParams = [];
47
48
    /**
49
     * Loaded relations
50
     * 
51
     * @var array 
52
     */
53
    public $loadedRelations = [];
54
55
    /**
56
     * Model name where this model uses as category
57
     * 
58
     * @var string
59
     */
60
    public static $treeCategory = '';
61
62
    /**
63
     * Model name who uses as category in this model
64
     * 
65
     * @var string
66
     */
67
    public static $categoryModel = '';
68
69
    /**
70
     * Col labels
71
     * 
72
     * @var array
73
     */
74
    public static $labels = [];
75
76
    /**
77
     * Model forms
78
     * 
79
     * @var array
80
     */
81
    public static $forms = [];
82
83
    /**
84
     * Model cols
85
     * 
86
     * @var array
87
     */
88
    public static $cols = [];
89
90
    /**
91
     * Options group for display inforamtion from model
92
     * 
93
     * @var array
94
     */
95
    public static $view = [];
96
97
    /**
98
     * List of relations need loaded with item
99
     * 
100
     * @var array 
101
     */
102
    public static $needJoin = [];
103
104
    /**
105
     * List of joins who need to laod
106
     * 
107
     * @var array 
108
     */
109
    public static $relJoins = [];
110
111
    /**
112
     * Set params when model create
113
     * 
114
     * @param array $params
115
     */
116 4
    public function __construct($params = []) {
117 4
        $this->setParams($params);
118 4
    }
119
120
    public static $logging = true;
121
122
    /**
123
     * return object name
124
     * 
125
     * @return string
126
     */
127
    public static function objectName() {
128
        return static::$objectName;
129
    }
130
131
    /**
132
     * Retrn col value with col params and relations path
133
     * 
134
     * @param Model $object
135
     * @param string $valuePath
136
     * @param boolean $convert
137
     * @param boolean $manageHref
138
     * @return string
139
     */
140
    public static function getColValue($object, $valuePath, $convert = false, $manageHref = false) {
141
        if (strpos($valuePath, ':')) {
142
            $rel = substr($valuePath, 0, strpos($valuePath, ':'));
143
            $param = substr($valuePath, strpos($valuePath, ':') + 1);
144
            if (!$object->$rel) {
145
                $modelName = get_class($object);
146
                $relations = $modelName::relations();
147
                if (empty($relations[$rel]['type']) || $relations[$rel]['type'] == 'one') {
148
                    return $object->{$relations[$rel]['col']};
149
                }
150
                return 0;
151
            }
152
            if (strpos($valuePath, ':')) {
153
                return self::getColValue($object->$rel, $param, $convert, $manageHref);
154
            } else {
155
                return $convert ? Model::resloveTypeValue($object->$rel, $param, $manageHref) : $object->$rel->$param;
156
            }
157
        } else {
158
            return $convert ? Model::resloveTypeValue($object, $valuePath, $manageHref) : $object->$valuePath;
159
        }
160
    }
161
162
    /**
163
     * Retrun value for view
164
     * 
165
     * @param Model $item
166
     * @param string $colName
167
     * @param boolean $manageHref
168
     * @return string
169
     */
170
    public static function resloveTypeValue($item, $colName, $manageHref = false) {
171
        $modelName = get_class($item);
172
        $colInfo = $modelName::getColInfo($colName);
173
        $type = !empty($colInfo['colParams']['type']) ? $colInfo['colParams']['type'] : 'string';
174
        $value = '';
175
        switch ($type) {
176
            case 'select':
177
                switch ($colInfo['colParams']['source']) {
178
                    case 'model':
179
                        $sourceValue = '';
180
                        if ($item->$colName) {
181
                            $sourceValue = $colInfo['colParams']['model']::get($item->$colName);
182
                        }
183
                        $value = $sourceValue ? $sourceValue->name() : 'Не задано';
184
                        break;
185
                    case 'array':
186
                        $value = !empty($colInfo['colParams']['sourceArray'][$item->$colName]) ? $colInfo['colParams']['sourceArray'][$item->$colName] : 'Не задано';
187
                        if (is_array($value) && $value['text']) {
188
                            $value = $value['text'];
189
                        }
190
                        break;
191
                    case 'bool':
192
                        return $item->$colName ? 'Да' : 'Нет';
193
                    case 'method':
194 View Code Duplication
                        if (!empty($colInfo['colParams']['params'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
195
                            $values = call_user_func_array([App::$cur->$colInfo['colParams']['module'], $colInfo['colParams']['method']], $colInfo['colParams']['params']);
196
                        } else {
197
                            $values = \App::$cur->{$colInfo['colParams']['module']}->$colInfo['colParams']['method']();
198
                        }
199
                        $value = !empty($values[$item->$colName]) ? $values[$item->$colName] : 'Не задано';
200
                        break;
201
                    case 'void':
202
                        if (!empty($modelName::$cols[$colName]['value']['type']) && $modelName::$cols[$colName]['value']['type'] == 'moduleMethod') {
203
                            return \App::$cur->{$modelName::$cols[$colName]['value']['module']}->{$modelName::$cols[$colName]['value']['method']}($item, $colName, $modelName::$cols[$colName]);
204
                        }
205
                        break;
206
                    case 'relation':
207
                        $relations = $colInfo['modelName']::relations();
208
                        $relValue = $relations[$colInfo['colParams']['relation']]['model']::get($item->$colName);
209
                        $relModel = $relations[$colInfo['colParams']['relation']]['model'];
210
                        $relModel = strpos($relModel, '\\') === 0 ? substr($relModel, 1) : $relModel;
211
                        if ($manageHref) {
212
                            $value = $relValue ? "<a href='/admin/" . str_replace('\\', '/view/', $relModel) . "/" . $relValue->pk() . "'>" . $relValue->name() . "</a>" : 'Не задано';
213
                        } else {
214
                            $value = $relValue ? $relValue->name() : 'Не задано';
215
                        }
216
                        break;
217
                }
218
                break;
219
            case 'image':
220
                $file = Files\File::get($item->$colName);
221
                if ($file) {
222
                    $photoId = Tools::randomString();
223
                    $value = '<a href = "' . $file->path . '" id="' . $photoId . '"><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
            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 1
            case 'key':
404
                foreach ($array as $key => $item) {
405 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
                    if (!isset($cols[$key]) && isset($cols[static::colPrefix() . $key])) {
410
                        $array[static::colPrefix() . $key] = $item;
411
                        unset($array[$key]);
412
                        $key = static::colPrefix() . $key;
413
                    }
414
                    if (is_array($array[$key])) {
415
                        static::fixPrefix($array[$key], 'key', $rootModel);
416
                    } else {
417
                        static::checkForJoin($key, $rootModel);
418
                    }
419
                }
420
                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 1
    }
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 4
        $null = ' NULL';
642 4
        if (empty(static::$cols[$colName]['null'])) {
643 4
            $null = ' NOT NULL';
644 4
        }
645
646 4
        $params = false;
647 4
        switch (static::$cols[$colName]['type']) {
648 4
            case 'select':
649 4
                switch (static::$cols[$colName]['source']) {
650 4
                    case 'relation':
651 4
                        $params = 'int(11) UNSIGNED' . $null;
652 4
                        break;
653 1
                    default:
654 1
                        $params = 'varchar(255)' . $null;
655 4
                }
656 4
                break;
657 4
            case 'image':
658 4
            case 'file':
659 1
                $params = 'int(11) UNSIGNED' . $null;
660 1
                break;
661 4
            case 'number':
662
                $params = 'int(11)' . $null;
663
                break;
664 4
            case 'text':
665 4
            case 'email':
666 3
                $params = 'varchar(255)' . $null;
667 3
                break;
668 3
            case 'html':
669 3
            case 'textarea':
670 3
            case 'json':
671 3
            case 'password':
672 3
            case 'dynamicType':
673 3
            case 'map':
674 1
                $params = 'text' . $null;
675 1
                break;
676 3
            case 'bool':
677 1
                $params = 'tinyint(1) UNSIGNED' . $null;
678 1
                break;
679 3
            case 'decimal':
680
                $params = 'decimal(8, 2)' . $null;
681
                break;
682 3
            case 'date':
683 1
                $params = 'date' . $null;
684 1
                break;
685 3
            case 'dateTime':
686 2
                $params = 'timestamp' . $null;
687 2
                break;
688 4
        }
689 4
        return $params;
690
    }
691
692
    /**
693
     * Create new col in data base
694
     * 
695
     * @param string $colName
696
     * @return boolean|integer
697
     */
698 2
    public static function createCol($colName) {
699 2
        $cols = static::cols(true);
700 2
        if (!empty($cols[static::colPrefix() . $colName])) {
701
            return true;
702
        }
703 2
        $params = static::genColParams($colName);
704 2
        if ($params === false) {
705 2
            return false;
706
        }
707
        return App::$cur->db->addCol(static::table(), static::colPrefix() . $colName, $params);
708
    }
709
710 4
    public static function createTable() {
711 4
        if (static::$storage['type'] == 'moduleConfig') {
712
            return true;
713
        }
714 4
        if (!App::$cur->db) {
715
            return false;
716
        }
717
718 4
        $query = App::$cur->db->newQuery();
719 4
        if (!$query) {
720
            return false;
721
        }
722
723 4
        if (!isset($this)) {
724 4
            $tableName = static::table();
725 4
            $colPrefix = static::colPrefix();
726 4
            $indexes = static::indexes();
727 4
        } else {
728
            $tableName = $this->table();
729
            $colPrefix = $this->colPrefix();
730
            $indexes = $this->indexes();
731
        }
732 4
        if (App::$cur->db->tableExist($tableName)) {
733
            return true;
734
        }
735
        $cols = [
736 4
            $colPrefix . 'id' => 'pk'
737 4
        ];
738 4
        $className = get_called_class();
739 4
        if (!empty($className::$cols)) {
740 4
            foreach ($className::$cols as $colName => $colParams) {
741 4
                if ($colName == 'date_create') {
742 4
                    $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
743 4
                    continue;
744
                }
745 4
                $params = $className::genColParams($colName);
746 4
                if ($params) {
747 4
                    $cols[$colPrefix . $colName] = $params;
748 4
                }
749 4
            }
750 4
        }
751 4
        if (empty($cols[$colPrefix . 'date_create'])) {
752 1
            $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
753 1
        }
754 4
        $tableIndexes = [];
755 4
        if ($indexes) {
756 1
            foreach ($indexes as $indexName => $index) {
757 1
                $tableIndexes[] = $index['type'] . ' ' . App::$cur->db->table_prefix . $indexName . ' (' . implode(',', $index['cols']) . ')';
758 1
            }
759 1
        }
760
761 4
        $query->createTable($tableName, $cols, $tableIndexes);
762 4
        return true;
763
    }
764
765
    /**
766
     * Return table name
767
     * 
768
     * @return string
769
     */
770 4
    public static function table() {
771 4
        return strtolower(str_replace('\\', '_', get_called_class()));
772
    }
773
774
    /**
775
     * Return table index col name
776
     * 
777
     * @return string
778
     */
779 4
    public static function index() {
780
781 4
        return static::colPrefix() . 'id';
782
    }
783
784
    /**
785
     * Return col prefix
786
     * 
787
     * @return string
788
     */
789 4
    public static function colPrefix() {
790 4
        $classPath = explode('\\', get_called_class());
791 4
        $classPath = array_slice($classPath, 1);
792 4
        return strtolower(implode('_', $classPath)) . '_';
793
    }
794
795
    /**
796
     * return relations list
797
     * 
798
     * @return string
799
     */
800 1
    public static function relations() {
801 1
        return [];
802
    }
803
804
    /**
805
     * views list
806
     * 
807
     * @return array
808
     */
809
    public static $views = [];
810
811
    /**
812
     * Return name of col with object name
813
     * 
814
     * @return string
815
     */
816
    public static function nameCol() {
817
        return 'name';
818
    }
819
820
    /**
821
     * Return object name
822
     * 
823
     * @return string
824
     */
825
    public function name() {
826
        return $this->{$this->nameCol()} ? $this->{$this->nameCol()} : '№' . $this->pk();
827
    }
828
829
    /**
830
     * Get single object from data base
831
     * 
832
     * @param mixed $param
833
     * @param string $col
834
     * @param array $options
835
     * @return boolean|\Model
836
     */
837 4
    public static function get($param, $col = null, $options = []) {
838 4
        if (static::$storage['type'] == 'moduleConfig') {
839
            return static::getFromModuleStorage($param, $col, $options);
840
        }
841 4
        if (!empty($col)) {
842 4
            static::fixPrefix($col);
843 4
        }
844
845 4
        if (is_array($param)) {
846 1
            static::fixPrefix($param, 'first');
847 1
        }
848 4
        foreach (static::$relJoins as $join) {
849
            App::$cur->db->join($join[0], $join[1]);
850 4
        }
851 4
        static::$relJoins = [];
852 4
        foreach (static::$needJoin as $rel) {
853
            $relations = static::relations();
854
            if (isset($relations[$rel])) {
855
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
856
                switch ($type) {
857
                    case 'to':
858
                        $relCol = $relations[$rel]['col'];
859
                        static::fixPrefix($relCol);
860
                        App::$cur->db->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
861
                        break;
862
                    case 'one':
863
                        $col = $relations[$rel]['col'];
864
                        $relations[$rel]['model']::fixPrefix($col);
865
                        App::$cur->db->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
866
                        break;
867
                }
868
            }
869 4
        }
870 4
        static::$needJoin = [];
871 4
        if (is_array($param)) {
872 1
            App::$cur->db->where($param);
873 1
        } else {
874 4
            if ($col === null) {
875
876 3
                $col = static::index();
877 3
            }
878 4
            if ($param !== null) {
879 4
                $cols = static::cols();
880 4
                if (!isset($cols[$col]) && isset($cols[static::colPrefix() . $col])) {
881
                    $col = static::colPrefix() . $col;
882
                }
883 4
                App::$cur->db->where($col, $param);
884 4
            } else {
885
                return false;
886
            }
887
        }
888 4
        if (!App::$cur->db->where) {
889
            return false;
890
        }
891
        try {
892 4
            $result = App::$cur->db->select(static::table());
893 4
        } catch (PDOException $exc) {
894
            if ($exc->getCode() == '42S02') {
895
                static::createTable();
896
            } else {
897
                throw $exc;
898
            }
899
            $result = App::$cur->db->select(static::table());
900
        }
901 4
        if (!$result) {
902
            return false;
903
        }
904 4
        return $result->fetch(get_called_class());
905
    }
906
907
    /**
908
     * Old method
909
     * 
910
     * @param type $options
911
     * @return Array
912
     */
913
    public static function get_list($options = []) {
914
        $query = App::$cur->db->newQuery();
915
        if (!$query) {
916
            return [];
917
        }
918
        if (!empty($options['where'])) {
919
            $query->where($options['where']);
920
        }
921
        if (!empty($options['cols'])) {
922
            $query->cols = $options['cols'];
923
        }
924
        if (!empty($options['group'])) {
925
            $query->group($options['group']);
926
        }
927
        if (!empty($options['having'])) {
928
            $query->having($options['having']);
929
        }
930
        if (!empty($options['order'])) {
931
            $query->order($options['order']);
932
        }
933
        if (!empty($options['join'])) {
934
            $query->join($options['join']);
935
        }
936
        if (!empty($options['distinct'])) {
937
            $query->distinct = $options['distinct'];
938
        }
939
940
        foreach (static::$relJoins as $join) {
941
            $query->join($join[0], $join[1]);
942
        }
943
        static::$relJoins = [];
944 View Code Duplication
        foreach (static::$needJoin as $rel) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
945
            $relations = static::relations();
946
            if (isset($relations[$rel])) {
947
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
948
                switch ($type) {
949
                    case 'to':
950
                        $relCol = $relations[$rel]['col'];
951
                        static::fixPrefix($relCol);
952
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
953
                        break;
954
                    case 'one':
955
                        $col = $relations[$rel]['col'];
956
                        $relations[$rel]['model']::fixPrefix($col);
957
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
958
                        break;
959
                }
960
            }
961
        }
962
        static::$needJoin = [];
963
964 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...
965
            $limit = (int) $options['limit'];
966
        } else {
967
            $limit = 0;
968
        }
969 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...
970
            $start = (int) $options['start'];
971
        } else {
972
            $start = 0;
973
        }
974
        if ($limit || $start) {
975
            $query->limit($start, $limit);
976
        }
977
        if (isset($options['key'])) {
978
            $key = $options['key'];
979
        } else {
980
            $key = static::index();
981
        }
982
        try {
983
            $query->operation = 'SELECT';
984
            $query->table = static::table();
985
            $queryArr = $query->buildQuery();
986
            $result = $query->query($queryArr);
987
        } catch (PDOException $exc) {
988
            if ($exc->getCode() == '42S02') {
989
                static::createTable();
990
                $result = $query->query($queryArr);
991
            } else {
992
                throw $exc;
993
            }
994
        }
995
996
        if (!empty($options['array'])) {
997
            return $result->getArray($key);
998
        }
999
        $list = $result->getObjects(get_called_class(), $key);
1000 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...
1001
            $return = [];
1002
            foreach ($list as $key => $item) {
1003
                $return[$key] = $item->name();
1004
            }
1005
            return $return;
1006
        }
1007
        return $list;
1008
    }
1009
1010
    /**
1011
     * Return list of objects from data base
1012
     * 
1013
     * @param type $options
1014
     * @return type
1015
     */
1016
    public static function getList($options = []) {
1017
        if (static::$storage['type'] != 'db') {
1018
            return static::getListFromModuleStorage($options);
1019
        }
1020
        if (!empty($options['where'])) {
1021
            static::fixPrefix($options['where'], 'first');
1022
        }
1023
        if (!empty($options['group'])) {
1024
            static::fixPrefix($options['group'], 'first');
1025
        }
1026
        if (!empty($options['order'])) {
1027
            static::fixPrefix($options['order'], 'first');
1028
        }
1029
        if (!empty($options['having'])) {
1030
            static::fixPrefix($options['having'], 'first');
1031
        }
1032
        return static::get_list($options);
1033
    }
1034
1035
    /**
1036
     * Get single item from module storage
1037
     * 
1038
     * @param array $param
1039
     * @param string $col
1040
     * @param array $options
1041
     * @return boolean|\Model
1042
     */
1043
    public static function getFromModuleStorage($param = null, $col = null, $options = []) {
1044
        if ($col === null) {
1045
1046
            $col = static::index();
1047
        }
1048
        if ($param == null) {
1049
            return false;
1050
        }
1051
        $classPath = explode('\\', get_called_class());
1052 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...
1053
            $moduleConfig = Config::share($classPath[0]);
1054
        } else {
1055
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1056
        }
1057
        $appType = App::$cur->type;
1058 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...
1059
            if (!empty($options['appType'])) {
1060
                $appType = $options['appType'];
1061
            }
1062
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1063
        } else {
1064
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1065
        }
1066
        if (!empty($storage[$classPath[1]])) {
1067
            $items = $storage[$classPath[1]];
1068
            $class = get_called_class();
1069
            $where = is_array($param) ? $param : [$col, $param];
1070
            foreach ($items as $key => $item) {
1071
                if (!Model::checkWhere($item, $where)) {
1072
                    continue;
1073
                }
1074
                if (!empty($options['array'])) {
1075
                    return $item;
1076
                }
1077
                $item = new $class($item);
1078
                $item->appType = $appType;
1079
                return $item;
1080
            }
1081
        }
1082
        return false;
1083
    }
1084
1085
    /**
1086
     * Return list items from module storage
1087
     * 
1088
     * @param array $options
1089
     * @return array
1090
     */
1091
    public static function getListFromModuleStorage($options = []) {
1092
        $classPath = explode('\\', get_called_class());
1093 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1094
            $moduleConfig = Config::share($classPath[0]);
1095
        } else {
1096
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1097
        }
1098 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...
1099
            if (empty($options['appType'])) {
1100
                $appType = App::$cur->type;
1101
            } else {
1102
                $appType = $options['appType'];
1103
            }
1104
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1105
        } else {
1106
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1107
        }
1108
        if (!empty($storage[$classPath[1]])) {
1109
            $items = [];
1110
            $class = get_called_class();
1111
            if (isset($options['key'])) {
1112
                $arrayKey = $options['key'];
1113
            } else {
1114
                $arrayKey = static::index();
1115
            }
1116
            foreach ($storage[$classPath[1]] as $key => $item) {
1117
                if (!empty($options['where']) && !Model::checkWhere($item, $options['where'])) {
1118
                    continue;
1119
                }
1120
                $items[$item[$arrayKey]] = new $class($item);
1121
            }
1122
            if (!empty($options['order'])) {
1123
                usort($items, function($a, $b) use($options) {
1124
                    if ($a->{$options['order'][0]} > $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1125
                        return 1;
1126
                    } elseif ($a->{$options['order'][0]} < $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1127
                        return -1;
1128
                    }
1129
                    return 0;
1130
                });
1131
            }
1132 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...
1133
                $return = [];
1134
                foreach ($items as $key => $item) {
1135
                    $return[$key] = $item->name();
1136
                }
1137
                return $return;
1138
            }
1139
            return $items;
1140
        }
1141
        return [];
1142
    }
1143
1144
    /**
1145
     * Return count of records from module storage
1146
     * 
1147
     * @param array $options
1148
     * @return int
1149
     */
1150
    public static function getCountFromModuleStorage($options = []) {
1151
1152
        $classPath = explode('\\', get_called_class());
1153
        $count = 0;
1154
        if (empty($options['appType'])) {
1155
            $appType = App::$cur->type;
1156
        } else {
1157
            $appType = $options['appType'];
1158
        }
1159 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...
1160
            $moduleConfig = Config::share($classPath[0]);
1161
        } else {
1162
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1163
        }
1164
        if (!empty($moduleConfig['storage'][$appType][$classPath[1]])) {
1165
            $items = $moduleConfig['storage'][$appType][$classPath[1]];
1166
            if (empty($options['where'])) {
1167
                return count($items);
1168
            }
1169
            foreach ($items as $key => $item) {
1170
                if (!empty($options['where'])) {
1171
                    if (Model::checkWhere($item, $options['where'])) {
1172
                        $count++;
1173
                    }
1174
                } else {
1175
                    $count++;
1176
                }
1177
            }
1178
        }
1179
        return $count;
1180
    }
1181
1182
    /**
1183
     * Check where for module storage query
1184
     * 
1185
     * @param array $item
1186
     * @param array|string $where
1187
     * @param string $value
1188
     * @param string $operation
1189
     * @param string $concatenation
1190
     * @return boolean
1191
     */
1192
    public static function checkWhere($item = [], $where = '', $value = '', $operation = '=', $concatenation = 'AND') {
1193
1194
        if (is_array($where)) {
1195
            if (is_array($where[0])) {
1196
                $result = true;
1197
                foreach ($where as $key => $whereItem) {
1198
                    $concatenation = empty($whereItem[3]) ? 'AND' : strtoupper($whereItem[3]);
1199
                    switch ($concatenation) {
1200 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...
1201
                            $result = $result && forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1202
                            break;
1203 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...
1204
                            $result = $result || forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1205
                            break;
1206
                    }
1207
                }
1208
1209
                return $result;
1210
            } else {
1211
                return forward_static_call_array(['Model', 'checkWhere'], array_merge([$item], $where));
1212
            }
1213
        }
1214
        if (!isset($item[$where]) && !$value) {
1215
            return true;
1216
        }
1217
        if (!isset($item[$where]) && $value) {
1218
            return false;
1219
        }
1220
        if ($item[$where] == $value) {
1221
            return true;
1222
        }
1223
        return false;
1224
    }
1225
1226
    /**
1227
     * Return count of records from data base
1228
     * 
1229
     * @param array $options
1230
     * @return array|int
1231
     */
1232
    public static function getCount($options = []) {
1233
        if (static::$storage['type'] == 'moduleConfig') {
1234
            return static::getCountFromModuleStorage($options);
1235
        }
1236
        $query = App::$cur->db->newQuery();
1237
        if (!$query) {
1238
            return 0;
1239
        }
1240
        if (!empty($options['where'])) {
1241
            static::fixPrefix($options['where'], 'first');
1242
        }
1243
        if (!empty($options['group'])) {
1244
            static::fixPrefix($options['group'], 'first');
1245
        }
1246
        if (!empty($options['order'])) {
1247
            static::fixPrefix($options['order'], 'first');
1248
        }
1249
        if (!empty($options['where'])) {
1250
            $query->where($options['where']);
1251
        }
1252
        if (!empty($options['join'])) {
1253
            $query->join($options['join']);
1254
        }
1255
        if (!empty($options['order'])) {
1256
            $query->order($options['order']);
1257
        }
1258 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...
1259
            $limit = (int) $options['limit'];
1260
        } else {
1261
            $limit = 0;
1262
        }
1263 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...
1264
            $start = (int) $options['start'];
1265
        } else {
1266
            $start = 0;
1267
        }
1268
        if ($limit || $start) {
1269
            $query->limit($start, $limit);
1270
        }
1271
1272
        foreach (static::$relJoins as $join) {
1273
            $query->join($join[0], $join[1]);
1274
        }
1275
        static::$relJoins = [];
1276 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...
1277
            $relations = static::relations();
1278
            if (isset($relations[$rel])) {
1279
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
1280
                switch ($type) {
1281
                    case 'to':
1282
                        $relCol = $relations[$rel]['col'];
1283
                        static::fixPrefix($relCol);
1284
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
1285
                        break;
1286
                    case 'one':
1287
                        $col = $relations[$rel]['col'];
1288
                        $relations[$rel]['model']::fixPrefix($col);
1289
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
1290
                        break;
1291
                }
1292
            }
1293
        }
1294
        static::$needJoin = [];
1295
        $cols = 'COUNT(';
1296
1297
        if (!empty($options['distinct'])) {
1298
            if (is_bool($options['distinct'])) {
1299
                $cols .= 'DISTINCT *';
1300
            } else {
1301
                $cols .= "DISTINCT {$options['distinct']}";
1302
            }
1303
        } else {
1304
            $cols .= '*';
1305
        }
1306
        $cols .=') as `count`' . (!empty($options['cols']) ? ',' . $options['cols'] : '');
1307
        $query->cols = $cols;
1308
        if (!empty($options['group'])) {
1309
            $query->group($options['group']);
1310
        }
1311
        try {
1312
            $result = $query->select(static::table());
1313
        } catch (PDOException $exc) {
1314
            if ($exc->getCode() == '42S02') {
1315
                static::createTable();
1316
            } else {
1317
                throw $exc;
1318
            }
1319
            $result = $query->select(static::table());
1320
        }
1321
        if (!empty($options['group'])) {
1322
            $count = $result->getArray();
1323
            return $count;
1324
        } else {
1325
            $count = $result->fetch();
1326
            return $count['count'];
1327
        }
1328
    }
1329
1330
    /**
1331
     * Update records in data base
1332
     * 
1333
     * @param array $params
1334
     * @param array $where
1335
     * @return false|null
1336
     */
1337
    public static function update($params, $where = []) {
1338
        static::fixPrefix($params);
1339
1340
        $cols = self::cols();
1341
1342
        $values = [];
1343
        foreach ($cols as $col => $param) {
1344
            if (isset($params[$col])) {
1345
                $values[$col] = $params[$col];
1346
            }
1347
        }
1348
        if (empty($values)) {
1349
            return false;
1350
        }
1351
1352
        if (!empty($where)) {
1353
            static::fixPrefix($where, 'first');
1354
1355
            App::$cur->db->where($where);
1356
        }
1357
        App::$cur->db->update(static::table(), $values);
1358
    }
1359
1360
    /**
1361
     * Return primary key of object
1362
     * 
1363
     * @return mixed
1364
     */
1365 4
    public function pk() {
1366 4
        return $this->{$this->index()};
1367
    }
1368
1369
    /**
1370
     * Before save trigger
1371
     */
1372 4
    public function beforeSave() {
1373
        
1374 4
    }
1375
1376
    /**
1377
     * Save object to module storage
1378
     * 
1379
     * @param array $options
1380
     * @return boolean
1381
     */
1382 1
    public function saveModuleStorage($options) {
1383
1384 1
        $col = static::index();
1385 1
        $id = $this->pk();
1386 1
        $appType = '';
1387 1
        $classPath = explode('\\', get_called_class());
1388
1389 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...
1390
            $moduleConfig = Config::share($classPath[0]);
1391
        } else {
1392 1
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1393
        }
1394
1395 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...
1396 1
            if (empty($options['appType'])) {
1397
                $appType = App::$cur->type;
1398
            } else {
1399 1
                $appType = $options['appType'];
1400
            }
1401 1
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1402 1
        } else {
1403
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1404
        }
1405 1
        if (empty($storage[$classPath[1]])) {
1406
            $storage[$classPath[1]] = [];
1407
        }
1408 1
        if ($id) {
1409 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...
1410
                if ($item[$col] == $id) {
1411
                    $storage[$classPath[1]][$key] = $this->_params;
1412
                    break;
1413
                }
1414
            }
1415
        } else {
1416 1
            $id = !empty($storage['scheme'][$classPath[1]]['ai']) ? $storage['scheme'][$classPath[1]]['ai'] : 1;
1417 1
            $this->$col = $id;
1418 1
            $storage['scheme'][$classPath[1]]['ai'] = $id + 1;
1419 1
            $storage[$classPath[1]][] = $this->_params;
1420
        }
1421 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...
1422 1
            $moduleConfig['storage'][$appType] = $storage;
1423 1
        } else {
1424
            $moduleConfig['storage'] = $storage;
1425
        }
1426 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...
1427 1
            Config::save('module', $moduleConfig, $classPath[0]);
1428 1
        } else {
1429
            Config::save('share', $moduleConfig, $classPath[0]);
1430
        }
1431 1
        return true;
1432
    }
1433
1434
    /**
1435
     * Update tree path category
1436
     */
1437
    public function changeCategoryTree() {
1438
        $class = get_class($this);
1439
        $itemModel = $class::$treeCategory;
1440
        $oldPath = $this->tree_path;
1441
        $this->tree_path = $this->getCatalogTree($this);
1442
        $itemsTable = \App::$cur->db->table_prefix . $itemModel::table();
1443
        $itemTreeCol = $itemModel::colPrefix() . 'tree_path';
1444
1445
        $categoryTreeCol = $this->colPrefix() . 'tree_path';
1446
        $categoryTable = \App::$cur->db->table_prefix . $this->table();
1447
        if ($oldPath) {
1448
            \App::$cur->db->query('UPDATE
1449
                ' . $categoryTable . ' 
1450
                    SET 
1451
                        ' . $categoryTreeCol . ' = REPLACE(' . $categoryTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1452
                    WHERE ' . $categoryTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1453
1454
            \App::$cur->db->query('UPDATE
1455
                ' . $itemsTable . '
1456
                    SET 
1457
                        ' . $itemTreeCol . ' = REPLACE(' . $itemTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1458
                    WHERE ' . $itemTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1459
        }
1460
        $itemModel::update([$itemTreeCol => $this->tree_path . $this->id . '/'], [$itemModel::colPrefix() . $this->index(), $this->id]);
1461
    }
1462
1463
    /**
1464
     * Return tree path
1465
     * 
1466
     * @param \Model $catalog
1467
     * @return string
1468
     */
1469
    public function getCatalogTree($catalog) {
1470
        $catalogClass = get_class($catalog);
1471
        $catalogParent = $catalogClass::get($catalog->parent_id);
1472
        if ($catalog && $catalogParent) {
1473
            if ($catalogParent->tree_path) {
1474
                return $catalogParent->tree_path . $catalogParent->id . '/';
1475
            } else {
1476
                return $this->getCatalogTree($catalogParent) . $catalogParent->id . '/';
1477
            }
1478
        }
1479
        return '/';
1480
    }
1481
1482
    /**
1483
     * Update tree path item
1484
     */
1485
    public function changeItemTree() {
1486
        $class = get_class($this);
1487
        $categoryModel = $class::$categoryModel;
1488
        $category = $categoryModel::get($this->{$categoryModel::index()});
1489
        if ($category) {
1490
            $this->tree_path = $category->tree_path . $category->pk() . '/';
1491
        } else {
1492
            $this->tree_path = '/';
1493
        }
1494
    }
1495
1496
    /**
1497
     * Save object to data base
1498
     * 
1499
     * @param array $options
1500
     * @return boolean|int
1501
     */
1502 4
    public function save($options = []) {
1503
1504 4
        if (static::$storage['type'] == 'moduleConfig') {
1505 1
            return static::saveModuleStorage($options);
1506
        }
1507 4
        $class = get_class($this);
1508 4
        if ($class::$categoryModel) {
1509
            $this->changeItemTree();
1510
        }
1511 4
        if ($class::$treeCategory) {
1512
            $this->changeCategoryTree();
1513
        }
1514 4
        if (!empty($this->_changedParams) && $this->pk()) {
1515 3
            Inji::$inst->event('modelItemParamsChanged-' . get_called_class(), $this);
1516 3
        }
1517 4
        $this->beforeSave();
1518 4
        $values = [];
1519
1520 4
        foreach ($this->cols() as $col => $param) {
1521 4
            if (in_array($col, array_keys($this->_params))) {
1522 4
                $values[$col] = $this->_params[$col];
1523 4
            }
1524 4
        }
1525 4
        foreach ($class::$cols as $colName => $params) {
1526 4
            $class::fixPrefix($colName);
1527 4
            if (isset($params['default']) && !isset($values[$colName])) {
1528
                $this->_params[$colName] = $values[$colName] = $params['default'];
1529
            }
1530 4
        }
1531
1532 4
        if (empty($values) && empty($options['empty'])) {
1533
            return false;
1534
        }
1535
1536 4
        if ($this->pk()) {
1537 3
            $new = false;
1538 3
            if ($this->get($this->_params[$this->index()])) {
1539 3
                App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1540 3
                App::$cur->db->update($this->table(), $values);
1541 3
            } else {
1542
1543
                $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1544
            }
1545 3
        } else {
1546 4
            $new = true;
1547 4
            $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1548
        }
1549 4
        $this->logChanges($new);
1550 4
        App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1551
        try {
1552 4
            $result = App::$cur->db->select($this->table());
1553 4
        } catch (PDOException $exc) {
1554
            if ($exc->getCode() == '42S02') {
1555
                $this->createTable();
1556
            }
1557
            $result = App::$cur->db->select($this->table());
1558
        }
1559 4
        $this->_params = $result->fetch();
1560 4
        if ($new) {
1561 4
            Inji::$inst->event('modelCreatedItem-' . get_called_class(), $this);
1562 4
        }
1563 4
        $this->afterSave();
1564 4
        return $this->{$this->index()};
1565
    }
1566
1567
    /**
1568
     * After save trigger
1569
     */
1570 4
    public function afterSave() {
1571
        
1572 4
    }
1573
1574
    /**
1575
     * Before delete trigger
1576
     */
1577 1
    public function beforeDelete() {
1578
        
1579 1
    }
1580
1581
    /**
1582
     * Delete item from module storage
1583
     * 
1584
     * @param array $options
1585
     * @return boolean
1586
     */
1587
    public function deleteFromModuleStorage($options) {
1588
1589
        $col = static::index();
1590
        $id = $this->pk();
1591
        $appType = '';
1592
        $classPath = explode('\\', get_called_class());
1593 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...
1594
            $moduleConfig = Config::share($classPath[0]);
1595
        } else {
1596
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1597
        }
1598
1599 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...
1600
            if (empty($options['appType'])) {
1601
                $appType = App::$cur->type;
1602
            } else {
1603
                $appType = $options['appType'];
1604
            }
1605
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1606
        } else {
1607
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1608
        }
1609
        if (empty($storage[$classPath[1]])) {
1610
            $storage[$classPath[1]] = [];
1611
        }
1612 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...
1613
1614
            if ($item[$col] == $id) {
1615
                unset($storage[$classPath[1]][$key]);
1616
                break;
1617
            }
1618
        }
1619 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...
1620
            $moduleConfig['storage'][$appType] = $storage;
1621
        } else {
1622
            $moduleConfig['storage'] = $storage;
1623
        }
1624 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...
1625
            Config::save('module', $moduleConfig, $classPath[0]);
1626
        } else {
1627
            Config::save('share', $moduleConfig, $classPath[0]);
1628
        }
1629
        return true;
1630
    }
1631
1632
    /**
1633
     * Delete item from data base
1634
     * 
1635
     * @param array $options
1636
     * @return boolean
1637
     */
1638 1
    public function delete($options = []) {
1639 1
        $this->beforeDelete();
1640
1641 1
        if (static::$storage['type'] == 'moduleConfig') {
1642
            return static::deleteFromModuleStorage($options);
1643
        }
1644 1
        if (!empty($this->_params[$this->index()])) {
1645 1
            App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1646 1
            $result = App::$cur->db->delete($this->table());
1647 1
            if ($result) {
1648 1
                $this->afterDelete();
1649 1
                return $result;
1650
            }
1651
        }
1652
        return false;
1653
    }
1654
1655
    /**
1656
     * Delete items from data base
1657
     * 
1658
     * @param array $where
1659
     */
1660 4
    public static function deleteList($where = []) {
1661 4
        if (!empty($where)) {
1662
            static::fixPrefix($where, 'first');
1663
            App::$cur->db->where($where);
1664
        }
1665 4
        App::$cur->db->delete(static::table());
1666 4
    }
1667
1668
    /**
1669
     * After delete trigger
1670
     */
1671 1
    public function afterDelete() {
1672
        
1673 1
    }
1674
1675
    /**
1676
     * find relation for col name
1677
     * 
1678
     * @param string $col
1679
     * @return array|null
1680
     */
1681
    public static function findRelation($col) {
1682
1683
        foreach (static::relations() as $relName => $rel) {
1684
            if ($rel['col'] == $col) {
1685
                return $relName;
1686
            }
1687
        }
1688
        return null;
1689
    }
1690
1691
    /**
1692
     * Set params for model
1693
     * 
1694
     * @param array $params
1695
     */
1696 4
    public function setParams($params) {
1697 4
        foreach ($params as $paramName => $value) {
1698 2
            $this->$paramName = $value;
1699 4
        }
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
    public function extract($model) {
1953
        $params = [];
1954
        $indexes = array_keys($this->_params);
1955
        foreach ($model::$cols as $colName => $colParams) {
1956
            if (in_array($model::colPrefix() . $colName, $indexes)) {
1957
                $params[$model::colPrefix() . $colName] = $this->_params[$model::colPrefix() . $colName];
1958 4
            }
1959 4
        }
1960 4
        if (!$params) {
1961 4
            return FALSE;
1962 4
        }
1963
        return new $model($params);
1964
    }
1965 4
1966 2
    /**
1967 2
     * Set handler for model params
1968 4
     * 
1969 4
     * @param string $name
1970 4
     * @param mixed $value
1971
     */
1972
    public function __set($name, $value) {
1973 4
        static::fixPrefix($name);
1974 2
        $className = get_called_class();
1975 2
        $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $name);
1976 4
        if (!$value && !empty(static::$cols[$shortName]) && in_array('emptyValue', array_keys(static::$cols[$shortName]))) {
1977 1
            $value = static::$cols[$shortName]['emptyValue'];
1978 1
        }
1979 4
        if (is_null($value) && empty(static::$cols[$shortName]['null'])) {
1980 4
            $value = '';
1981 4
        }
1982 4
        if (!empty($className::$cols[$shortName])) {
1983 3
            switch ($className::$cols[$shortName]['type']) {
1984 3
                case 'decimal':
1985 4
                    $value = (float) $value;
1986 4
                    break;
1987
                case 'number':
1988
                    $value = (int) $value;
1989
                    break;
1990
                case 'bool':
1991
                    $value = (bool) $value;
1992
                    break;
1993
            }
1994
        }
1995 View Code Duplication
        if (in_array($name, array_keys($this->_params)) && $this->_params[$name] != $value && !in_array($name, array_keys($this->_changedParams))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1996
            $this->_changedParams[$name] = $this->_params[$name];
1997
        }
1998
        $this->_params[$name] = $value;
1999 View Code Duplication
        if (in_array($name, array_keys($this->_params)) && in_array($name, array_keys($this->_changedParams)) && $this->_changedParams[$name] == $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2000
            unset($this->_changedParams[$name]);
2001
        }
2002
    }
2003
2004
    /**
2005
     * Isset handler for model params
2006
     * 
2007
     * @param string $name
2008
     * @return boolean
2009
     */
2010
    public function __isset($name) {
2011
        static::fixPrefix($name);
2012
        return isset($this->_params[$name]);
2013
    }
2014
2015
    /**
2016
     * Convert object to string
2017
     * 
2018
     * @return string
2019
     */
2020
    public function __toString() {
2021
        return $this->name();
2022
    }
2023
}