Passed
Push — master ( edbfbd...89a048 )
by Alexey
05:17
created

Model::createTable()   C

Complexity

Conditions 13
Paths 21

Size

Total Lines 54
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 13.7292

Importance

Changes 0
Metric Value
cc 13
eloc 37
nc 21
nop 0
dl 0
loc 54
ccs 36
cts 43
cp 0.8372
crap 13.7292
rs 6.7593
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Log
5
 *
6
 * @author Alexey Krupskiy <[email protected]>
7
 * @link http://inji.ru/
8
 * @copyright 2015 Alexey Krupskiy
9
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
10
 */
11
class Model {
12
13
    /**
14
     * Object storage type
15
     * 
16
     * @var array 
17
     */
18
    public static $storage = ['type' => 'db'];
19
20
    /**
21
     * Object name
22
     * 
23
     * @var string 
24
     */
25
    public static $objectName = '';
26
27
    /**
28
     * App type for separate data storage
29
     * 
30
     * @var string
31
     */
32
    public $appType = 'app';
33
34
    /**
35
     * Object current params
36
     * 
37
     * @var array
38
     */
39
    public $_params = [];
40
41
    /**
42
     * List of changed params in current instance
43
     * 
44
     * @var array
45
     */
46
    public $_changedParams = [];
47
48
    /**
49
     * Loaded relations
50
     * 
51
     * @var array 
52
     */
53
    public $loadedRelations = [];
54
55
    /**
56
     * Model name where this model uses as category
57
     * 
58
     * @var string
59
     */
60
    public static $treeCategory = '';
61
62
    /**
63
     * Model name who uses as category in this model
64
     * 
65
     * @var string
66
     */
67
    public static $categoryModel = '';
68
69
    /**
70
     * Col labels
71
     * 
72
     * @var array
73
     */
74
    public static $labels = [];
75
76
    /**
77
     * Model forms
78
     * 
79
     * @var array
80
     */
81
    public static $forms = [];
82
83
    /**
84
     * Model cols
85
     * 
86
     * @var array
87
     */
88
    public static $cols = [];
89
90
    /**
91
     * Options group for display inforamtion from model
92
     * 
93
     * @var array
94
     */
95
    public static $view = [];
96
97
    /**
98
     * List of relations need loaded with item
99
     * 
100
     * @var array 
101
     */
102
    public static $needJoin = [];
103
104
    /**
105
     * List of joins who need to laod
106
     * 
107
     * @var array 
108
     */
109
    public static $relJoins = [];
110
111
    /**
112
     * Set params when model create
113
     * 
114
     * @param array $params
115
     */
116 4
    public function __construct($params = []) {
117 4
        $this->setParams($params);
118 4
    }
119
120
    public static $logging = true;
121
122
    /**
123
     * return object name
124
     * 
125
     * @return string
126
     */
127
    public static function objectName() {
128
        return static::$objectName;
129
    }
130
131
    /**
132
     * Retrn col value with col params and relations path
133
     * 
134
     * @param Model $object
135
     * @param string $valuePath
136
     * @param boolean $convert
137
     * @param boolean $manageHref
138
     * @return string
139
     */
140
    public static function getColValue($object, $valuePath, $convert = false, $manageHref = false) {
141
        if (strpos($valuePath, ':')) {
142
            $rel = substr($valuePath, 0, strpos($valuePath, ':'));
143
            $param = substr($valuePath, strpos($valuePath, ':') + 1);
144
            if (!$object->$rel) {
145
                $modelName = get_class($object);
146
                $relations = $modelName::relations();
147
                if (empty($relations[$rel]['type']) || $relations[$rel]['type'] == 'one') {
148
                    return $object->{$relations[$rel]['col']};
149
                }
150
                return 0;
151
            }
152
            if (strpos($valuePath, ':')) {
153
                return self::getColValue($object->$rel, $param, $convert, $manageHref);
154
            } else {
155
                return $convert ? Model::resloveTypeValue($object->$rel, $param, $manageHref) : $object->$rel->$param;
156
            }
157
        } else {
158
            return $convert ? Model::resloveTypeValue($object, $valuePath, $manageHref) : $object->$valuePath;
159
        }
160
    }
161
162
    /**
163
     * Retrun value for view
164
     * 
165
     * @param Model $item
166
     * @param string $colName
167
     * @param boolean $manageHref
168
     * @return string
169
     */
170
    public static function resloveTypeValue($item, $colName, $manageHref = false) {
171
        $modelName = get_class($item);
172
        $colInfo = $modelName::getColInfo($colName);
173
        $type = !empty($colInfo['colParams']['type']) ? $colInfo['colParams']['type'] : 'string';
174
        $value = '';
175
        switch ($type) {
176
            case 'select':
177
                switch ($colInfo['colParams']['source']) {
178
                    case 'model':
179
                        $sourceValue = '';
180
                        if ($item->$colName) {
181
                            $sourceValue = $colInfo['colParams']['model']::get($item->$colName);
182
                        }
183
                        $value = $sourceValue ? $sourceValue->name() : 'Не задано';
184
                        break;
185
                    case 'array':
186
                        $value = !empty($colInfo['colParams']['sourceArray'][$item->$colName]) ? $colInfo['colParams']['sourceArray'][$item->$colName] : 'Не задано';
187
                        if (is_array($value) && $value['text']) {
188
                            $value = $value['text'];
189
                        }
190
                        break;
191
                    case 'bool':
192
                        return $item->$colName ? 'Да' : 'Нет';
193
                    case 'method':
194
                        if (!empty($colInfo['colParams']['params'])) {
195
                            $values = call_user_func_array([App::$cur->$colInfo['colParams']['module'], $colInfo['colParams']['method']], $colInfo['colParams']['params']);
196
                        } else {
197
                            $values = $colInfo['colParams']['module']->$colInfo['colParams']['method']();
198
                        }
199
                        $value = !empty($values[$item->$colName]) ? $values[$item->$colName] : 'Не задано';
200
                        break;
201
                    case 'void':
202
                        if (!empty($modelName::$cols[$colName]['value']['type']) && $modelName::$cols[$colName]['value']['type'] == 'moduleMethod') {
203
                            return \App::$cur->{$modelName::$cols[$colName]['value']['module']}->{$modelName::$cols[$colName]['value']['method']}($item, $colName, $modelName::$cols[$colName]);
204
                        }
205
                        break;
206
                    case 'relation':
207
                        $relations = $colInfo['modelName']::relations();
208
                        $relValue = $relations[$colInfo['colParams']['relation']]['model']::get($item->$colName);
209
                        $relModel = $relations[$colInfo['colParams']['relation']]['model'];
210
                        $relModel = strpos($relModel, '\\') === 0 ? substr($relModel, 1) : $relModel;
211
                        if ($manageHref) {
212
                            $value = $relValue ? "<a href='/admin/" . str_replace('\\', '/view/', $relModel) . "/" . $relValue->pk() . "'>" . $relValue->name() . "</a>" : 'Не задано';
213
                        } else {
214
                            $value = $relValue ? $relValue->name() : 'Не задано';
215
                        }
216
                        break;
217
                }
218
                break;
219
            case 'image':
220
                $file = Files\File::get($item->$colName);
221
                if ($file) {
222
                    $value = '<img src="' . $file->path . '?resize=60x120" />';
223
                } else {
224
                    $value = '<img src="/static/system/images/no-image.png?resize=60x120" />';
225
                }
226
                break;
227
            case 'file':
228
                $file = Files\File::get($item->$colName);
229
                if ($file) {
230
                    $value = '<a href="' . $file->path . '">' . $file->name . '.' . $file->type->ext . '</a>';
231
                } else {
232
                    $value = 'Файл не загружен';
233
                }
234
                break;
235
            case 'bool':
236
                $value = $item->$colName ? 'Да' : 'Нет';
237
                break;
238
            case 'void':
239
                if (!empty($colInfo['colParams']['value']['type']) && $colInfo['colParams']['value']['type'] == 'moduleMethod') {
240
                    return \App::$cur->{$colInfo['colParams']['value']['module']}->{$colInfo['colParams']['value']['method']}($item, $colName, $colInfo['colParams']);
241
                }
242
                break;
243 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...
244
                if ($item->$colName && json_decode($item->$colName, true)) {
245
                    $addres = json_decode($item->$colName, true);
246
                    $name = $addres['address'] ? $addres['address'] : 'lat:' . $addres['lat'] . ': lng:' . $addres['lng'];
247
                    \App::$cur->libs->loadLib('yandexMap');
248
                    ob_start();
249
                    $uid = Tools::randomString();
250
                    ?>
251
                    <div id='map<?= $uid; ?>_container' style="display:none;"><script>/*
252
                     <div id='map<?= $uid; ?>' style="width: 100%; height: 500px"></div>
253
                     <script>
254
                     var myMap<?= $uid; ?>;
255
                     var myMap<?= $uid; ?>CurPin;
256
                     inji.onLoad(function () {
257
                     ymaps.ready(init<?= $uid; ?>);
258
                     function init<?= $uid; ?>() {
259
                     var myPlacemark;
260
                     myMap<?= $uid; ?> = new ymaps.Map("map<?= $uid; ?>", {
261
                     center: ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"],
262
                     zoom: 13
263
                     });
264
                     myCoords = ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"];
265
                     myMap<?= $uid; ?>CurPin = new ymaps.Placemark(myCoords,
266
                     {iconContent: "<?= $addres['address']; ?>"},
267
                     {preset: 'islands#greenStretchyIcon'}
268
                     );
269
                     myMap<?= $uid; ?>.geoObjects.add(myMap<?= $uid; ?>CurPin, 0);
270
                     }
271
                     window['init<?= $uid; ?>'] = init<?= $uid; ?>;
272
                     });
273
                     */</script>
274
                    </div>
275
                    <?php
276
                    $content = ob_get_contents();
277
                    ob_end_clean();
278
                    $onclick = 'inji.Ui.modals.show("' . addcslashes($addres['address'], '"') . '", $("#map' . $uid . '_container script").html().replace(/^\/\*/g, "").replace(/\*\/$/g, "")+"</script>","mapmodal' . $uid . '","modal-lg");';
279
                    $onclick .= 'return false;';
280
                    $value = "<a href ='#' onclick='{$onclick}' >{$name}</a>";
281
                    $value .= $content;
282
                } else {
283
                    $value = 'Местоположение не заданно';
284
                }
285
286
                break;
287
            case 'dynamicType':
288
                switch ($colInfo['colParams']['typeSource']) {
289
                    case'selfMethod':
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
290
                        $type = $item->{$colInfo['colParams']['selfMethod']}();
291
                        if (is_array($type)) {
292 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...
293
                                $relationPath = explode(':', $type['relation']);
294
                                $relationName = array_pop($relationPath);
295
                                $curItem = $item;
296
                                foreach ($relationPath as $path) {
297
                                    $curItem = $curItem->$path;
298
                                }
299
                                $itemModel = get_class($curItem);
300
                                $relation = $itemModel::getRelation($relationName);
301
                                $sourceModel = $relation['model'];
302
                            } else {
303
                                $relation = static::getRelation($type['relation']);
304
                                $sourceModel = $relation['model'];
305
                            }
306
                            $value = $sourceModel::get($item->$colName);
307
                            if ($value) {
308
                                $value = $value->name();
309
                            } else {
310
                                $value = $item->$colName;
311
                            }
312
                        } else {
313
                            switch ($type) {
314 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...
315
                                    if ($item->$colName && json_decode($item->$colName, true)) {
316
                                        $addres = json_decode($item->$colName, true);
317
                                        $name = $addres['address'] ? $addres['address'] : 'lat:' . $addres['lat'] . ': lng:' . $addres['lng'];
318
                                        \App::$cur->libs->loadLib('yandexMap');
319
                                        ob_start();
320
                                        $uid = Tools::randomString();
321
                                        ?>
322
                                        <div id='map<?= $uid; ?>_container' style="display:none;"><script>/*
323
                                                                                 <div id='map<?= $uid; ?>' style="width: 100%; height: 500px"></div>
324
                                                                                 <script>
325
                                                                                 var myMap<?= $uid; ?>;
326
                                                                                 var myMap<?= $uid; ?>CurPin;
327
                                                                                 inji.onLoad(function () {
328
                                                                                 ymaps.ready(init<?= $uid; ?>);
329
                                                                                 function init<?= $uid; ?>() {
330
                                                                                 var myPlacemark;
331
                                                                                 myMap<?= $uid; ?> = new ymaps.Map("map<?= $uid; ?>", {
332
                                                                                 center: ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"],
333
                                                                                 zoom: 13
334
                                                                                 });
335
                                                                                 myCoords = ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"];
336
                                                                                 myMap<?= $uid; ?>CurPin = new ymaps.Placemark(myCoords,
337
                                                                                 {iconContent: "<?= $addres['address']; ?>"},
338
                                                                                 {preset: 'islands#greenStretchyIcon'}
339
                                                                                 );
340
                                                                                 myMap<?= $uid; ?>.geoObjects.add(myMap<?= $uid; ?>CurPin, 0);
341
                                                                                 }
342
                                                                                 window['init<?= $uid; ?>'] = init<?= $uid; ?>;
343
                                                                                 });
344
                                                                                 */</script>
345
                                        </div>
346
                                        <?php
347
                                        $content = ob_get_contents();
348
                                        ob_end_clean();
349
                                        $onclick = 'inji.Ui.modals.show("' . addcslashes($addres['address'], '"') . '", $("#map' . $uid . '_container script").html().replace(/^\/\*/g, "").replace(/\*\/$/g, "")+"</script>","mapmodal' . $uid . '","modal-lg");';
350
                                        $onclick .= 'return false;';
351
                                        $value = "<a href ='#' onclick='{$onclick}' >{$name}</a>";
352
                                        $value .= $content;
353
                                    } else {
354
                                        $value = 'Местоположение не заданно';
355
                                    }
356
357
                                    break;
358
                                default:
359
                                    $value = $item->$colName;
360
                            }
361
                        }
362
                        break;
363
                }
364
                break;
365
            default:
366
                $value = $item->$colName;
367
                break;
368
        }
369
        return $value;
370
    }
371
372
    /**
373
     * Fix col prefix
374
     * 
375
     * @param mixed $array
376
     * @param string $searchtype
377
     * @param string $rootModel
378
     * @return null
379
     */
380 4
    public static function fixPrefix(&$array, $searchtype = 'key', $rootModel = '') {
381 4
        if (!$rootModel) {
382 4
            $rootModel = get_called_class();
383 4
        }
384 4
        $cols = static::cols();
385 4
        if (!$array) {
386 4
            return;
387
        }
388 4
        if (!is_array($array)) {
389 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...
390 2
                static::createCol($array);
391 2
                $cols = static::cols(true);
392 2
            }
393 4
            if (!isset($cols[$array]) && isset($cols[static::colPrefix() . $array])) {
394 4
                $array = static::colPrefix() . $array;
395 4
            } else {
396 4
                static::checkForJoin($array, $rootModel);
397
            }
398 4
            return;
399
        }
400
        switch ($searchtype) {
401 2
            case 'key':
402 2
                foreach ($array as $key => $item) {
403 2 View Code Duplication
                    if (!isset($cols[static::colPrefix() . $key]) && isset(static::$cols[$key])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
404
                        static::createCol($key);
405
                        $cols = static::cols(true);
406
                    }
407 2
                    if (!isset($cols[$key]) && isset($cols[static::colPrefix() . $key])) {
408 2
                        $array[static::colPrefix() . $key] = $item;
409 2
                        unset($array[$key]);
410 2
                        $key = static::colPrefix() . $key;
411 2
                    }
412 2
                    if (is_array($array[$key])) {
413
                        static::fixPrefix($array[$key], 'key', $rootModel);
414
                    } else {
415 2
                        static::checkForJoin($key, $rootModel);
416
                    }
417 2
                }
418 2
                break;
419 1
            case 'first':
420 1
                if (isset($array[0]) && is_string($array[0])) {
421 1
                    if (!isset($cols[static::colPrefix() . $array[0]]) && isset(static::$cols[$array[0]])) {
422
                        static::createCol($array[0]);
423
                        $cols = static::cols(true);
424
                    }
425 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...
426 1
                        $array[0] = static::colPrefix() . $array[0];
427 1
                    } else {
428
                        static::checkForJoin($array[0], $rootModel);
429
                    }
430 1
                } elseif (isset($array[0]) && is_array($array[0])) {
431 1
                    foreach ($array as &$item) {
432 1
                        static::fixPrefix($item, 'first', $rootModel);
433 1
                    }
434 1
                }
435 1
                break;
436
        }
437 2
    }
438
439
    /**
440
     * @param boolean $new
441
     */
442 4
    public function logChanges($new) {
443 4
        if (!App::$cur->db->connect || !App::$cur->dashboard) {
444
            return false;
445
        }
446 4
        $class = get_class($this);
447 4
        if (!$class::$logging) {
448 4
            return false;
449
        }
450 2
        $user_id = class_exists('Users\User') ? \Users\User::$cur->id : 0;
451 2
        if (!$new && !empty($this->_changedParams)) {
452
            $activity = new Dashboard\Activity([
453
                'user_id' => $user_id,
454
                'module' => substr($class, 0, strpos($class, '\\')),
455
                'model' => $class,
456
                'item_id' => $this->pk(),
457
                'type' => 'changes'
458
            ]);
459
            $changes_text = [];
460
            foreach ($this->_changedParams as $fullColName => $oldValue) {
461
                $colName = substr($fullColName, strlen($class::colPrefix()));
462
                if (isset($class::$cols[$colName]['logging']) && !$class::$cols[$colName]['logging']) {
463
                    continue;
464
                }
465
                if (strlen($oldValue) + strlen($this->_params[$fullColName]) < 200) {
466
                    $changes_text[] = (!empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName) . ": \"{$oldValue}\" => \"{$this->$colName}\"";
467
                } else {
468
                    $changes_text[] = !empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName;
469
                }
470
            }
471
            if (!$changes_text) {
472
                return false;
473
            }
474
            $activity->changes_text = implode(', ', $changes_text);
475
            $activity->save();
476
            foreach ($this->_changedParams as $fullColName => $oldValue) {
477
                $colName = substr($fullColName, strlen($class::colPrefix()));
478
                $change = new Dashboard\Activity\Change([
479
                    'activity_id' => $activity->id,
480
                    'col' => $colName,
481
                    'old' => $oldValue,
482
                    'new' => $this->$colName
483
                ]);
484
                $change->save();
485
            }
486 2
        } elseif ($new) {
487 2
            $activity = new Dashboard\Activity([
488 2
                'user_id' => $user_id,
489 2
                'module' => substr($class, 0, strpos($class, '\\')),
490 2
                'model' => $class,
491 2
                'item_id' => $this->pk(),
492
                'type' => 'new'
493 2
            ]);
494 2
            $activity->save();
495 2
        }
496 2
        return true;
497
    }
498
499
    /**
500
     * Check model relations path and load need relations
501
     * 
502
     * @param string $col
503
     * @param string $rootModel
504
     */
505 4
    public static function checkForJoin(&$col, $rootModel) {
506
507 4
        if (strpos($col, ':') !== false) {
508
            $relations = static::relations();
509
            if (isset($relations[substr($col, 0, strpos($col, ':'))])) {
510
                $rel = substr($col, 0, strpos($col, ':'));
511
                $col = substr($col, strpos($col, ':') + 1);
512
513
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
514
                switch ($type) {
515 View Code Duplication
                    case 'to':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
516
                        $relCol = $relations[$rel]['col'];
517
                        static::fixPrefix($relCol);
518
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
519
                        break;
520
                    case 'one':
521 View Code Duplication
                    case 'many':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1938
        $className = get_class($this);
1939
        $link = substr($className, 0, strpos($className, '\\'));
1940
        $link .= '/view/';
1941
        $link .= str_replace('\\', '%5C', substr($className, strpos($className, '\\') + 1));
1942
        $link .= "/{$this->id}";
1943
        return $link;
1944
    }
1945
1946
    /**
1947
     * Set handler for model params
1948
     * 
1949
     * @param string $name
1950
     * @param mixed $value
1951
     */
1952 4
    public function __set($name, $value) {
1953 4
        static::fixPrefix($name);
1954 4
        $className = get_called_class();
1955 4
        $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $name);
1956 4
        if (!empty($className::$cols[$shortName])) {
1957 4
            switch ($className::$cols[$shortName]['type']) {
1958 4
                case 'decimal':
1959
                    $value = (float) $value;
1960
                    break;
1961 4
                case 'number':
1962
                    $value = (int) $value;
1963
                    break;
1964 4
                case 'bool':
1965
                    $value = (bool) $value;
1966
                    break;
1967 4
            }
1968 4
        }
1969 4
        if ((isset($this->_params[$name]) && $this->_params[$name] != $value) && !isset($this->_changedParams[$name])) {
1970 3
            $this->_changedParams[$name] = $this->_params[$name];
1971 3
        }
1972
1973 4
        $this->_params[$name] = $value;
1974 4
    }
1975
1976
    /**
1977
     * Isset handler for model params
1978
     * 
1979
     * @param string $name
1980
     * @return boolean
1981
     */
1982
    public function __isset($name) {
1983
        static::fixPrefix($name);
1984
        return isset($this->_params[$name]);
1985
    }
1986
1987
    /**
1988
     * Convert object to string
1989
     * 
1990
     * @return string
1991
     */
1992
    public function __toString() {
1993
        return $this->name();
1994
    }
1995
}