Test Failed
Push — master ( 47c2d9...dd4a4a )
by Alexey
04:51
created

Model::relations()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
172
     * @return string
173
     */
174
    public static function resloveTypeValue($item, $colName, $manageHref = false, $colInfo = []) {
175
        $modelName = get_class($item);
176
        if (!$colInfo) {
177
            $colInfo = $modelName::getColInfo($colName);
178
        }
179
        $type = !empty($colInfo['colParams']['type']) ? $colInfo['colParams']['type'] : 'string';
180
        $value = '';
181
        switch ($type) {
182
            case 'autocomplete':
183
                $options = $colInfo['colParams']['options'];
184 View Code Duplication
                if (isset($options['snippet']) && is_string($options['snippet'])) {
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...
185
                    $snippets = \App::$cur->Ui->getSnippets('autocomplete');
186
                    if (isset($snippets[$options['snippet']])) {
187
                        $value = $snippets[$options['snippet']]['getValueText']($item->$colName, $options['snippetParams']);
188
                    }
189
                }
190
                break;
191
            case 'select':
192
                switch ($colInfo['colParams']['source']) {
193
                    case 'model':
194
                        $sourceValue = '';
195
                        if ($item->$colName) {
196
                            $sourceValue = $colInfo['colParams']['model']::get($item->$colName);
197
                        }
198
                        $value = $sourceValue ? $sourceValue->name() : 'Не задано';
199
                        break;
200
                    case 'array':
201
                        $value = !empty($colInfo['colParams']['sourceArray'][$item->$colName]) ? $colInfo['colParams']['sourceArray'][$item->$colName] : 'Не задано';
202
                        if (is_array($value) && $value['text']) {
203
                            $value = $value['text'];
204
                        }
205
                        break;
206
                    case 'bool':
207
                        return $item->$colName ? 'Да' : 'Нет';
208
                    case 'method':
209 View Code Duplication
                        if (!empty($colInfo['colParams']['params'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
210
                            $values = call_user_func_array([App::$cur->$colInfo['colParams']['module'], $colInfo['colParams']['method']], $colInfo['colParams']['params']);
211
                        } else {
212
                            $values = \App::$cur->{$colInfo['colParams']['module']}->$colInfo['colParams']['method']();
213
                        }
214
                        $value = !empty($values[$item->$colName]) ? $values[$item->$colName] : 'Не задано';
215
                        break;
216
                    case 'void':
217
                        if (!empty($modelName::$cols[$colName]['value']['type']) && $modelName::$cols[$colName]['value']['type'] == 'moduleMethod') {
218
                            return \App::$cur->{$modelName::$cols[$colName]['value']['module']}->{$modelName::$cols[$colName]['value']['method']}($item, $colName, $modelName::$cols[$colName]);
219
                        }
220
                        break;
221
                    case 'relation':
222
                        if (strpos($colInfo['colParams']['relation'], ':')) {
223
                            $relationPath = explode(':', $colInfo['colParams']['relation']);
224
                            $relationName = array_pop($relationPath);
225
                            $curItem = $item;
226
                            foreach ($relationPath as $path) {
227
                                $curItem = $curItem->$path;
228
                            }
229
                            $itemModel = get_class($curItem);
230
                            $relation = $itemModel::getRelation($relationName);
231
                            $relModel = $relation['model'];
232
                        } else {
233
                            $itemModel = get_class($item);
234
                            $relation = $itemModel::getRelation($colInfo['colParams']['relation']);
235
                            $relModel = $relation['model'];
236
                        }
237
                        $relValue = $relModel::get($item->$colName);
238
                        $relModel = strpos($relModel, '\\') === 0 ? substr($relModel, 1) : $relModel;
239
                        if ($manageHref) {
240
                            $value = $relValue ? "<a href='/admin/" . str_replace('\\', '/view/', $relModel) . "/" . $relValue->pk() . "'>" . $relValue->name() . "</a>" : 'Не задано';
241
                        } else {
242
                            $value = $relValue ? $relValue->name() : 'Не задано';
243
                        }
244
                        break;
245
                }
246
                break;
247
            case 'image':
248
                $file = Files\File::get($item->$colName);
249
                if ($file) {
250
                    $photoId = Tools::randomString();
251
                    $value = '<a href = "' . $file->path . '" id="' . $photoId . '" rel="fgall[allimg]"><img src="' . $file->path . '?resize=60x120" /></a>';
252
                    $value .= '<script>inji.onLoad(function(){$("[rel]").fancybox();});</script>';
253
                } else {
254
                    $value = '<img src="/static/system/images/no-image.png?resize=60x120" />';
255
                }
256
                break;
257
            case 'file':
258
                $file = Files\File::get($item->$colName);
259
                if ($file) {
260
                    $value = '<a href="' . $file->path . '">' . $file->name . '.' . $file->type->ext . '</a>';
261
                } else {
262
                    $value = 'Файл не загружен';
263
                }
264
                break;
265
            case 'bool':
266
                $value = $item->$colName ? 'Да' : 'Нет';
267
                break;
268
            case 'void':
269
                if (!empty($colInfo['colParams']['value']['type']) && $colInfo['colParams']['value']['type'] == 'moduleMethod') {
270
                    return \App::$cur->{$colInfo['colParams']['value']['module']}->{$colInfo['colParams']['value']['method']}($item, $colName, $colInfo['colParams']);
271
                }
272
                break;
273
            case 'map':
274
                if ($item->$colName && json_decode($item->$colName, true)) {
275
                    $addres = json_decode($item->$colName, true);
276
                    $name = $addres['address'] ? $addres['address'] : 'lat:' . $addres['lat'] . ': lng:' . $addres['lng'];
277
                    \App::$cur->libs->loadLib('yandexMap');
278
                    ob_start();
279
                    $uid = Tools::randomString();
280
                    ?>
281
                    <div id='map<?= $uid; ?>_container' style="display:none;">
282
                        <script>/*
283
                             <div id='map<?= $uid; ?>' style="width: 100%; height: 500px"></div>
284
                             <script>
285
                             var myMap<?= $uid; ?>;
286
                             var myMap<?= $uid; ?>CurPin;
287
                             inji.onLoad(function () {
288
                             ymaps.ready(init<?= $uid; ?>);
289
                             function init<?= $uid; ?>() {
290
                             var myPlacemark;
291
                             myMap<?= $uid; ?> = new ymaps.Map("map<?= $uid; ?>", {
292
                             center: ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"],
293
                             zoom: 13
294
                             });
295
                             myCoords = ["<?= $addres['lat'] ?>", "<?= $addres['lng']; ?>"];
296
                             myMap<?= $uid; ?>CurPin = new ymaps.Placemark(myCoords,
297
                             {iconContent: "<?= $addres['address']; ?>"},
298
                             {preset: 'islands#greenStretchyIcon'}
299
                             );
300
                             myMap<?= $uid; ?>.geoObjects.add(myMap<?= $uid; ?>CurPin, 0);
301
                             }
302
                             window['init<?= $uid; ?>'] = init<?= $uid; ?>;
303
                             });
304
                             */</script>
305
                    </div>
306
                    <?php
307
                    $content = ob_get_contents();
308
                    ob_end_clean();
309
                    $onclick = 'inji.Ui.modals.show("' . addcslashes($addres['address'], '"') . '", $("#map' . $uid . '_container script").html().replace(/^\/\*/g, "").replace(/\*\/$/g, "")+"</script>","mapmodal' . $uid . '","modal-lg");';
310
                    $onclick .= 'return false;';
311
                    $value = "<a href ='#' onclick='{$onclick}' >{$name}</a>";
312
                    $value .= $content;
313
                } else {
314
                    $value = 'Местоположение не заданно';
315
                }
316
317
                break;
318
            case 'dynamicType':
319
                switch ($colInfo['colParams']['typeSource']) {
320
                    case 'selfMethod':
321
                        $type = $item->{$colInfo['colParams']['selfMethod']}();
322
                        if (is_array($type)) {
323
                            $value = static::resloveTypeValue($item, $colName, $manageHref, ['colParams' => $type]);
324
                        } else {
325
                            $value = static::resloveTypeValue($item, $colName, $manageHref, ['colParams' => ['type' => $type]]);
326
                        }
327
                        break;
328
                }
329
                break;
330
            default:
331
                $value = $item->$colName;
332
        }
333
        return $value;
334
    }
335
336
    /**
337
     * Fix col prefix
338
     *
339
     * @param mixed $array
340
     * @param string $searchtype
341
     * @param string $rootModel
342
     * @return null
343
     */
344
    public static function fixPrefix(&$array, $searchtype = 'key', $rootModel = '') {
345
        if (!$rootModel) {
346
            $rootModel = get_called_class();
347
        }
348
        $cols = static::cols();
349
        if (!$array) {
350
            return;
351
        }
352
        if (!is_array($array)) {
353 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...
354
                static::createCol($array);
355
                $cols = static::cols(true);
356
            }
357
            if (!isset($cols[$array]) && isset($cols[static::colPrefix() . $array])) {
358
                $array = static::colPrefix() . $array;
359
            } else {
360
                static::checkForJoin($array, $rootModel);
361
            }
362
            return;
363
        }
364
        switch ($searchtype) {
365
            case 'key':
366
                foreach ($array as $key => $item) {
367 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...
368
                        static::createCol($key);
369
                        $cols = static::cols(true);
370
                    }
371
                    if (!isset($cols[$key]) && isset($cols[static::colPrefix() . $key])) {
372
                        $array[static::colPrefix() . $key] = $item;
373
                        unset($array[$key]);
374
                        $key = static::colPrefix() . $key;
375
                    }
376
                    if (is_array($array[$key])) {
377
                        static::fixPrefix($array[$key], 'key', $rootModel);
378
                    } else {
379
                        static::checkForJoin($key, $rootModel);
380
                    }
381
                }
382 4
                break;
383 4
            case 'first':
384 4
                if (isset($array[0]) && is_string($array[0])) {
385 4
                    if (!isset($cols[static::colPrefix() . $array[0]]) && isset(static::$cols[$array[0]])) {
386 4
                        static::createCol($array[0]);
387 4
                        $cols = static::cols(true);
388
                    }
389 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...
390 4
                        $array[0] = static::colPrefix() . $array[0];
391 4
                    } else {
392 2
                        static::checkForJoin($array[0], $rootModel);
393 2
                    }
394 2
                } elseif (isset($array[0]) && is_array($array[0])) {
395 4
                    foreach ($array as &$item) {
396 4
                        static::fixPrefix($item, 'first', $rootModel);
397 4
                    }
398 4
                }
399
                break;
400 4
        }
401
    }
402
403 1
    /**
404
     * @param boolean $new
405
     */
406
    public function logChanges($new) {
407
        if (!App::$cur->db->connect || !App::$cur->dashboard) {
408
            return false;
409
        }
410
        $class = get_class($this);
411
        if (!Model::$logging || !$class::$logging) {
412
            return false;
413
        }
414
        $user_id = class_exists('Users\User') ? \Users\User::$cur->id : 0;
415
        if (!$new && !empty($this->_changedParams)) {
416
            $activity = new Dashboard\Activity([
417
                'user_id' => $user_id,
418
                'module' => substr($class, 0, strpos($class, '\\')),
419
                'model' => $class,
420
                'item_id' => $this->pk(),
421 1
                'type' => 'changes'
422 1
            ]);
423 1
            $changes_text = [];
424
            foreach ($this->_changedParams as $fullColName => $oldValue) {
425
                $colName = substr($fullColName, strlen($class::colPrefix()));
426 View Code Duplication
                if (isset($class::$cols[$colName]['logging']) && !$class::$cols[$colName]['logging']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
427 1
                    continue;
428 1
                }
429 1
                $oldValueText = $oldValue;
430
                if (isset($class::$cols[$colName]) && $class::$cols[$colName]['type'] === 'select') {
431
                    switch ($class::$cols[$colName]['source']) {
432 1
                        case 'array':
433 1
                            $oldValueText = isset($class::$cols[$colName]['sourceArray'][$oldValue]) ? $class::$cols[$colName]['sourceArray'][$oldValue] : $oldValue;
434 1
                            break;
435 1 View Code Duplication
                        case '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...
436 1
                            $relation = $class::getRelation($class::$cols[$colName]['relation']);
437 1
                            $relModel = $relation['model'];
438
                            $rel = $relModel::get($oldValue);
439 1
                            if ($rel) {
440
                                $oldValueText = $rel->name();
441
                            }
442
                    }
443
                }
444 4
                $newValueText = $this->$colName;
445 4
                if (isset($class::$cols[$colName]) && $class::$cols[$colName]['type'] === 'select') {
446
                    switch ($class::$cols[$colName]['source']) {
447
                        case 'array':
448 4
                            $newValueText = isset($class::$cols[$colName]['sourceArray'][$this->$colName]) ? $class::$cols[$colName]['sourceArray'][$this->$colName] : $this->$colName;
449 4
                            break;
450 4 View Code Duplication
                        case '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...
451
                            $relation = $class::getRelation($class::$cols[$colName]['relation']);
452 2
                            $relModel = $relation['model'];
453 2
                            $rel = $relModel::get($this->$colName);
454
                            if ($rel) {
455
                                $newValueText = $rel->name();
456
                            }
457
                    }
458
                }
459
                if (strlen($oldValueText) + strlen($newValueText) < 200) {
460
                    $changes_text[] = (!empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName) . ": \"{$oldValueText}\" => \"{$newValueText}\"";
461
                } else {
462
                    $changes_text[] = !empty($class::$labels[$colName]) ? $class::$labels[$colName] : $colName;
463
                }
464
            }
465
            if (!$changes_text) {
466
                return false;
467
            }
468
            $activity->changes_text = implode(', ', $changes_text);
469
            $activity->save();
470
            foreach ($this->_changedParams as $fullColName => $oldValue) {
471
                $colName = substr($fullColName, strlen($class::colPrefix()));
472 View Code Duplication
                if (isset($class::$cols[$colName]['logging']) && !$class::$cols[$colName]['logging']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
473
                    continue;
474
                }
475
                $colName = substr($fullColName, strlen($class::colPrefix()));
476
                $change = new Dashboard\Activity\Change([
477
                    'activity_id' => $activity->id,
478
                    'col' => $colName,
479
                    'old' => $oldValue,
480
                    'new' => $this->$colName
481
                ]);
482
                $change->save();
483
            }
484
        } elseif ($new) {
485
            $activity = new Dashboard\Activity([
486
                'user_id' => $user_id,
487
                'module' => substr($class, 0, strpos($class, '\\')),
488
                'model' => $class,
489
                'item_id' => $this->pk(),
490
                'type' => 'new'
491
            ]);
492 2
            $activity->save();
493 2
        }
494 2
        return true;
495 2
    }
496 2
497 2
    /**
498
     * Check model relations path and load need relations
499 2
     *
500 2
     * @param string $col
501 2
     * @param string $rootModel
502 2
     */
503
    public static function checkForJoin(&$col, $rootModel) {
504
505
        if (strpos($col, ':') !== false) {
506
            $relations = static::relations();
507
            if (isset($relations[substr($col, 0, strpos($col, ':'))])) {
508
                $rel = substr($col, 0, strpos($col, ':'));
509
                $col = substr($col, strpos($col, ':') + 1);
510
511 4
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
512
                switch ($type) {
513 4 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...
514
                        $relCol = $relations[$rel]['col'];
515
                        static::fixPrefix($relCol);
516
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
517
                        break;
518
                    case 'one':
519 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...
520
                        $relCol = $relations[$rel]['col'];
521
                        $relations[$rel]['model']::fixPrefix($relCol);
522
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
523
                        break;
524
                }
525
                $relations[$rel]['model']::fixPrefix($col, 'key', $rootModel);
526
            }
527
        }
528
    }
529
530
    /**
531
     * Return full col information
532
     *
533
     * @param string $col
534
     * @return array
535
     */
536 4
    public static function getColInfo($col) {
537
        return static::parseColRecursion($col);
538
    }
539
540
    /**
541
     * Information extractor for col relations path
542
     *
543
     * @param string $info
544
     * @return array
545
     */
546
    public static function parseColRecursion($info) {
547
        if (is_string($info)) {
548
            $info = ['col' => $info, 'rawCol' => $info, 'modelName' => '', 'label' => '', 'joins' => []];
549
        }
550
        if (strpos($info['col'], ':') !== false) {
551
            $relations = static::relations();
552
            if (isset($relations[substr($info['col'], 0, strpos($info['col'], ':'))])) {
553
                $rel = substr($info['col'], 0, strpos($info['col'], ':'));
554
                $info['col'] = substr($info['col'], strpos($info['col'], ':') + 1);
555
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
556
                switch ($type) {
557 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...
558
                        $relCol = $relations[$rel]['col'];
559
                        static::fixPrefix($relCol);
560
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
561
                        break;
562 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...
563
                        $relCol = $relations[$rel]['col'];
564
                        $relations[$rel]['model']::fixPrefix($relCol);
565
                        $info['joins'][$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
566
                        break;
567
                }
568
                $info = $relations[$rel]['model']::parseColRecursion($info);
569
            }
570
        } else {
571
            $cols = static::cols();
572 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...
573
                $info['label'] = static::$labels[$info['col']];
574
            }
575
576
            if (isset(static::$cols[$info['col']])) {
577
                $info['colParams'] = static::$cols[$info['col']];
578
            } elseif (isset(static::$cols[str_replace(static::colPrefix(), '', $info['col'])])) {
579
                $info['colParams'] = static::$cols[str_replace(static::colPrefix(), '', $info['col'])];
580
            } else {
581
                $info['colParams'] = [];
582
            }
583 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...
584
                $info['col'] = static::colPrefix() . $info['col'];
585
            }
586
            $info['modelName'] = get_called_class();
587
        }
588 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...
589
            $info['label'] = static::$labels[$info['rawCol']];
590
        }
591
        return $info;
592
    }
593
594
    /**
595
     * Return actual cols from data base
596
     *
597
     * @param boolean $refresh
598
     * @return array
599
     */
600
    public static function cols($refresh = false) {
601
        if (static::$storage['type'] == 'moduleConfig') {
602
            return [];
603
        }
604 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...
605
            Model::$cols[static::table()] = App::$cur->db->getTableCols(static::table());
606
        }
607 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...
608 4
            static::createTable();
609 4
            Model::$cols[static::table()] = App::$cur->db->getTableCols(static::table());
610 1
        }
611
        return Model::$cols[static::table()];
612 4
    }
613 4
614 4
    /**
615 4
     * Return cols indexes for create tables
616
     *
617
     * @return array
618
     */
619 4
    public static function indexes() {
620
        return [];
621
    }
622
623
    /**
624
     * Generate params string for col by name
625
     *
626
     * @param string $colName
627 3
     * @return false|string
628 3
     */
629
    public static function genColParams($colName) {
630
        if (empty(static::$cols[$colName]) || static::$storage['type'] == 'moduleConfig') {
631
            return false;
632
        }
633
        $null = ' NULL';
634
        if (empty(static::$cols[$colName]['null'])) {
635
            $null = ' NOT NULL';
636
        }
637 4
638 4
        $params = false;
639 1
        switch (static::$cols[$colName]['type']) {
640
            case 'select':
641 4
                switch (static::$cols[$colName]['source']) {
642 4
                    case 'relation':
643 4
                        $params = 'int(11) UNSIGNED' . $null;
644 4
                        break;
645
                    default:
646 4
                        $params = 'varchar(255)' . $null;
647 4
                }
648 4
                break;
649 4
            case 'image':
650 4
            case 'file':
651 4
                $params = 'int(11) UNSIGNED' . $null;
652 4
                break;
653 1
            case 'number':
654 1
                $params = 'int(11)' . $null;
655 4
                break;
656 4
            case 'text':
657 4
            case 'email':
658 4
                $params = 'varchar(255)' . $null;
659 1
                break;
660 1
            case 'html':
661 4
            case 'textarea':
662
            case 'json':
663
            case 'password':
664 4
            case 'dynamicType':
665 4
            case 'map':
666 3
                $params = 'text' . $null;
667 3
                break;
668 3
            case 'bool':
669 3
                $params = 'tinyint(1) UNSIGNED' . $null;
670 3
                break;
671 3
            case 'decimal':
672 3
                $params = 'decimal(8, 2)' . $null;
673 3
                break;
674 1
            case 'time':
675 1
                $params = 'time' . $null;
676 3
                break;
677 1
            case 'date':
678 1
                $params = 'date' . $null;
679 3
                break;
680
            case 'dateTime':
681
                $params = 'timestamp' . $null;
682 3
                break;
683 1
        }
684 1
        return $params;
685 3
    }
686 2
687 2
    /**
688 4
     * Create new col in data base
689 4
     *
690
     * @param string $colName
691
     * @return boolean|integer
692
     */
693
    public static function createCol($colName) {
694
        $cols = static::cols(true);
695
        if (!empty($cols[static::colPrefix() . $colName])) {
696
            return true;
697
        }
698 2
        $params = static::genColParams($colName);
699 2
        if ($params === false) {
700 2
            return false;
701
        }
702
        return App::$cur->db->addCol(static::table(), static::colPrefix() . $colName, $params);
703 2
    }
704 2
705 2
    public static function createTable() {
706
        if (static::$storage['type'] == 'moduleConfig') {
707
            return true;
708
        }
709
        if (!App::$cur->db) {
710 4
            return false;
711 4
        }
712
713
        $query = App::$cur->db->newQuery();
714 4
        if (!$query) {
715
            return false;
716
        }
717
718 4
        if (!isset($this)) {
719 4
            $tableName = static::table();
720
            $colPrefix = static::colPrefix();
721
            $indexes = static::indexes();
722
        } else {
723 4
            $tableName = $this->table();
724 4
            $colPrefix = $this->colPrefix();
725 4
            $indexes = $this->indexes();
726 4
        }
727 4
        if (App::$cur->db->tableExist($tableName)) {
728
            return true;
729
        }
730
        $cols = [
731
            $colPrefix . 'id' => 'pk'
732 4
        ];
733
        $className = get_called_class();
734
        if (!empty($className::$cols)) {
735
            foreach ($className::$cols as $colName => $colParams) {
736 4
                if ($colName == 'date_create') {
737 4
                    $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
738 4
                    continue;
739 4
                }
740 4
                $params = $className::genColParams($colName);
741 4
                if ($params) {
742 4
                    $cols[$colPrefix . $colName] = $params;
743 4
                }
744
            }
745 4
        }
746 4
        if (empty($cols[$colPrefix . 'date_create'])) {
747 4
            $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
748 4
        }
749 4
        $tableIndexes = [];
750 4
        if ($indexes) {
751 4
            foreach ($indexes as $indexName => $index) {
752 1
                $tableIndexes[] = $index['type'] . ' ' . App::$cur->db->table_prefix . $indexName . ' (' . implode(',', $index['cols']) . ')';
753 1
            }
754 4
        }
755 4
756 1
        $query->createTable($tableName, $cols, $tableIndexes);
757 1
        return true;
758 1
    }
759 1
760
    /**
761 4
     * Return table name
762 4
     *
763
     * @return string
764
     */
765
    public static function table() {
766
        return strtolower(str_replace('\\', '_', get_called_class()));
767
    }
768
769
    /**
770 4
     * Return table index col name
771 4
     *
772
     * @return string
773
     */
774
    public static function index() {
775
776
        return static::colPrefix() . 'id';
777
    }
778
779 4
    /**
780
     * Return col prefix
781 4
     *
782
     * @return string
783
     */
784
    public static function colPrefix() {
785
        $classPath = explode('\\', get_called_class());
786
        $classPath = array_slice($classPath, 1);
787
        return strtolower(implode('_', $classPath)) . '_';
788
    }
789 4
790 4
    /**
791 4
     * return relations list
792 4
     *
793
     * @return string
794
     */
795
    public static function relations() {
796
        return [];
797
    }
798
799
    /**
800 1
     * views list
801 1
     *
802
     * @return array
803
     */
804
    public static $views = [];
805
806
    /**
807
     * Return name of col with object name
808
     *
809
     * @return string
810
     */
811
    public static function nameCol() {
812
        return 'name';
813
    }
814
815
    /**
816
     * Return object name
817
     *
818
     * @return string
819
     */
820
    public function name() {
821
        return $this->{$this->nameCol()} ? $this->{$this->nameCol()} : '№' . $this->pk();
822
    }
823
824
    /**
825
     * Get single object from data base
826
     *
827
     * @param mixed $param
828
     * @param string $col
829
     * @param array $options
830
     * @return boolean|static
831
     */
832
    public static function get($param, $col = null, $options = []) {
833
        if (static::$storage['type'] == 'moduleConfig') {
834
            return static::getFromModuleStorage($param, $col, $options);
835
        }
836
        if (!empty($col)) {
837 4
            static::fixPrefix($col);
838 4
        }
839
840
        if (is_array($param)) {
841 4
            static::fixPrefix($param, 'first');
842 4
        }
843 4
        foreach (static::$relJoins as $join) {
844
            App::$cur->db->join($join[0], $join[1]);
845 4
        }
846 1
        static::$relJoins = [];
847 1
        foreach (static::$needJoin as $rel) {
848 4
            $relations = static::relations();
849
            if (isset($relations[$rel])) {
850 4
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
851 4
                switch ($type) {
852 4
                    case 'to':
853
                        $relCol = $relations[$rel]['col'];
854
                        static::fixPrefix($relCol);
855
                        App::$cur->db->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
856
                        break;
857
                    case 'one':
858
                        $col = $relations[$rel]['col'];
859
                        $relations[$rel]['model']::fixPrefix($col);
860
                        App::$cur->db->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
861
                        break;
862
                }
863
            }
864
        }
865
        static::$needJoin = [];
866
        if (is_array($param)) {
867
            App::$cur->db->where($param);
868
        } else {
869 4
            if ($col === null) {
870 4
871 4
                $col = static::index();
872 1
            }
873 1
            if ($param !== null) {
874 4
                $cols = static::cols();
875
                if (!isset($cols[$col]) && isset($cols[static::colPrefix() . $col])) {
876 3
                    $col = static::colPrefix() . $col;
877 3
                }
878 4
                App::$cur->db->where($col, $param);
879 4
            } else {
880 4
                return false;
881
            }
882
        }
883 4
        if (!App::$cur->db->where) {
884 4
            return false;
885
        }
886
        try {
887
            $result = App::$cur->db->select(static::table());
888 4
        } catch (PDOException $exc) {
889
            if ($exc->getCode() == '42S02') {
890
                static::createTable();
891
            } else {
892 4
                throw $exc;
893 4
            }
894
            $result = App::$cur->db->select(static::table());
895
        }
896
        if (!$result) {
897
            return false;
898
        }
899
        return $result->fetch(get_called_class());
900
    }
901 4
902
    /**
903
     * Old method
904 4
     *
905
     * @param type $options
906
     * @return Array
907
     */
908
    public static function get_list($options = [], $debug = false) {
909
        $query = App::$cur->db->newQuery();
910
        if (!$query) {
911
            return [];
912
        }
913
        if (!empty($options['where'])) {
914
            $query->where($options['where']);
915
        }
916
        if (!empty($options['cols'])) {
917
            $query->cols = $options['cols'];
918
        }
919
        if (!empty($options['group'])) {
920
            $query->group($options['group']);
921
        }
922
        if (!empty($options['having'])) {
923
            $query->having($options['having']);
924
        }
925
        if (!empty($options['order'])) {
926
            $query->order($options['order']);
927
        }
928
        if (!empty($options['join'])) {
929
            $query->join($options['join']);
930
        }
931
        if (!empty($options['distinct'])) {
932
            $query->distinct = $options['distinct'];
933
        }
934
935
        foreach (static::$relJoins as $join) {
936
            $query->join($join[0], $join[1]);
937
        }
938
        static::$relJoins = [];
939 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...
940
            $relations = static::relations();
941
            if (isset($relations[$rel])) {
942
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
943
                switch ($type) {
944
                    case 'to':
945
                        $relCol = $relations[$rel]['col'];
946
                        static::fixPrefix($relCol);
947
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
948
                        break;
949
                    case 'one':
950
                        $col = $relations[$rel]['col'];
951
                        $relations[$rel]['model']::fixPrefix($col);
952
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
953
                        break;
954
                }
955
            }
956
        }
957
        static::$needJoin = [];
958
959 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...
960
            $limit = (int) $options['limit'];
961
        } else {
962
            $limit = 0;
963
        }
964 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...
965
            $start = (int) $options['start'];
966
        } else {
967
            $start = 0;
968
        }
969
        if ($limit || $start) {
970
            $query->limit($start, $limit);
971
        }
972
        if (isset($options['key'])) {
973
            $key = $options['key'];
974
        } else {
975
            $key = static::index();
976
        }
977
978
        if ($debug) {
979
            $query->operation = 'SELECT';
980
            $query->table = static::table();
981
            return $query->buildQuery();
982
        }
983
        try {
984
            $query->operation = 'SELECT';
985
            $query->table = static::table();
986
            $queryArr = $query->buildQuery();
987
            $result = $query->query($queryArr);
988
        } catch (PDOException $exc) {
989
            if ($exc->getCode() == '42S02') {
990
                static::createTable();
991
                $result = $query->query($queryArr);
992
            } else {
993
                throw $exc;
994
            }
995
        }
996
997
        if (!empty($options['array'])) {
998
            return $result->getArray($key);
999
        }
1000
        $list = $result->getObjects(get_called_class(), $key);
1001 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...
1002
            $return = [];
1003
            foreach ($list as $key => $item) {
1004
                $return[$key] = $item->name();
1005
            }
1006
            return $return;
1007
        }
1008
        return $list;
1009
    }
1010
1011
    /**
1012
     * Return list of objects from data base
1013
     *
1014
     * @param array $options
1015
     * @return static[]
1016
     */
1017
    public static function getList($options = [], $debug = false) {
1018
        if (static::$storage['type'] != 'db') {
1019
            return static::getListFromModuleStorage($options);
1020
        }
1021
        if (!empty($options['where'])) {
1022
            static::fixPrefix($options['where'], 'first');
1023
        }
1024
        if (!empty($options['group'])) {
1025
            static::fixPrefix($options['group'], 'first');
1026
        }
1027
        if (!empty($options['order'])) {
1028
            static::fixPrefix($options['order'], 'first');
1029
        }
1030
        if (!empty($options['having'])) {
1031
            static::fixPrefix($options['having'], 'first');
1032
        }
1033
        return static::get_list($options, $debug);
1034
    }
1035
1036
    /**
1037
     * Get single item from module storage
1038
     *
1039
     * @param array $param
1040
     * @param string $col
1041
     * @param array $options
1042
     * @return boolean|\Model
1043
     */
1044
    public static function getFromModuleStorage($param = null, $col = null, $options = []) {
1045
        if ($col === null) {
1046
1047
            $col = static::index();
1048
        }
1049
        if ($param == null) {
1050
            return false;
1051
        }
1052
        $classPath = explode('\\', get_called_class());
1053 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...
1054
            $moduleConfig = Config::share($classPath[0]);
1055
        } else {
1056
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1057
        }
1058
        $appType = App::$cur->type;
1059 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...
1060
            if (!empty($options['appType'])) {
1061
                $appType = $options['appType'];
1062
            }
1063
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1064
        } else {
1065
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1066
        }
1067
        if (!empty($storage[$classPath[1]])) {
1068
            $items = $storage[$classPath[1]];
1069
            $class = get_called_class();
1070
            $where = is_array($param) ? $param : [$col, $param];
1071
            foreach ($items as $key => $item) {
1072
                if (!Model::checkWhere($item, $where)) {
1073
                    continue;
1074
                }
1075
                if (!empty($options['array'])) {
1076
                    return $item;
1077
                }
1078
                $item = new $class($item);
1079
                $item->appType = $appType;
1080
                return $item;
1081
            }
1082
        }
1083
        return false;
1084
    }
1085
1086
    /**
1087
     * Return list items from module storage
1088
     *
1089
     * @param array $options
1090
     * @return array
1091
     */
1092
    public static function getListFromModuleStorage($options = []) {
1093
        $classPath = explode('\\', get_called_class());
1094 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...
1095
            $moduleConfig = Config::share($classPath[0]);
1096
        } else {
1097
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1098
        }
1099 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...
1100
            if (empty($options['appType'])) {
1101
                $appType = App::$cur->type;
1102
            } else {
1103
                $appType = $options['appType'];
1104
            }
1105
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1106
        } else {
1107
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1108
        }
1109
        if (!empty($storage[$classPath[1]])) {
1110
            $items = [];
1111
            $class = get_called_class();
1112
            if (isset($options['key'])) {
1113
                $arrayKey = $options['key'];
1114
            } else {
1115
                $arrayKey = static::index();
1116
            }
1117
            foreach ($storage[$classPath[1]] as $key => $item) {
1118
                if (!empty($options['where']) && !Model::checkWhere($item, $options['where'])) {
1119
                    continue;
1120
                }
1121
                $items[$item[$arrayKey]] = new $class($item);
1122
            }
1123
            if (!empty($options['order'])) {
1124
                usort($items, function ($a, $b) use ($options) {
1125
                    if ($a->{$options['order'][0]} > $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1126
                        return 1;
1127
                    } elseif ($a->{$options['order'][0]} < $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
1128
                        return -1;
1129
                    } elseif ($a->{$options['order'][0]} == $b->{$options['order'][0]} && $a->id > $b->id) {
1130
                        return 1;
1131
                    } elseif ($a->{$options['order'][0]} == $b->{$options['order'][0]} && $a->id < $b->id) {
1132
                        return -1;
1133
                    }
1134
                    return 0;
1135
                });
1136
            }
1137 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...
1138
                $return = [];
1139
                foreach ($items as $key => $item) {
1140
                    $return[$key] = $item->name();
1141
                }
1142
                return $return;
1143
            }
1144
            return $items;
1145
        }
1146
        return [];
1147
    }
1148
1149
    /**
1150
     * Return count of records from module storage
1151
     *
1152
     * @param array $options
1153
     * @return int
1154
     */
1155
    public static function getCountFromModuleStorage($options = []) {
1156
1157
        $classPath = explode('\\', get_called_class());
1158
        $count = 0;
1159
        if (empty($options['appType'])) {
1160
            $appType = App::$cur->type;
1161
        } else {
1162
            $appType = $options['appType'];
1163
        }
1164 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...
1165
            $moduleConfig = Config::share($classPath[0]);
1166
        } else {
1167
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1168
        }
1169
        if (!empty($moduleConfig['storage'][$appType][$classPath[1]])) {
1170
            $items = $moduleConfig['storage'][$appType][$classPath[1]];
1171
            if (empty($options['where'])) {
1172
                return count($items);
1173
            }
1174
            foreach ($items as $key => $item) {
1175
                if (!empty($options['where'])) {
1176
                    if (Model::checkWhere($item, $options['where'])) {
1177
                        $count++;
1178
                    }
1179
                } else {
1180
                    $count++;
1181
                }
1182
            }
1183
        }
1184
        return $count;
1185
    }
1186
1187
    /**
1188
     * Check where for module storage query
1189
     *
1190
     * @param array $item
1191
     * @param array|string $where
1192
     * @param string $value
1193
     * @param string $operation
1194
     * @param string $concatenation
1195
     * @return boolean
1196
     */
1197
    public static function checkWhere($item = [], $where = '', $value = '', $operation = '=', $concatenation = 'AND') {
1198
1199
        if (is_array($where)) {
1200
            if (is_array($where[0])) {
1201
                $result = true;
1202
                foreach ($where as $key => $whereItem) {
1203
                    $concatenation = empty($whereItem[3]) ? 'AND' : strtoupper($whereItem[3]);
1204
                    switch ($concatenation) {
1205 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...
1206
                            $result = $result && forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1207
                            break;
1208 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...
1209
                            $result = $result || forward_static_call_array(['Model', 'checkWhere'], [$item, $whereItem]);
1210
                            break;
1211
                    }
1212
                }
1213
1214
                return $result;
1215
            } else {
1216
                return forward_static_call_array(['Model', 'checkWhere'], array_merge([$item], $where));
1217
            }
1218
        }
1219
        if (!isset($item[$where]) && !$value) {
1220
            return true;
1221
        }
1222
        if (!isset($item[$where]) && $value) {
1223
            return false;
1224
        }
1225
        if ($item[$where] == $value) {
1226
            return true;
1227
        }
1228
        return false;
1229
    }
1230
1231
    /**
1232
     * Return count of records from data base
1233
     *
1234
     * @param array $options
1235
     * @return array|int
1236
     */
1237
    public static function getCount($options = []) {
1238
        if (static::$storage['type'] == 'moduleConfig') {
1239
            return static::getCountFromModuleStorage($options);
1240
        }
1241
        $query = App::$cur->db->newQuery();
1242
        if (!$query) {
1243
            return 0;
1244
        }
1245
        if (!empty($options['where'])) {
1246
            static::fixPrefix($options['where'], 'first');
1247
        }
1248
        if (!empty($options['group'])) {
1249
            static::fixPrefix($options['group'], 'first');
1250
        }
1251
        if (!empty($options['order'])) {
1252
            static::fixPrefix($options['order'], 'first');
1253
        }
1254
        if (!empty($options['where'])) {
1255
            $query->where($options['where']);
1256
        }
1257
        if (!empty($options['join'])) {
1258
            $query->join($options['join']);
1259
        }
1260
        if (!empty($options['order'])) {
1261
            $query->order($options['order']);
1262
        }
1263 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...
1264
            $limit = (int) $options['limit'];
1265
        } else {
1266
            $limit = 0;
1267
        }
1268 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...
1269
            $start = (int) $options['start'];
1270
        } else {
1271
            $start = 0;
1272
        }
1273
        if ($limit || $start) {
1274
            $query->limit($start, $limit);
1275
        }
1276
1277
        foreach (static::$relJoins as $join) {
1278
            $query->join($join[0], $join[1]);
1279
        }
1280
        static::$relJoins = [];
1281 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...
1282
            $relations = static::relations();
1283
            if (isset($relations[$rel])) {
1284
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
1285
                switch ($type) {
1286
                    case 'to':
1287
                        $relCol = $relations[$rel]['col'];
1288
                        static::fixPrefix($relCol);
1289
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
1290
                        break;
1291
                    case 'one':
1292
                        $col = $relations[$rel]['col'];
1293
                        $relations[$rel]['model']::fixPrefix($col);
1294
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
1295
                        break;
1296
                }
1297
            }
1298
        }
1299
        static::$needJoin = [];
1300
        $cols = 'COUNT(';
1301
1302
        if (!empty($options['distinct'])) {
1303
            if (is_bool($options['distinct'])) {
1304
                $cols .= 'DISTINCT *';
1305
            } else {
1306
                $cols .= "DISTINCT {$options['distinct']}";
1307
            }
1308
        } else {
1309
            $cols .= '*';
1310
        }
1311
        $cols .= ') as `count`' . (!empty($options['cols']) ? ',' . $options['cols'] : '');
1312
        $query->cols = $cols;
1313
        if (!empty($options['group'])) {
1314
            $query->group($options['group']);
1315
        }
1316
        try {
1317
            $result = $query->select(static::table());
1318
        } catch (PDOException $exc) {
1319
            if ($exc->getCode() == '42S02') {
1320
                static::createTable();
1321
            } else {
1322
                throw $exc;
1323
            }
1324
            $result = $query->select(static::table());
1325
        }
1326
        if (!empty($options['group'])) {
1327
            $count = $result->getArray();
1328
            return $count;
1329
        } else {
1330
            $count = $result->fetch();
1331
            return $count['count'];
1332
        }
1333
    }
1334
1335
    /**
1336
     * Update records in data base
1337
     *
1338
     * @param array $params
1339
     * @param array $where
1340
     * @return false|null
1341
     */
1342
    public static function update($params, $where = []) {
1343
        static::fixPrefix($params);
1344
1345
        $cols = self::cols();
1346
1347
        $values = [];
1348
        foreach ($cols as $col => $param) {
1349
            if (isset($params[$col])) {
1350
                $values[$col] = $params[$col];
1351
            }
1352
        }
1353
        if (empty($values)) {
1354
            return false;
1355
        }
1356
1357
        if (!empty($where)) {
1358
            static::fixPrefix($where, 'first');
1359
1360
            App::$cur->db->where($where);
1361
        }
1362
        App::$cur->db->update(static::table(), $values);
1363
    }
1364
1365 4
    /**
1366 4
     * Return primary key of object
1367
     *
1368
     * @return mixed
1369
     */
1370
    public function pk() {
1371
        return $this->{$this->index()};
1372 4
    }
1373
1374 4
    /**
1375
     * Before save trigger
1376
     */
1377
    public function beforeSave() {
1378
1379
    }
1380
1381
    /**
1382 1
     * Save object to module storage
1383
     *
1384 1
     * @param array $options
1385 1
     * @return boolean
1386 1
     */
1387 1
    public function saveModuleStorage($options) {
1388
1389 1
        $col = static::index();
1390
        $id = $this->pk();
1391
        $appType = '';
1392 1
        $classPath = explode('\\', get_called_class());
1393
1394 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...
1395 1
            $moduleConfig = Config::share($classPath[0]);
1396 1
        } else {
1397
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1398
        }
1399 1
1400 View Code Duplication
        if (!empty($moduleConfig['storage']['appTypeSplit'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1401 1
            if (empty($options['appType'])) {
1402 1
                $appType = App::$cur->type;
1403
            } else {
1404
                $appType = $options['appType'];
1405 1
            }
1406
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1407
        } else {
1408 1
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1409
        }
1410
        if (empty($storage[$classPath[1]])) {
1411
            $storage[$classPath[1]] = [];
1412
        }
1413
        if ($id) {
1414 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...
1415
                if ($item[$col] == $id) {
1416 1
                    $storage[$classPath[1]][$key] = $this->_params;
1417 1
                    break;
1418 1
                }
1419 1
            }
1420
        } else {
1421 1
            $id = !empty($storage['scheme'][$classPath[1]]['ai']) ? $storage['scheme'][$classPath[1]]['ai'] : 1;
1422 1
            $this->$col = $id;
1423 1
            $storage['scheme'][$classPath[1]]['ai'] = $id + 1;
1424
            $storage[$classPath[1]][] = $this->_params;
1425
        }
1426 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...
1427 1
            $moduleConfig['storage'][$appType] = $storage;
1428 1
        } else {
1429
            $moduleConfig['storage'] = $storage;
1430
        }
1431 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...
1432
            Config::save('module', $moduleConfig, $classPath[0]);
1433
        } else {
1434
            Config::save('share', $moduleConfig, $classPath[0]);
1435
        }
1436
        return true;
1437
    }
1438
1439
    /**
1440
     * Update tree path category
1441
     */
1442
    public function changeCategoryTree() {
1443
        $class = get_class($this);
1444
        $itemModel = $class::$treeCategory;
1445
        $oldPath = $this->tree_path;
1446
        $this->tree_path = $this->getCatalogTree($this);
1447
        $itemsTable = \App::$cur->db->table_prefix . $itemModel::table();
1448
        $itemTreeCol = $itemModel::colPrefix() . 'tree_path';
1449
1450
        $categoryTreeCol = $this->colPrefix() . 'tree_path';
1451
        $categoryTable = \App::$cur->db->table_prefix . $this->table();
1452
        if ($oldPath) {
1453
            \App::$cur->db->query('UPDATE
1454
                ' . $categoryTable . ' 
1455
                    SET 
1456
                        ' . $categoryTreeCol . ' = REPLACE(' . $categoryTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1457
                    WHERE ' . $categoryTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1458
1459
            \App::$cur->db->query('UPDATE
1460
                ' . $itemsTable . '
1461
                    SET 
1462
                        ' . $itemTreeCol . ' = REPLACE(' . $itemTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1463
                    WHERE ' . $itemTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1464
        }
1465
        $itemModel::update([$itemTreeCol => $this->tree_path . $this->id . '/'], [$itemModel::colPrefix() . $this->index(), $this->id]);
1466
    }
1467
1468
    /**
1469
     * Return tree path
1470
     *
1471
     * @param \Model $catalog
1472
     * @return string
1473
     */
1474
    public function getCatalogTree($catalog) {
1475
        $catalogClass = get_class($catalog);
1476
        $catalogParent = $catalogClass::get($catalog->parent_id);
1477
        if ($catalog && $catalogParent) {
1478
            if ($catalogParent->tree_path) {
1479
                return $catalogParent->tree_path . $catalogParent->id . '/';
1480
            } else {
1481
                return $this->getCatalogTree($catalogParent) . $catalogParent->id . '/';
1482
            }
1483
        }
1484
        return '/';
1485
    }
1486
1487
    /**
1488
     * Update tree path item
1489
     */
1490
    public function changeItemTree() {
1491
        $class = get_class($this);
1492
        $categoryModel = $class::$categoryModel;
1493
        $category = $categoryModel::get($this->{$categoryModel::index()});
1494
        if ($category) {
1495
            $this->tree_path = $category->tree_path . $category->pk() . '/';
1496
        } else {
1497
            $this->tree_path = '/';
1498
        }
1499
    }
1500
1501
    /**
1502 4
     * Save object to data base
1503
     *
1504 4
     * @param array $options
1505 1
     * @return boolean|int
1506
     */
1507 4
    public function save($options = []) {
1508 4
1509
        if (static::$storage['type'] == 'moduleConfig') {
1510
            return static::saveModuleStorage($options);
1511 4
        }
1512
        $class = get_class($this);
1513
        if ($class::$categoryModel) {
1514 4
            $this->changeItemTree();
1515 3
        }
1516 3
        if ($class::$treeCategory) {
1517 4
            $this->changeCategoryTree();
1518 4
        }
1519
        if (!empty($this->_changedParams) && $this->pk()) {
1520 4
            Inji::$inst->event('modelItemParamsChanged-' . get_called_class(), $this);
1521 4
        }
1522 4
        $this->beforeSave();
1523 4
        $values = [];
1524 4
1525 4
        foreach ($this->cols() as $col => $param) {
1526 4
            if (in_array($col, array_keys($this->_params)) && (!$this->pk() || ($this->pk() && in_array($col, array_keys($this->_changedParams))))) {
1527 4
                $values[$col] = $this->_params[$col];
1528
            }
1529
        }
1530 4
        if (!$this->pk()) {
1531
            foreach ($class::$cols as $colName => $params) {
1532 4
                $class::fixPrefix($colName);
1533
                if (isset($params['default']) && !isset($values[$colName])) {
1534
                    $this->_params[$colName] = $values[$colName] = $params['default'];
1535
                }
1536 4
            }
1537 3
        }
1538 3
1539 3
        if (empty($values) && empty($options['empty'])) {
1540 3
            return false;
1541 3
        }
1542
1543
        if ($this->pk()) {
1544
            $new = false;
1545 3
            if ($this->get($this->_params[$this->index()])) {
1546 4
                App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1547 4
                App::$cur->db->update($this->table(), $values);
1548
            } else {
1549 4
1550 4
                $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1551
            }
1552 4
        } else {
1553 4
            $new = true;
1554
            //print_r($this->_params);
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% 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...
1555
            $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1556
        }
1557
        $this->logChanges($new);
1558
        App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1559 4
        try {
1560 4
            $result = App::$cur->db->select($this->table());
1561 4
        } catch (PDOException $exc) {
1562 4
            if ($exc->getCode() == '42S02') {
1563 4
                $this->createTable();
1564 4
            }
1565
            $result = App::$cur->db->select($this->table());
1566
        }
1567
        $this->_params = $result->fetch();
1568
        if ($new) {
1569
            Inji::$inst->event('modelCreatedItem-' . get_called_class(), $this);
1570 4
        }
1571
        $this->afterSave();
1572 4
        return $this->{$this->index()};
1573
    }
1574
1575
    /**
1576
     * After save trigger
1577 1
     */
1578
    public function afterSave() {
1579 1
1580
    }
1581
1582
    /**
1583
     * Before delete trigger
1584
     */
1585
    public function beforeDelete() {
1586
1587
    }
1588
1589
    /**
1590
     * Delete item from module storage
1591
     *
1592
     * @param array $options
1593
     * @return boolean
1594
     */
1595
    public function deleteFromModuleStorage($options) {
1596
1597
        $col = static::index();
1598
        $id = $this->pk();
1599
        $appType = '';
1600
        $classPath = explode('\\', get_called_class());
1601 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...
1602
            $moduleConfig = Config::share($classPath[0]);
1603
        } else {
1604
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1605
        }
1606
1607 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...
1608
            if (empty($options['appType'])) {
1609
                $appType = App::$cur->type;
1610
            } else {
1611
                $appType = $options['appType'];
1612
            }
1613
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1614
        } else {
1615
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1616
        }
1617
        if (empty($storage[$classPath[1]])) {
1618
            $storage[$classPath[1]] = [];
1619
        }
1620 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...
1621
1622
            if ($item[$col] == $id) {
1623
                unset($storage[$classPath[1]][$key]);
1624
                break;
1625
            }
1626
        }
1627 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...
1628
            $moduleConfig['storage'][$appType] = $storage;
1629
        } else {
1630
            $moduleConfig['storage'] = $storage;
1631
        }
1632 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...
1633
            Config::save('module', $moduleConfig, $classPath[0]);
1634
        } else {
1635
            Config::save('share', $moduleConfig, $classPath[0]);
1636
        }
1637
        return true;
1638 1
    }
1639 1
1640
    /**
1641 1
     * Delete item from data base
1642
     *
1643
     * @param array $options
1644 1
     * @return boolean
1645 1
     */
1646 1
    public function delete($options = []) {
1647 1
        $this->beforeDelete();
1648 1
1649 1
        if (static::$storage['type'] == 'moduleConfig') {
1650
            return static::deleteFromModuleStorage($options);
1651
        }
1652
        if (!empty($this->_params[$this->index()])) {
1653
            App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1654
            $result = App::$cur->db->delete($this->table());
1655
            if ($result) {
1656
                $this->afterDelete();
1657
                return $result;
1658
            }
1659
        }
1660 4
        return false;
1661 4
    }
1662
1663
    /**
1664
     * Delete items from data base
1665 4
     *
1666 4
     * @param array $where
1667
     */
1668
    public static function deleteList($where = []) {
1669
        if (!empty($where)) {
1670
            static::fixPrefix($where, 'first');
1671 1
            App::$cur->db->where($where);
1672
        }
1673 1
        App::$cur->db->delete(static::table());
1674
    }
1675
1676
    /**
1677
     * After delete trigger
1678
     */
1679
    public function afterDelete() {
1680
1681
    }
1682
1683
    /**
1684
     * find relation for col name
1685
     *
1686
     * @param string $col
1687
     * @return array|null
1688
     */
1689
    public static function findRelation($col) {
1690
1691
        foreach (static::relations() as $relName => $rel) {
1692
            if ($rel['col'] == $col) {
1693
                return $relName;
1694
            }
1695
        }
1696 4
        return null;
1697 4
    }
1698 2
1699 4
    /**
1700 4
     * Set params for model
1701
     *
1702
     * @param array $params
1703
     */
1704
    public function setParams($params) {
1705
        foreach ($params as $paramName => $value) {
1706
            $this->$paramName = $value;
1707
        }
1708 4
    }
1709 4
1710 4
    /**
1711
     * Return relation
1712
     *
1713
     * @param string $relName
1714
     * @return array|boolean
1715
     */
1716
    public static function getRelation($relName) {
1717
        $relations = static::relations();
1718
        return !empty($relations[$relName]) ? $relations[$relName] : false;
1719
    }
1720 4
1721 4
    /**
1722 4
     * Load relation
1723 2
     *
1724 2
     * @param string $name
1725 2
     * @param array $params
1726
     * @return null|array|integer|\Model
1727
     */
1728 2
    public function loadRelation($name, $params = []) {
1729 2
        $relation = static::getRelation($name);
1730
        if ($relation) {
1731 2
            if (!isset($relation['type'])) {
1732
                $type = 'to';
1733
            } else {
1734
                $type = $relation['type'];
1735
            }
1736
            $getCol = null;
1737
            $getParams = [];
1738
            switch ($type) {
1739
                case 'relModel':
1740
                    if (!$this->pk()) {
1741
                        return [];
1742
                    }
1743
                    $fixedCol = $relation['model']::index();
1744
                    $relation['relModel']::fixPrefix($fixedCol);
1745
                    $join = [$relation['relModel']::table(), $relation['relModel']::colPrefix() . $this->index() . ' = ' . $this->pk() . ' and ' . $relation['relModel']::colPrefix() . $relation['model']::index() . ' = ' . $relation['model']::index(), 'INNER'];
1746
                    $getType = 'getList';
1747
                    $options = [
1748
                        'join' => [$join],
1749
                        'where' => (isset($params['where'])) ? $params['where'] : ((isset($relation['where'])) ? $relation['where'] : null),
1750
                        'array' => (!empty($params['array'])) ? true : false,
1751
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1752
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1753
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1754
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1755 2
                    ];
1756
                    break;
1757
                case 'many':
1758
                    if (!$this->{$this->index()}) {
1759
                        return [];
1760
                    }
1761
                    $getType = 'getList';
1762
                    $options = [
1763
                        'join' => (isset($relation['join'])) ? $relation['join'] : null,
1764
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1765
                        'array' => (!empty($params['array'])) ? true : false,
1766
                        'forSelect' => (!empty($params['forSelect'])) ? true : false,
1767
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1768
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1769
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1770
                        'appType' => (isset($params['appType'])) ? $params['appType'] : ((isset($relation['appType'])) ? $relation['appType'] : null),
1771
                        'where' => []
1772
                    ];
1773
                    $options['where'][] = [$relation['col'], $this->{$this->index()}];
1774
                    if (!empty($relation['where'])) {
1775
                        $options['where'] = array_merge($options['where'], [$relation['where']]);
1776
                    }
1777
                    if (!empty($params['where'])) {
1778
                        $options['where'] = array_merge($options['where'], [$params['where']]);
1779 2
                    }
1780
                    break;
1781
                case 'one':
1782
                    $getType = 'get';
1783 2
                    $options = [$relation['col'], $this->pk()];
1784 2
                    break;
1785
                default:
1786
                    if ($this->$relation['col'] === null) {
1787 2
                        return null;
1788 2
                    }
1789 2
                    $getType = 'get';
1790 2
                    $options = $this->$relation['col'];
1791 2
                    $getParams['appType'] = $this->appType;
1792
            }
1793
            if (!empty($params['count'])) {
1794
                if (class_exists($relation['model'])) {
1795
                    return $relation['model']::getCount($options);
1796
                }
1797 2
                return 0;
1798 2
            } else {
1799 2
                if (class_exists($relation['model'])) {
1800
                    $this->loadedRelations[$name][json_encode($params)] = $relation['model']::$getType($options, $getCol, $getParams);
1801
                } else {
1802
                    $this->loadedRelations[$name][json_encode($params)] = [];
1803 2
                }
1804
            }
1805 4
            return $this->loadedRelations[$name][json_encode($params)];
1806
        }
1807
        return null;
1808
    }
1809
1810
    /**
1811
     * Add relation item
1812
     *
1813
     * @param string $relName
1814
     * @param \Model $objectId
1815
     * @return \Model|boolean
1816
     */
1817
    public function addRelation($relName, $objectId) {
1818
        $relation = $this->getRelation($relName);
1819
        if ($relation) {
1820
            $rel = $relation['relModel']::get([[$relation['model']::index(), $objectId], [$this->index(), $this->pk()]]);
1821
            if (!$rel) {
1822
                $rel = new $relation['relModel']([
1823
                    $relation['model']::index() => $objectId,
1824
                    $this->index() => $this->pk()
1825
                ]);
1826
                $rel->save();
1827
            }
1828
            return $rel;
1829
        }
1830
        return false;
1831
    }
1832
1833
    /**
1834
     * Check user access for form
1835
     *
1836
     * @param string $formName
1837
     * @return boolean
1838
     */
1839
    public function checkFormAccess($formName) {
1840
        if ($formName == 'manage' && !Users\User::$cur->isAdmin()) {
1841
            return false;
1842
        }
1843
        return true;
1844
    }
1845
1846
    /**
1847
     * Check access for model
1848
     *
1849
     * @param string $mode
1850
     * @param \Users\User $user
1851
     * @return boolean
1852
     */
1853
    public function checkAccess($mode = 'write', $user = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $mode is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1854
        if (!$user) {
1855
            $user = \Users\User::$cur;
1856
        }
1857
        return $user->isAdmin();
1858
    }
1859
1860
    /**
1861
     * Param and relation with params getter
1862
     *
1863
     * @param string $name
1864
     * @param array $params
1865
     * @return \Value|mixed
1866
     */
1867
    public function __call($name, $params) {
1868
        $fixedName = $name;
1869
        static::fixPrefix($fixedName);
1870 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...
1871
            return new Value($this, $fixedName);
1872
        } elseif (isset($this->_params[$name])) {
1873
            return new Value($this, $name);
1874
        }
1875
        return call_user_func_array([$this, 'loadRelation'], array_merge([$name], $params));
1876
    }
1877
1878
    /**
1879
     * Param and relation getter
1880
     *
1881
     * @param string $name
1882 4
     * @return mixed
1883 4
     */
1884 4
    public function __get($name) {
1885 4
        $fixedName = $name;
1886 4
        static::fixPrefix($fixedName);
1887
        if (isset($this->_params[$fixedName])) {
1888 4
            return $this->_params[$fixedName];
1889 2
        }
1890
        if (isset($this->loadedRelations[$name][json_encode([])])) {
1891 4
            return $this->loadedRelations[$name][json_encode([])];
1892
        }
1893
        return $this->loadRelation($name);
1894
    }
1895
1896
    /**
1897
     * Return model value in object
1898
     *
1899
     * @param string $name
1900
     * @return \Value|null
1901
     */
1902
    public function value($name) {
1903
        $fixedName = $name;
1904
        static::fixPrefix($fixedName);
1905 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...
1906
            return new Value($this, $fixedName);
1907
        } elseif ($this->_params[$name]) {
1908
            return new Value($this, $name);
1909
        }
1910
        return null;
1911
    }
1912
1913
    /**
1914
     * Return manager filters
1915
     *
1916
     * @return array
1917
     */
1918
    public static function managerFilters() {
1919
        return [];
1920
    }
1921
1922
    /**
1923
     * Return validators for cols
1924
     *
1925
     * @return array
1926
     */
1927
    public static function validators() {
1928
        return [];
1929
    }
1930
1931
    /**
1932
     * Return validator by name
1933
     *
1934
     * @param string $name
1935
     * @return array
1936
     */
1937
    public static function validator($name) {
1938
        $validators = static::validators();
1939
        if (!empty($validators[$name])) {
1940
            return $validators[$name];
1941
        }
1942
        return [];
1943
    }
1944
1945
    public function genViewLink() {
1946
        $className = get_class($this);
1947
        $link = substr($className, 0, strpos($className, '\\'));
1948
        $link .= '/view/';
1949
        $link .= str_replace('\\', '%5C', substr($className, strpos($className, '\\') + 1));
1950
        $link .= "/{$this->id}";
1951
        return $link;
1952
    }
1953
1954
    public function extract($model) {
1955
        $params = [];
1956
        if (empty($this->_params[$model::index()])) {
1957
            return false;
1958 4
        }
1959 4
        $params['id'] = $this->_params[$model::index()];
1960 4
        $indexes = array_keys($this->_params);
1961 4
        foreach ($model::$cols as $colName => $colParams) {
1962 4
            if (in_array($model::colPrefix() . $colName, $indexes)) {
1963
                $params[$model::colPrefix() . $colName] = $this->_params[$model::colPrefix() . $colName];
1964
            }
1965 4
        }
1966 2
        if (!$params) {
1967 2
            return FALSE;
1968 4
        }
1969 4
        return new $model($params);
1970 4
    }
1971
1972
    /**
1973 4
     * Set handler for model params
1974 2
     *
1975 2
     * @param string $name
1976 4
     * @param mixed $value
1977 1
     */
1978 1
    public function __set($name, $value) {
1979 4
        static::fixPrefix($name);
1980 4
        $className = get_called_class();
1981 4
        $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $name);
1982 4
        if (!$value && !empty(static::$cols[$shortName]) && in_array('emptyValue', array_keys(static::$cols[$shortName]))) {
1983 3
            $value = static::$cols[$shortName]['emptyValue'];
1984 3
        }
1985 4
        if (is_null($value) && empty(static::$cols[$shortName]['null'])) {
1986 4
            $value = '';
1987
        }
1988
        if (!empty($className::$cols[$shortName])) {
1989
            switch ($className::$cols[$shortName]['type']) {
1990
                case 'decimal':
1991
                    $value = (float) $value;
1992
                    break;
1993
                case 'number':
1994
                    $value = (int) $value;
1995
                    break;
1996
                case 'bool':
1997
                    $value = (bool) $value;
1998
                    break;
1999
            }
2000
        }
2001 View Code Duplication
        if (in_array($name, array_keys($this->_params)) && $this->_params[$name] != $value && !in_array($name, array_keys($this->_changedParams))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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

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

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

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