Passed
Push — master ( d15464...d64dd2 )
by Alexey
05:25
created

Model::update()   B

Complexity

Conditions 5
Paths 9

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

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

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
307
                            $value = $sourceModel::get($item->$colName);
308
                            if ($value) {
309
                                $value = $value->name();
310
                            } else {
311
                                $value = $item->$colName;
312
                            }
313
                        } else {
314
                            switch ($type) {
315 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...
316
                                    if ($item->$colName && json_decode($item->$colName, true)) {
317
                                        $addres = json_decode($item->$colName, true);
318
                                        $name = $addres['address'] ? $addres['address'] : 'lat:' . $addres['lat'] . ': lng:' . $addres['lng'];
319
                                        \App::$cur->libs->loadLib('yandexMap');
320
                                        ob_start();
321
                                        $uid = Tools::randomString();
322
                                        ?>
323
                                        <div id='map<?= $uid; ?>_container' style="display:none;"><script>/*
324
                                                                                 <div id='map<?= $uid; ?>' style="width: 100%; height: 500px"></div>
325
                                                                                 <script>
326
                                                                                 var myMap<?= $uid; ?>;
327
                                                                                 var myMap<?= $uid; ?>CurPin;
328
                                                                                 inji.onLoad(function () {
329
                                                                                 ymaps.ready(init<?= $uid; ?>);
330
                                                                                 function init<?= $uid; ?>() {
331
                                                                                 var myPlacemark;
332
                                                                                 myMap<?= $uid; ?> = new ymaps.Map("map<?= $uid; ?>", {
333
                                                                                 center: ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"],
334
                                                                                 zoom: 13
335
                                                                                 });
336
                                                                                 myCoords = ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"];
337
                                                                                 myMap<?= $uid; ?>CurPin = new ymaps.Placemark(myCoords,
338
                                                                                 {iconContent: "<?= $addres['address']; ?>"},
339
                                                                                 {preset: 'islands#greenStretchyIcon'}
340
                                                                                 );
341
                                                                                 myMap<?= $uid; ?>.geoObjects.add(myMap<?= $uid; ?>CurPin, 0);
342
                                                                                 }
343
                                                                                 window['init<?= $uid; ?>'] = init<?= $uid; ?>;
344
                                                                                 });
345
                                                                                 */</script>
346
                                        </div>
347
                                        <?php
348
                                        $content = ob_get_contents();
349
                                        ob_end_clean();
350
                                        $onclick = 'inji.Ui.modals.show("' . addcslashes($addres['address'], '"') . '", $("#map' . $uid . '_container script").html().replace(/^\/\*/g, "").replace(/\*\/$/g, "")+"</script>","mapmodal' . $uid . '","modal-lg");';
351
                                        $onclick .= 'return false;';
352
                                        $value = "<a href ='#' onclick='{$onclick}' >{$name}</a>";
353
                                        $value .= $content;
354
                                    } else {
355
                                        $value = 'Местоположение не заданно';
356
                                    }
357
358
                                    break;
359
                                default:
360
                                    $value = $item->$colName;
361
                            }
362
                        }
363
                        break;
364
                }
365
                break;
366
            default:
367
                $value = $item->$colName;
368
                break;
369
        }
370
        return $value;
371
    }
372
373
    /**
374
     * Fix col prefix
375
     * 
376
     * @param mixed $array
377
     * @param string $searchtype
378
     * @param string $rootModel
379
     * @return null
380
     */
381 4
    public static function fixPrefix(&$array, $searchtype = 'key', $rootModel = '') {
382 4
        if (!$rootModel) {
383 4
            $rootModel = get_called_class();
384 4
        }
385 4
        $cols = static::cols();
386 4
        if (!$array) {
387 4
            return;
388
        }
389 4
        if (!is_array($array)) {
390 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...
391 2
                static::createCol($array);
392 2
                $cols = static::cols(true);
393 2
            }
394 4
            if (!isset($cols[$array]) && isset($cols[static::colPrefix() . $array])) {
395 4
                $array = static::colPrefix() . $array;
396 4
            } else {
397 4
                static::checkForJoin($array, $rootModel);
398
            }
399 4
            return;
400
        }
401
        switch ($searchtype) {
402 2
            case 'key':
403 2
                foreach ($array as $key => $item) {
404 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...
405
                        static::createCol($key);
406
                        $cols = static::cols(true);
407
                    }
408 2
                    if (!isset($cols[$key]) && isset($cols[static::colPrefix() . $key])) {
409 2
                        $array[static::colPrefix() . $key] = $item;
410 2
                        unset($array[$key]);
411 2
                        $key = static::colPrefix() . $key;
412 2
                    }
413 2
                    if (is_array($array[$key])) {
414
                        static::fixPrefix($array[$key], 'key', $rootModel);
415
                    } else {
416 2
                        static::checkForJoin($key, $rootModel);
417
                    }
418 2
                }
419 2
                break;
420 1
            case 'first':
421 1
                if (isset($array[0]) && is_string($array[0])) {
422 1
                    if (!isset($cols[static::colPrefix() . $array[0]]) && isset(static::$cols[$array[0]])) {
423
                        static::createCol($array[0]);
424
                        $cols = static::cols(true);
425
                    }
426 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...
427 1
                        $array[0] = static::colPrefix() . $array[0];
428 1
                    } else {
429
                        static::checkForJoin($array[0], $rootModel);
430
                    }
431 1
                } elseif (isset($array[0]) && is_array($array[0])) {
432 1
                    foreach ($array as &$item) {
433 1
                        static::fixPrefix($item, 'first', $rootModel);
434 1
                    }
435 1
                }
436 1
                break;
437
        }
438 2
    }
439
440
    /**
441
     * @param boolean $new
442
     */
443 4
    public function logChanges($new) {
444 4
        if (!App::$cur->db->connect || !App::$cur->dashboard) {
445
            return false;
446
        }
447 4
        $class = get_class($this);
448 4
        if (!$class::$logging) {
449 4
            return false;
450
        }
451 2
        $user_id = class_exists('Users\User') ? \Users\User::$cur->id : 0;
452 2
        if (!$new && !empty($this->_changedParams)) {
453
            $activity = new Dashboard\Activity([
454
                'user_id' => $user_id,
455
                'module' => substr($class, 0, strpos($class, '\\')),
456
                'model' => $class,
457
                'item_id' => $this->pk(),
458
                'type' => 'changes'
459
            ]);
460
            $changes_text = [];
461
            foreach ($this->_changedParams as $fullColName => $oldValue) {
462
                $colName = substr($fullColName, strlen($class::colPrefix()));
463
                if (isset($class::$cols[$colName]['logging']) && !$class::$cols[$colName]['logging']) {
464
                    continue;
465
                }
466
                if (strlen($oldValue) + strlen($this->_params[$fullColName]) < 200) {
467
                    $changes_text[] = (!empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName) . ": \"{$oldValue}\" => \"{$this->$colName}\"";
468
                } else {
469
                    $changes_text[] = !empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName;
470
                }
471
            }
472
            if (!$changes_text) {
473
                return false;
474
            }
475
            $activity->changes_text = implode(', ', $changes_text);
476
            $activity->save();
477
            foreach ($this->_changedParams as $fullColName => $oldValue) {
478
                $colName = substr($fullColName, strlen($class::colPrefix()));
479
                $change = new Dashboard\Activity\Change([
480
                    'activity_id' => $activity->id,
481
                    'col' => $colName,
482
                    'old' => $oldValue,
483
                    'new' => $this->$colName
484
                ]);
485
                $change->save();
486
            }
487 2
        } elseif ($new) {
488 2
            $activity = new Dashboard\Activity([
489 2
                'user_id' => $user_id,
490 2
                'module' => substr($class, 0, strpos($class, '\\')),
491 2
                'model' => $class,
492 2
                'item_id' => $this->pk(),
493
                'type' => 'new'
494 2
            ]);
495 2
            $activity->save();
496 2
        }
497 2
        return true;
498
    }
499
500
    /**
501
     * Check model relations path and load need relations
502
     * 
503
     * @param string $col
504
     * @param string $rootModel
505
     */
506 4
    public static function checkForJoin(&$col, $rootModel) {
507
508 4
        if (strpos($col, ':') !== false) {
509
            $relations = static::relations();
510
            if (isset($relations[substr($col, 0, strpos($col, ':'))])) {
511
                $rel = substr($col, 0, strpos($col, ':'));
512
                $col = substr($col, strpos($col, ':') + 1);
513
514
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
515
                switch ($type) {
516 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...
517
                        $relCol = $relations[$rel]['col'];
518
                        static::fixPrefix($relCol);
519
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
520
                        break;
521
                    case 'one':
522 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...
523
                        $relCol = $relations[$rel]['col'];
524
                        $relations[$rel]['model']::fixPrefix($relCol);
525
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
526
                        break;
527
                }
528
                $relations[$rel]['model']::fixPrefix($col, 'key', $rootModel);
529
            }
530
        }
531 4
    }
532
533
    /**
534
     * Return full col information
535
     * 
536
     * @param string $col
537
     * @return array
538
     */
539
    public static function getColInfo($col) {
540
        return static::parseColRecursion($col);
541
    }
542
543
    /**
544
     * Information extractor for col relations path
545
     * 
546
     * @param string|array $info
547
     * @return array
548
     */
549
    public static function parseColRecursion($info) {
550
        if (is_string($info)) {
551
            $info = ['col' => $info, 'rawCol' => $info, 'modelName' => '', 'label' => '', 'joins' => []];
552
        }
553
        if (strpos($info['col'], ':') !== false) {
554
            $relations = static::relations();
555
            if (isset($relations[substr($info['col'], 0, strpos($info['col'], ':'))])) {
556
                $rel = substr($info['col'], 0, strpos($info['col'], ':'));
557
                $info['col'] = substr($info['col'], strpos($info['col'], ':') + 1);
558
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
559
                switch ($type) {
560 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...
561
                        $relCol = $relations[$rel]['col'];
562
                        static::fixPrefix($relCol);
563
                        //$info['modelName'] = $relations[$rel]['model'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
564
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
565
                        break;
566 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...
567
                        $relCol = $relations[$rel]['col'];
568
                        $relations[$rel]['model']::fixPrefix($relCol);
569
                        //$info['modelName'] = $relations[$rel]['model'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
570
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
571
                        break;
572
                }
573
                $info = $relations[$rel]['model']::parseColRecursion($info);
574
            }
575
        } else {
576
            $cols = static::cols();
577 View Code Duplication
            if (!empty(static::$labels[$info['col']])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
578
                $info['label'] = static::$labels[$info['col']];
579
            }
580
581
            if (isset(static::$cols[$info['col']])) {
582
                $info['colParams'] = static::$cols[$info['col']];
583
            } elseif (isset(static::$cols[str_replace(static::colPrefix(), '', $info['col'])])) {
584
                $info['colParams'] = static::$cols[str_replace(static::colPrefix(), '', $info['col'])];
585
            } else {
586
                $info['colParams'] = [];
587
            }
588 View Code Duplication
            if (!isset($cols[$info['col']]) && isset($cols[static::colPrefix() . $info['col']])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
589
                $info['col'] = static::colPrefix() . $info['col'];
590
            }
591
            $info['modelName'] = get_called_class();
592
        }
593 View Code Duplication
        if (!empty(static::$labels[$info['rawCol']])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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

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

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

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

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

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

Loading history...
613
            static::createTable();
614
            Model::$cols[static::table()] = App::$cur->db->getTableCols(static::table());
615
        }
616 4
        return Model::$cols[static::table()];
617
    }
618
619
    /**
620
     * Return cols indexes for create tables
621
     * 
622
     * @return array
623
     */
624 3
    public static function indexes() {
625 3
        return [];
626
    }
627
628
    /**
629
     * Generate params string for col by name
630
     * 
631
     * @param string $colName
632
     * @return boolean|string
633
     */
634 4
    public static function genColParams($colName) {
635 4
        if (empty(static::$cols[$colName]) || static::$storage['type'] == 'moduleConfig') {
636 1
            return false;
637
        }
638
639 4
        $params = false;
640 4
        switch (static::$cols[$colName]['type']) {
641 4
            case 'select':
642 4
                switch (static::$cols[$colName]['source']) {
643 4
                    case 'relation':
644 4
                        $params = 'int(11) UNSIGNED NOT NULL';
645 4
                        break;
646 1
                    default:
647 1
                        $params = 'varchar(255) NOT NULL';
648 4
                }
649 4
                break;
650 4
            case 'image':
651 4
            case 'file':
652 1
                $params = 'int(11) UNSIGNED NOT NULL';
653 1
                break;
654 4
            case 'number':
655
                $params = 'int(11) NOT NULL';
656
                break;
657 4
            case 'text':
658 4
            case 'email':
659 3
                $params = 'varchar(255) NOT NULL';
660 3
                break;
661 3
            case 'html':
662 3
            case 'textarea':
663 3
            case 'json':
664 3
            case 'password':
665 3
            case 'dynamicType':
666 3
            case 'map':
667 1
                $params = 'text NOT NULL';
668 1
                break;
669 3
            case 'bool':
670 1
                $params = 'tinyint(1) UNSIGNED NOT NULL';
671 1
                break;
672 3
            case 'decimal':
673
                $params = 'decimal(8, 2) NOT NULL';
674
                break;
675 3
            case 'date':
676 1
                $params = 'date NOT NULL DEFAULT 0';
677 1
                break;
678 3
            case 'dateTime':
679 2
                $params = 'timestamp NOT NULL DEFAULT 0';
680 2
                break;
681 4
        }
682 4
        return $params;
683
    }
684
685
    /**
686
     * Create new col in data base
687
     * 
688
     * @param string $colName
689
     * @return boolean|integer
690
     */
691 2
    public static function createCol($colName) {
692 2
        $params = static::genColParams($colName);
693 2
        if ($params === false) {
694 2
            return false;
695
        }
696
        return App::$cur->db->addCol(static::table(), static::colPrefix() . $colName, $params);
697
    }
698
699 4
    public static function createTable() {
700 4
        if (static::$storage['type'] == 'moduleConfig') {
701
            return true;
702
        }
703 4
        if (!App::$cur->db) {
704
            return false;
705
        }
706
707 4
        $query = App::$cur->db->newQuery();
708 4
        if (!$query) {
709
            return false;
710
        }
711
712 4
        if (!isset($this)) {
713 4
            $tableName = static::table();
714 4
            $colPrefix = static::colPrefix();
715 4
            $indexes = static::indexes();
716 4
        } else {
717
            $tableName = $this->table();
718
            $colPrefix = $this->colPrefix();
719
            $indexes = $this->indexes();
720
        }
721 4
        if (App::$cur->db->tableExist($tableName)) {
722
            return true;
723
        }
724
        $cols = [
725 4
            $colPrefix . 'id' => 'pk'
726 4
        ];
727 4
        $className = get_called_class();
728 4
        if (!empty($className::$cols)) {
729 4
            foreach ($className::$cols as $colName => $colParams) {
730 4
                if ($colName == 'date_create') {
731 4
                    $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
732 4
                    continue;
733
                }
734 4
                $params = $className::genColParams($colName);
735 4
                if ($params) {
736 4
                    $cols[$colPrefix . $colName] = $params;
737 4
                }
738 4
            }
739 4
        }
740 4
        if (empty($cols[$colPrefix . 'date_create'])) {
741 1
            $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
742 1
        }
743 4
        $tableIndexes = [];
744 4
        if ($indexes) {
745 1
            foreach ($indexes as $indexName => $index) {
746 1
                $tableIndexes[] = $index['type'] . ' ' . App::$cur->db->table_prefix . $indexName . ' (' . implode(',', $index['cols']) . ')';
747 1
            }
748 1
        }
749
750 4
        $query->createTable($tableName, $cols, $tableIndexes);
751 4
        return true;
752
    }
753
754
    /**
755
     * Return table name
756
     * 
757
     * @return string
758
     */
759 4
    public static function table() {
760 4
        return strtolower(str_replace('\\', '_', get_called_class()));
761
    }
762
763
    /**
764
     * Return table index col name
765
     * 
766
     * @return string
767
     */
768 4
    public static function index() {
769
770 4
        return static::colPrefix() . 'id';
771
    }
772
773
    /**
774
     * Return col prefix
775
     * 
776
     * @return string
777
     */
778 4
    public static function colPrefix() {
779 4
        $classPath = explode('\\', get_called_class());
780 4
        $classPath = array_slice($classPath, 1);
781 4
        return strtolower(implode('_', $classPath)) . '_';
782
    }
783
784
    /**
785
     * return relations list
786
     * 
787
     * @return array
788
     */
789 1
    public static function relations() {
790 1
        return [];
791
    }
792
793
    /**
794
     * views list
795
     * 
796
     * @return array
797
     */
798
    public static $views = [];
799
800
    /**
801
     * Return name of col with object name
802
     * 
803
     * @return string
804
     */
805
    public static function nameCol() {
806
        return 'name';
807
    }
808
809
    /**
810
     * Return object name
811
     * 
812
     * @return string
813
     */
814
    public function name() {
815
        return $this->{$this->nameCol()} ? $this->{$this->nameCol()} : '№' . $this->pk();
816
    }
817
818
    /**
819
     * Get single object from data base
820
     * 
821
     * @param mixed $param
822
     * @param string $col
823
     * @param array $options
824
     * @return boolean|\Model
825
     */
826 4
    public static function get($param, $col = null, $options = []) {
827 4
        if (static::$storage['type'] == 'moduleConfig') {
828
            return static::getFromModuleStorage($param, $col, $options);
829
        }
830 4
        if (!empty($col)) {
831 4
            static::fixPrefix($col);
832 4
        }
833
834 4
        if (is_array($param)) {
835 1
            static::fixPrefix($param, 'first');
836 1
        }
837 4
        foreach (static::$relJoins as $join) {
838
            App::$cur->db->join($join[0], $join[1]);
839 4
        }
840 4
        static::$relJoins = [];
841 4
        foreach (static::$needJoin as $rel) {
842
            $relations = static::relations();
843
            if (isset($relations[$rel])) {
844
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
845
                switch ($type) {
846
                    case 'to':
847
                        $relCol = $relations[$rel]['col'];
848
                        static::fixPrefix($relCol);
849
                        App::$cur->db->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
850
                        break;
851
                    case 'one':
852
                        $col = $relations[$rel]['col'];
853
                        $relations[$rel]['model']::fixPrefix($col);
854
                        App::$cur->db->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
855
                        break;
856
                }
857
            }
858 4
        }
859 4
        static::$needJoin = [];
860 4
        if (is_array($param)) {
861 1
            App::$cur->db->where($param);
862 1
        } else {
863 4
            if ($col === null) {
864
865 3
                $col = static::index();
866 3
            }
867 4
            if ($param !== null) {
868 4
                $cols = static::cols();
869 4
                if (!isset($cols[$col]) && isset($cols[static::colPrefix() . $col])) {
870
                    $col = static::colPrefix() . $col;
871
                }
872 4
                App::$cur->db->where($col, $param);
873 4
            } else {
874
                return false;
875
            }
876
        }
877 4
        if (!App::$cur->db->where) {
878
            return false;
879
        }
880
        try {
881 4
            $result = App::$cur->db->select(static::table());
882 4
        } catch (PDOException $exc) {
883
            if ($exc->getCode() == '42S02') {
884
                static::createTable();
885
            }
886
            $result = App::$cur->db->select(static::table());
887
        }
888 4
        if (!$result) {
889
            return false;
890
        }
891 4
        return $result->fetch(get_called_class());
892
    }
893
894
    /**
895
     * Old method
896
     * 
897
     * @param type $options
898
     * @return Array
899
     */
900
    public static function get_list($options = []) {
901
        $query = App::$cur->db->newQuery();
902
        if (!$query) {
903
            return [];
904
        }
905
        if (!empty($options['where'])) {
906
            $query->where($options['where']);
907
        }
908
        if (!empty($options['cols'])) {
909
            $query->cols = $options['cols'];
910
        }
911
        if (!empty($options['group'])) {
912
            $query->group($options['group']);
913
        }
914
        if (!empty($options['having'])) {
915
            $query->having($options['having']);
916
        }
917
        if (!empty($options['order'])) {
918
            $query->order($options['order']);
919
        }
920
        if (!empty($options['join'])) {
921
            $query->join($options['join']);
922
        }
923
        if (!empty($options['distinct'])) {
924
            $query->distinct = $options['distinct'];
925
        }
926
927
        foreach (static::$relJoins as $join) {
928
            $query->join($join[0], $join[1]);
929
        }
930
        static::$relJoins = [];
931 View Code Duplication
        foreach (static::$needJoin as $rel) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
932
            $relations = static::relations();
933
            if (isset($relations[$rel])) {
934
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
935
                switch ($type) {
936
                    case 'to':
937
                        $relCol = $relations[$rel]['col'];
938
                        static::fixPrefix($relCol);
939
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
940
                        break;
941
                    case 'one':
942
                        $col = $relations[$rel]['col'];
943
                        $relations[$rel]['model']::fixPrefix($col);
944
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
945
                        break;
946
                }
947
            }
948
        }
949
        static::$needJoin = [];
950
951 View Code Duplication
        if (!empty($options['limit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
952
            $limit = (int) $options['limit'];
953
        } else {
954
            $limit = 0;
955
        }
956 View Code Duplication
        if (!empty($options['start'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
957
            $start = (int) $options['start'];
958
        } else {
959
            $start = 0;
960
        }
961
        if ($limit || $start) {
962
            $query->limit($start, $limit);
963
        }
964
        if (isset($options['key'])) {
965
            $key = $options['key'];
966
        } else {
967
            $key = static::index();
968
        }
969
        try {
970
            $query->operation = 'SELECT';
971
            $query->table = static::table();
972
            $queryArr = $query->buildQuery();
973
            $result = $query->query($queryArr);
974
        } catch (PDOException $exc) {
975
            if ($exc->getCode() == '42S02') {
976
                static::createTable();
977
                $result = $query->query($queryArr);
978
            } else {
979
                throw $exc;
980
            }
981
        }
982
983
        if (!empty($options['array'])) {
984
            return $result->getArray($key);
985
        }
986
        $list = $result->getObjects(get_called_class(), $key);
987 View Code Duplication
        if (!empty($options['forSelect'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
988
            $return = [];
989
            foreach ($list as $key => $item) {
990
                $return[$key] = $item->name();
991
            }
992
            return $return;
993
        }
994
        return $list;
995
    }
996
997
    /**
998
     * Return list of objects from data base
999
     * 
1000
     * @param type $options
1001
     * @return type
1002
     */
1003
    public static function getList($options = []) {
1004
        if (static::$storage['type'] != 'db') {
1005
            return static::getListFromModuleStorage($options);
1006
        }
1007
        if (!empty($options['where'])) {
1008
            static::fixPrefix($options['where'], 'first');
1009
        }
1010
        if (!empty($options['group'])) {
1011
            static::fixPrefix($options['group'], 'first');
1012
        }
1013
        if (!empty($options['order'])) {
1014
            static::fixPrefix($options['order'], 'first');
1015
        }
1016
        if (!empty($options['having'])) {
1017
            static::fixPrefix($options['having'], 'first');
1018
        }
1019
        return static::get_list($options);
1020
    }
1021
1022
    /**
1023
     * Get single item from module storage
1024
     * 
1025
     * @param array $param
1026
     * @param string $col
1027
     * @param array $options
1028
     * @return boolean|\Model
1029
     */
1030
    public static function getFromModuleStorage($param = null, $col = null, $options = []) {
1031
        if ($col === null) {
1032
1033
            $col = static::index();
1034
        }
1035
        if ($param == null) {
1036
            return false;
1037
        }
1038
        $classPath = explode('\\', get_called_class());
1039 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1040
            $moduleConfig = Config::share($classPath[0]);
1041
        } else {
1042
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1043
        }
1044
        $appType = App::$cur->type;
1045 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1046
            if (!empty($options['appType'])) {
1047
                $appType = $options['appType'];
1048
            }
1049
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1050
        } else {
1051
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1052
        }
1053
        if (!empty($storage[$classPath[1]])) {
1054
            $items = $storage[$classPath[1]];
1055
            $class = get_called_class();
1056
            $where = is_array($param) ? $param : [$col, $param];
1057
            foreach ($items as $key => $item) {
1058
                if (!Model::checkWhere($item, $where)) {
1059
                    continue;
1060
                }
1061
                if (!empty($options['array'])) {
1062
                    return $item;
1063
                }
1064
                $item = new $class($item);
1065
                $item->appType = $appType;
1066
                return $item;
1067
            }
1068
        }
1069
        return false;
1070
    }
1071
1072
    /**
1073
     * Return list items from module storage
1074
     * 
1075
     * @param array $options
1076
     * @return array
1077
     */
1078
    public static function getListFromModuleStorage($options = []) {
1079
        $classPath = explode('\\', get_called_class());
1080 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1081
            $moduleConfig = Config::share($classPath[0]);
1082
        } else {
1083
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1084
        }
1085 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1086
            if (empty($options['appType'])) {
1087
                $appType = App::$cur->type;
1088
            } else {
1089
                $appType = $options['appType'];
1090
            }
1091
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1092
        } else {
1093
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1094
        }
1095
        if (!empty($storage[$classPath[1]])) {
1096
            $items = [];
1097
            $class = get_called_class();
1098
            if (isset($options['key'])) {
1099
                $arrayKey = $options['key'];
1100
            } else {
1101
                $arrayKey = static::index();
1102
            }
1103
            foreach ($storage[$classPath[1]] as $key => $item) {
1104
                if (!empty($options['where']) && !Model::checkWhere($item, $options['where'])) {
1105
                    continue;
1106
                }
1107
                $items[$item[$arrayKey]] = new $class($item);
1108
            }
1109
            if (!empty($options['order'])) {
1110
                usort($items, function($a, $b) use($options) {
1111
                    if ($a->{$options['order'][0]} > $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1112
                        return 1;
1113
                    } elseif ($a->{$options['order'][0]} < $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1114
                        return -1;
1115
                    }
1116
                    return 0;
1117
                });
1118
            }
1119 View Code Duplication
            if (!empty($options['forSelect'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1120
                $return = [];
1121
                foreach ($items as $key => $item) {
1122
                    $return[$key] = $item->name();
1123
                }
1124
                return $return;
1125
            }
1126
            return $items;
1127
        }
1128
        return [];
1129
    }
1130
1131
    /**
1132
     * Return count of records from module storage
1133
     * 
1134
     * @param array $options
1135
     * @return int
1136
     */
1137
    public static function getCountFromModuleStorage($options = []) {
1138
1139
        $classPath = explode('\\', get_called_class());
1140
        $count = 0;
1141
        if (empty($options['appType'])) {
1142
            $appType = App::$cur->type;
1143
        } else {
1144
            $appType = $options['appType'];
1145
        }
1146 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1147
            $moduleConfig = Config::share($classPath[0]);
1148
        } else {
1149
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1150
        }
1151
        if (!empty($moduleConfig['storage'][$appType][$classPath[1]])) {
1152
            $items = $moduleConfig['storage'][$appType][$classPath[1]];
1153
            if (empty($options['where'])) {
1154
                return count($items);
1155
            }
1156
            foreach ($items as $key => $item) {
1157
                if (!empty($options['where'])) {
1158
                    if (Model::checkWhere($item, $options['where'])) {
1159
                        $count++;
1160
                    }
1161
                } else {
1162
                    $count++;
1163
                }
1164
            }
1165
        }
1166
        return $count;
1167
    }
1168
1169
    /**
1170
     * Check where for module storage query
1171
     * 
1172
     * @param array $item
1173
     * @param array|string $where
1174
     * @param string $value
1175
     * @param string $operation
1176
     * @param string $concatenation
1177
     * @return boolean
1178
     */
1179
    public static function checkWhere($item = [], $where = '', $value = '', $operation = '=', $concatenation = 'AND') {
1180
1181
        if (is_array($where)) {
1182
            if (is_array($where[0])) {
1183
                $result = true;
1184
                foreach ($where as $key => $whereItem) {
1185
                    $concatenation = empty($whereItem[3]) ? 'AND' : strtoupper($whereItem[3]);
1186
                    switch ($concatenation) {
1187 View Code Duplication
                        case 'AND':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1188
                            $result = $result && forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1189
                            break;
1190 View Code Duplication
                        case 'OR':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1191
                            $result = $result || forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1192
                            break;
1193
                    }
1194
                }
1195
1196
                return $result;
1197
            } else {
1198
                return forward_static_call_array(['Model', 'checkWhere'], array_merge([$item], $where));
1199
            }
1200
        }
1201
        if (!isset($item[$where]) && !$value) {
1202
            return true;
1203
        }
1204
        if (!isset($item[$where]) && $value) {
1205
            return false;
1206
        }
1207
        if ($item[$where] == $value) {
1208
            return true;
1209
        }
1210
        return false;
1211
    }
1212
1213
    /**
1214
     * Return count of records from data base
1215
     * 
1216
     * @param array $options
1217
     * @return array|int
1218
     */
1219
    public static function getCount($options = []) {
1220
        if (static::$storage['type'] == 'moduleConfig') {
1221
            return static::getCountFromModuleStorage($options);
1222
        }
1223
        $query = App::$cur->db->newQuery();
1224
        if (!$query) {
1225
            return 0;
1226
        }
1227
        if (!empty($options['where'])) {
1228
            static::fixPrefix($options['where'], 'first');
1229
        }
1230
        if (!empty($options['group'])) {
1231
            static::fixPrefix($options['group'], 'first');
1232
        }
1233
        if (!empty($options['where'])) {
1234
            $query->where($options['where']);
1235
        }
1236
        if (!empty($options['join'])) {
1237
            $query->join($options['join']);
1238
        }
1239
        if (!empty($options['order'])) {
1240
            $query->order($options['order']);
1241
        }
1242 View Code Duplication
        if (!empty($options['limit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1243
            $limit = (int) $options['limit'];
1244
        } else {
1245
            $limit = 0;
1246
        }
1247 View Code Duplication
        if (!empty($options['start'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1248
            $start = (int) $options['start'];
1249
        } else {
1250
            $start = 0;
1251
        }
1252
        if ($limit || $start) {
1253
            $query->limit($start, $limit);
1254
        }
1255
1256
        foreach (static::$relJoins as $join) {
1257
            $query->join($join[0], $join[1]);
1258
        }
1259
        static::$relJoins = [];
1260 View Code Duplication
        foreach (static::$needJoin as $rel) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1261
            $relations = static::relations();
1262
            if (isset($relations[$rel])) {
1263
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
1264
                switch ($type) {
1265
                    case 'to':
1266
                        $relCol = $relations[$rel]['col'];
1267
                        static::fixPrefix($relCol);
1268
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
1269
                        break;
1270
                    case 'one':
1271
                        $col = $relations[$rel]['col'];
1272
                        $relations[$rel]['model']::fixPrefix($col);
1273
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
1274
                        break;
1275
                }
1276
            }
1277
        }
1278
        static::$needJoin = [];
1279
        $cols = 'COUNT(';
1280
1281
        if (!empty($options['distinct'])) {
1282
            if (is_bool($options['distinct'])) {
1283
                $cols .= 'DISTINCT *';
1284
            } else {
1285
                $cols .= "DISTINCT {$options['distinct']}";
1286
            }
1287
        } else {
1288
            $cols .= '*';
1289
        }
1290
        $cols .=') as `count`' . (!empty($options['cols']) ? ',' . $options['cols'] : '');
1291
        $query->cols = $cols;
1292
        if (!empty($options['group'])) {
1293
            $query->group($options['group']);
1294
        }
1295
        try {
1296
            $result = $query->select(static::table());
1297
        } catch (PDOException $exc) {
1298
            if ($exc->getCode() == '42S02') {
1299
                static::createTable();
1300
            }
1301
            $result = $query->select(static::table());
1302
        }
1303
        if (!empty($options['group'])) {
1304
            $count = $result->getArray();
1305
            return $count;
1306
        } else {
1307
            $count = $result->fetch();
1308
            return $count['count'];
1309
        }
1310
    }
1311
1312
    /**
1313
     * Update records in data base
1314
     * 
1315
     * @param array $params
1316
     * @param array $where
1317
     * @return boolean
1318
     */
1319
    public static function update($params, $where = []) {
1320
        static::fixPrefix($params);
1321
1322
        $cols = self::cols();
1323
1324
        $values = [];
1325
        foreach ($cols as $col => $param) {
1326
            if (isset($params[$col])) {
1327
                $values[$col] = $params[$col];
1328
            }
1329
        }
1330
        if (empty($values)) {
1331
            return false;
1332
        }
1333
1334
        if (!empty($where)) {
1335
            static::fixPrefix($where, 'first');
1336
1337
            App::$cur->db->where($where);
1338
        }
1339
        App::$cur->db->update(static::table(), $values);
1340
    }
1341
1342
    /**
1343
     * Return primary key of object
1344
     * 
1345
     * @return mixed
1346
     */
1347 4
    public function pk() {
1348 4
        return $this->{$this->index()};
1349
    }
1350
1351
    /**
1352
     * Before save trigger
1353
     */
1354 4
    public function beforeSave() {
1355
        
1356 4
    }
1357
1358
    /**
1359
     * Save object to module storage
1360
     * 
1361
     * @param array $options
1362
     * @return boolean
1363
     */
1364 1
    public function saveModuleStorage($options) {
1365
1366 1
        $col = static::index();
1367 1
        $id = $this->pk();
1368 1
        $appType = '';
1369 1
        $classPath = explode('\\', get_called_class());
1370
1371 1 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1372
            $moduleConfig = Config::share($classPath[0]);
1373
        } else {
1374 1
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1375
        }
1376
1377 1 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1378 1
            if (empty($options['appType'])) {
1379
                $appType = App::$cur->type;
1380
            } else {
1381 1
                $appType = $options['appType'];
1382
            }
1383 1
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1384 1
        } else {
1385
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1386
        }
1387 1
        if (empty($storage[$classPath[1]])) {
1388
            $storage[$classPath[1]] = [];
1389
        }
1390 1
        if ($id) {
1391 View Code Duplication
            foreach ($storage[$classPath[1]] as $key => $item) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1392
                if ($item[$col] == $id) {
1393
                    $storage[$classPath[1]][$key] = $this->_params;
1394
                    break;
1395
                }
1396
            }
1397
        } else {
1398 1
            $id = !empty($storage['scheme'][$classPath[1]]['ai']) ? $storage['scheme'][$classPath[1]]['ai'] : 1;
1399 1
            $this->$col = $id;
1400 1
            $storage['scheme'][$classPath[1]]['ai'] = $id + 1;
1401 1
            $storage[$classPath[1]][] = $this->_params;
1402
        }
1403 1 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1404 1
            $moduleConfig['storage'][$appType] = $storage;
1405 1
        } else {
1406
            $moduleConfig['storage'] = $storage;
1407
        }
1408 1 View Code Duplication
        if (empty(static::$storage['options']['share'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1409 1
            Config::save('module', $moduleConfig, $classPath[0]);
1410 1
        } else {
1411
            Config::save('share', $moduleConfig, $classPath[0]);
1412
        }
1413 1
        return true;
1414
    }
1415
1416
    /**
1417
     * Update tree path category
1418
     */
1419
    public function changeCategoryTree() {
1420
        $class = get_class($this);
1421
        $itemModel = $class::$treeCategory;
1422
        $oldPath = $this->tree_path;
1423
        $this->tree_path = $this->getCatalogTree($this);
1424
        $itemsTable = \App::$cur->db->table_prefix . $itemModel::table();
1425
        $itemTreeCol = $itemModel::colPrefix() . 'tree_path';
1426
1427
        $categoryTreeCol = $this->colPrefix() . 'tree_path';
1428
        $categoryTable = \App::$cur->db->table_prefix . $this->table();
1429
        if ($oldPath) {
1430
            \App::$cur->db->query('UPDATE
1431
                ' . $categoryTable . ' 
1432
                    SET 
1433
                        ' . $categoryTreeCol . ' = REPLACE(' . $categoryTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1434
                    WHERE ' . $categoryTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1435
1436
            \App::$cur->db->query('UPDATE
1437
                ' . $itemsTable . '
1438
                    SET 
1439
                        ' . $itemTreeCol . ' = REPLACE(' . $itemTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1440
                    WHERE ' . $itemTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1441
        }
1442
        $itemModel::update([$itemTreeCol => $this->tree_path . $this->id . '/'], [$itemModel::colPrefix() . $this->index(), $this->id]);
1443
    }
1444
1445
    /**
1446
     * Return tree path
1447
     * 
1448
     * @param \Model $catalog
1449
     * @return string
1450
     */
1451
    public function getCatalogTree($catalog) {
1452
        $catalogClass = get_class($catalog);
1453
        $catalogParent = $catalogClass::get($catalog->parent_id);
1454
        if ($catalog && $catalogParent) {
1455
            if ($catalogParent->tree_path) {
1456
                return $catalogParent->tree_path . $catalogParent->id . '/';
1457
            } else {
1458
                return $this->getCatalogTree($catalogParent) . $catalogParent->id . '/';
1459
            }
1460
        }
1461
        return '/';
1462
    }
1463
1464
    /**
1465
     * Update tree path item
1466
     */
1467
    public function changeItemTree() {
1468
        $class = get_class($this);
1469
        $categoryModel = $class::$categoryModel;
1470
        $category = $categoryModel::get($this->{$categoryModel::index()});
1471
        if ($category) {
1472
            $this->tree_path = $category->tree_path . $category->pk() . '/';
1473
        } else {
1474
            $this->tree_path = '/';
1475
        }
1476
    }
1477
1478
    /**
1479
     * Save object to data base
1480
     * 
1481
     * @param array $options
1482
     * @return boolean|int
1483
     */
1484 4
    public function save($options = []) {
1485
1486 4
        if (static::$storage['type'] == 'moduleConfig') {
1487 1
            return static::saveModuleStorage($options);
1488
        }
1489 4
        $class = get_class($this);
1490 4
        if ($class::$categoryModel) {
1491
            $this->changeItemTree();
1492
        }
1493 4
        if ($class::$treeCategory) {
1494
            $this->changeCategoryTree();
1495
        }
1496 4
        if (!empty($this->_changedParams) && $this->pk()) {
1497 3
            Inji::$inst->event('modelItemParamsChanged-' . get_called_class(), $this);
1498 3
        }
1499 4
        $this->beforeSave();
1500 4
        $values = [];
1501
1502 4
        foreach ($this->cols() as $col => $param) {
1503 4
            if (isset($this->_params[$col])) {
1504 4
                $values[$col] = $this->_params[$col];
1505 4
            }
1506 4
        }
1507 4
        foreach ($class::$cols as $colName => $params) {
1508 4
            $class::fixPrefix($colName);
1509 4
            if (isset($params['default']) && !isset($values[$colName])) {
1510
                $this->_params[$colName] = $values[$colName] = $params['default'];
1511
            }
1512 4
        }
1513 4
        if (empty($values) && empty($options['empty'])) {
1514
            return false;
1515
        }
1516
1517 4
        if ($this->pk()) {
1518 3
            $new = false;
1519 3
            if ($this->get($this->_params[$this->index()])) {
1520 3
                App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1521 3
                App::$cur->db->update($this->table(), $values);
1522 3
            } else {
1523
1524
                $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1525
            }
1526 3
        } else {
1527 4
            $new = true;
1528 4
            $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1529
        }
1530 4
        $this->logChanges($new);
1531 4
        App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1532
        try {
1533 4
            $result = App::$cur->db->select($this->table());
1534 4
        } catch (PDOException $exc) {
1535
            if ($exc->getCode() == '42S02') {
1536
                $this->createTable();
1537
            }
1538
            $result = App::$cur->db->select($this->table());
1539
        }
1540 4
        $this->_params = $result->fetch();
1541 4
        if ($new) {
1542 4
            Inji::$inst->event('modelCreatedItem-' . get_called_class(), $this);
1543 4
        }
1544 4
        $this->afterSave();
1545 4
        return $this->{$this->index()};
1546
    }
1547
1548
    /**
1549
     * After save trigger
1550
     */
1551 4
    public function afterSave() {
1552
        
1553 4
    }
1554
1555
    /**
1556
     * Before delete trigger
1557
     */
1558 1
    public function beforeDelete() {
1559
        
1560 1
    }
1561
1562
    /**
1563
     * Delete item from module storage
1564
     * 
1565
     * @param array $options
1566
     * @return boolean
1567
     */
1568
    public function deleteFromModuleStorage($options) {
1569
1570
        $col = static::index();
1571
        $id = $this->pk();
1572
        $appType = '';
1573
        $classPath = explode('\\', get_called_class());
1574 View Code Duplication
        if (!empty(static::$storage['options']['share'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1575
            $moduleConfig = Config::share($classPath[0]);
1576
        } else {
1577
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1578
        }
1579
1580 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1581
            if (empty($options['appType'])) {
1582
                $appType = App::$cur->type;
1583
            } else {
1584
                $appType = $options['appType'];
1585
            }
1586
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1587
        } else {
1588
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1589
        }
1590
        if (empty($storage[$classPath[1]])) {
1591
            $storage[$classPath[1]] = [];
1592
        }
1593 View Code Duplication
        foreach ($storage[$classPath[1]] as $key => $item) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1594
1595
            if ($item[$col] == $id) {
1596
                unset($storage[$classPath[1]][$key]);
1597
                break;
1598
            }
1599
        }
1600 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1601
            $moduleConfig['storage'][$appType] = $storage;
1602
        } else {
1603
            $moduleConfig['storage'] = $storage;
1604
        }
1605 View Code Duplication
        if (empty(static::$storage['options']['share'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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

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

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

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

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

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

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