Completed
Push — master ( d79a7d...905760 )
by Alexey
05:52
created

Model::getList()   B

Complexity

Conditions 5
Paths 9

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 16
rs 8.8571
cc 5
eloc 10
nc 9
nop 1
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
    public function __construct($params = [])
117
    {
118
        $this->setParams($params);
119
    }
120
121
    /**
122
     * return object name
123
     * 
124
     * @return string
125
     */
126
    public static function objectName()
127
    {
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
    {
142
        if (strpos($valuePath, ':')) {
143
            $rel = substr($valuePath, 0, strpos($valuePath, ':'));
144
            $param = substr($valuePath, strpos($valuePath, ':') + 1);
145
            if (!$object->$rel) {
146
                $modelName = get_class($object);
147
                $relations = $modelName::relations();
148
                if (empty($relations[$rel]['type']) || $relations[$rel]['type'] == 'one') {
149
                    return $object->{$relations[$rel]['col']};
150
                }
151
                return 0;
152
            }
153
            if (strpos($valuePath, ':')) {
154
                return self::getColValue($object->$rel, $param, $convert, $manageHref);
155
            } else {
156
                return $convert ? Model::resloveTypeValue($object->$rel, $param, $manageHref) : $object->$rel->$param;
157
            }
158
        } else {
159
            return $convert ? Model::resloveTypeValue($object, $valuePath, $manageHref) : $object->$valuePath;
160
        }
161
    }
162
163
    /**
164
     * Retrun value for view
165
     * 
166
     * @param Model $item
167
     * @param string $colName
168
     * @param boolean $manageHref
169
     * @return string
170
     */
171
    public static function resloveTypeValue($item, $colName, $manageHref = false)
172
    {
173
        $modelName = get_class($item);
174
        $colInfo = $modelName::getColInfo($colName);
175
        $type = !empty($colInfo['colParams']['type']) ? $colInfo['colParams']['type'] : 'string';
176
        $value = '';
177
        switch ($type) {
178
            case 'select':
179
                switch ($colInfo['colParams']['source']) {
180
                    case 'model':
181
                        $sourceValue = '';
182
                        if ($item->$colName) {
183
                            $sourceValue = $colInfo['colParams']['model']::get($item->$colName);
184
                        }
185
                        $value = $sourceValue ? $sourceValue->name() : 'Не задано';
186
                        break;
187
                    case 'array':
188
                        $value = !empty($colInfo['colParams']['sourceArray'][$item->$colName]) ? $colInfo['colParams']['sourceArray'][$item->$colName] : 'Не задано';
189
                        if (is_array($value) && $value['text']) {
190
                            $value = $value['text'];
191
                        }
192
                        break;
193
                    case 'bool':
194
                        return $item->$colName ? 'Да' : 'Нет';
195 View Code Duplication
                    case 'method':
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...
196
                        if (!empty($colInfo['colParams']['params'])) {
197
                            $values = call_user_func_array([App::$cur->$colInfo['colParams']['module'], $colInfo['colParams']['method']], $colInfo['colParams']['params']);
198
                        } else {
199
                            $values = $colInfo['colParams']['module']->$colInfo['colParams']['method']();
200
                        }
201
                        $value = !empty($values[$item->$colName]) ? $values[$item->$colName] : 'Не задано';
202
                        break;
203
                    case 'void':
204
                        if (!empty($modelName::$cols[$colName]['value']['type']) && $modelName::$cols[$colName]['value']['type'] == 'moduleMethod') {
205
                            return \App::$cur->{$modelName::$cols[$colName]['value']['module']}->{$modelName::$cols[$colName]['value']['method']}($item, $colName, $modelName::$cols[$colName]);
206
                        }
207
                        break;
208
                    case 'relation':
209
                        $relations = $colInfo['modelName']::relations();
210
                        $relValue = $relations[$colInfo['colParams']['relation']]['model']::get($item->$colName);
211
                        $relModel = $relations[$colInfo['colParams']['relation']]['model'];
212
                        $relModel = strpos($relModel, '\\') === 0 ? substr($relModel, 1) : $relModel;
213
                        if ($manageHref) {
214
                            $value = $relValue ? "<a href='/admin/" . str_replace('\\', '/view/', $relModel) . "/" . $relValue->pk() . "'>" . $relValue->name() . "</a>" : 'Не задано';
215
                        } else {
216
                            $value = $relValue ? $relValue->name() : 'Не задано';
217
                        }
218
                        break;
219
                }
220
                break;
221 View Code Duplication
            case 'image':
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...
222
                $file = Files\File::get($item->$colName);
223
                if ($file) {
224
                    $value = '<img src="' . $file->path . '?resize=60x120" />';
225
                } else {
226
                    $value = '<img src="/static/system/images/no-image.png?resize=60x120" />';
227
                }
228
                break;
229
            case 'bool':
230
                $value = $item->$colName ? 'Да' : 'Нет';
231
                break;
232
            case 'void':
233
                if (!empty($colInfo['colParams']['value']['type']) && $colInfo['colParams']['value']['type'] == 'moduleMethod') {
234
                    return \App::$cur->{$colInfo['colParams']['value']['module']}->{$colInfo['colParams']['value']['method']}($item, $colName, $colInfo['colParams']);
235
                }
236
                break;
237
            default:
238
                $value = $item->$colName;
239
                break;
240
        }
241
        return $value;
242
    }
243
244
    /**
245
     * Fix col prefix
246
     * 
247
     * @param mixed $array
248
     * @param string $searchtype
249
     * @param string $rootModel
250
     * @return null
251
     */
252
    public static function fixPrefix(&$array, $searchtype = 'key', $rootModel = '')
253
    {
254
        if (!$rootModel) {
255
            $rootModel = get_called_class();
256
        }
257
        $cols = static::cols();
258
        if (!$array) {
259
            return;
260
        }
261
        if (!is_array($array)) {
262 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...
263
                static::createCol($array);
264
                $cols = static::cols(true);
265
            }
266
            if (!isset($cols[$array]) && isset($cols[static::colPrefix() . $array])) {
267
                $array = static::colPrefix() . $array;
268
            } else {
269
                static::checkForJoin($array, $rootModel);
270
            }
271
            return;
272
        }
273
        switch ($searchtype) {
274
            case 'key':
275
                foreach ($array as $key => $item) {
276 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...
277
                        static::createCol($key);
278
                        $cols = static::cols(true);
279
                    }
280
                    if (!isset($cols[$key]) && isset($cols[static::colPrefix() . $key])) {
281
                        $array[static::colPrefix() . $key] = $item;
282
                        unset($array[$key]);
283
                        $key = static::colPrefix() . $key;
284
                    }
285
                    if (is_array($array[$key])) {
286
                        static::fixPrefix($array[$key], 'key', $rootModel);
287
                    } else {
288
                        static::checkForJoin($key, $rootModel);
289
                    }
290
                }
291
                break;
292
            case 'first':
293
                if (isset($array[0]) && is_string($array[0])) {
294
                    if (!isset($cols[static::colPrefix() . $array[0]]) && isset(static::$cols[$array[0]])) {
295
                        static::createCol($array[0]);
296
                        $cols = static::cols(true);
297
                    }
298 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...
299
                        $array[0] = static::colPrefix() . $array[0];
300
                    } else {
301
                        static::checkForJoin($array[0], $rootModel);
302
                    }
303
                } elseif (isset($array[0]) && is_array($array[0])) {
304
                    foreach ($array as &$item) {
305
                        static::fixPrefix($item, 'first', $rootModel);
306
                    }
307
                }
308
                break;
309
        }
310
    }
311
312
    /**
313
     * Check model relations path and load need relations
314
     * 
315
     * @param string $col
316
     * @param string $rootModel
317
     */
318
    public static function checkForJoin(&$col, $rootModel)
319
    {
320
321
        if (strpos($col, ':') !== false) {
322
            $relations = static::relations();
323
            if (isset($relations[substr($col, 0, strpos($col, ':'))])) {
324
                $rel = substr($col, 0, strpos($col, ':'));
325
                $col = substr($col, strpos($col, ':') + 1);
326
327
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
328
                switch ($type) {
329 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...
330
                        $relCol = $relations[$rel]['col'];
331
                        static::fixPrefix($relCol);
332
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol];
333
                        break;
334
                    case 'one':
335 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...
336
                        $relCol = $relations[$rel]['col'];
337
                        $relations[$rel]['model']::fixPrefix($relCol);
338
                        $rootModel::$relJoins[$relations[$rel]['model'] . '_' . $rel] = [$relations[$rel]['model']::table(), static::index() . ' = ' . $relCol];
339
                        break;
340
                }
341
                $relations[$rel]['model']::fixPrefix($col, 'key', $rootModel);
342
            }
343
        }
344
    }
345
346
    /**
347
     * Return full col information
348
     * 
349
     * @param string $col
350
     * @return array
351
     */
352
    public static function getColInfo($col)
353
    {
354
        return static::parseColRecursion($col);
355
    }
356
357
    /**
358
     * Information extractor for col relations path
359
     * 
360
     * @param string|array $info
361
     * @return array
362
     */
363
    public static function parseColRecursion($info)
364
    {
365
        if (is_string($info)) {
366
            $info = ['col' => $info, 'rawCol' => $info, 'modelName' => '', 'label' => [], 'joins' => []];
367
        }
368
        if (strpos($info['col'], ':') !== false) {
369
            $relations = static::relations();
370
            if (isset($relations[substr($info['col'], 0, strpos($info['col'], ':'))])) {
371
                $rel = substr($info['col'], 0, strpos($info['col'], ':'));
372
                $info['col'] = substr($info['col'], strpos($info['col'], ':') + 1);
373
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
374
                switch ($type) {
375 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...
376
                        $relCol = $relations[$rel]['col'];
377
                        static::fixPrefix($relCol);
378
                        //$info['modelName'] = $relations[$rel]['model'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

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

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

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

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

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

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

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

Loading history...
1395
1396
            if ($item[$col] == $id) {
1397
                unset($storage[$classPath[1]][$key]);
1398
                break;
1399
            }
1400
        }
1401 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...
1402
            $moduleConfig['storage'][$appType] = $storage;
1403
        } else {
1404
            $moduleConfig['storage'] = $storage;
1405
        }
1406 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...
1407
            Config::save('module', $moduleConfig, $classPath[0]);
1408
        } else {
1409
            Config::save('share', $moduleConfig, $classPath[0]);
1410
        }
1411
        return true;
1412
    }
1413
1414
    /**
1415
     * Delete item from data base
1416
     * 
1417
     * @param array $options
1418
     * @return boolean
1419
     */
1420
    public function delete($options = [])
1421
    {
1422
        $this->beforeDelete();
1423
1424
        if (static::$storage['type'] == 'moduleConfig') {
1425
            return static::deleteFromModuleStorage($options);
1426
        }
1427
        if (!empty($this->_params[$this->index()])) {
1428
            App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1429
            $result = App::$cur->db->delete($this->table());
1430
            if ($result) {
1431
                $this->afterDelete();
1432
                return $result;
1433
            }
1434
        }
1435
        return false;
1436
    }
1437
1438
    /**
1439
     * Delete items from data base
1440
     * 
1441
     * @param array $where
1442
     */
1443
    public static function deleteList($where)
1444
    {
1445
        if (!empty($where)) {
1446
            static::fixPrefix($where, 'first');
1447
            App::$cur->db->where($where);
1448
        }
1449
        App::$cur->db->delete(static::table());
1450
    }
1451
1452
    /**
1453
     * After delete trigger
1454
     */
1455
    public function afterDelete()
1456
    {
1457
        
1458
    }
1459
1460
    /**
1461
     * find relation for col name
1462
     * 
1463
     * @param string $col
1464
     * @return array|null
1465
     */
1466
    public static function findRelation($col)
1467
    {
1468
1469
        foreach (static::relations() as $relName => $rel) {
1470
            if ($rel['col'] == $col)
1471
                return $relName;
1472
        }
1473
        return NULL;
1474
    }
1475
1476
    /**
1477
     * Set params for model
1478
     * 
1479
     * @param array $params
1480
     */
1481
    public function setParams($params)
1482
    {
1483
        static::fixPrefix($params);
1484
        $className = get_called_class();
1485
        foreach ($params as $paramName => $value) {
1486
            $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $paramName);
1487
            if (!empty($className::$cols[$shortName])) {
1488
                switch ($className::$cols[$shortName]['type']) {
1489
                    case 'decimal':
1490
                        $params[$paramName] = (float) $value;
1491
                        break;
1492
                    case 'number':
1493
                        $params[$paramName] = (int) $value;
1494
                        break;
1495
                    case 'bool':
1496
                        $params[$paramName] = (bool) $value;
1497
                        break;
1498
                }
1499
            }
1500
        }
1501
        $this->_params = array_merge($this->_params, $params);
1502
    }
1503
1504
    /**
1505
     * Return relation
1506
     * 
1507
     * @param string $relName
1508
     * @return array|boolean
1509
     */
1510
    public static function getRelation($relName)
1511
    {
1512
        $relations = static::relations();
1513
        return !empty($relations[$relName]) ? $relations[$relName] : false;
1514
    }
1515
1516
    /**
1517
     * Load relation
1518
     * 
1519
     * @param string $name
1520
     * @param array $params
1521
     * @return null|array|integer|\Model
1522
     */
1523
    public function loadRelation($name, $params = [])
1524
    {
1525
        $relation = static::getRelation($name);
1526
        if ($relation) {
1527
            if (!isset($relation['type'])) {
1528
                $type = 'to';
1529
            } else {
1530
                $type = $relation['type'];
1531
            }
1532
            $getCol = null;
1533
            $getParams = [];
1534
            switch ($type) {
1535
                case 'relModel':
1536
                    if (!$this->pk()) {
1537
                        return [];
1538
                    }
1539
                    $fixedCol = $relation['model']::index();
1540
                    $relation['relModel']::fixPrefix($fixedCol);
1541
                    $ids = array_keys($relation['relModel']::getList(['where' => [$this->index(), $this->pk()], 'array' => true, 'key' => $fixedCol]));
1542
                    if (empty($ids)) {
1543
                        if (empty($params['count'])) {
1544
                            return [];
1545
                        } else {
1546
                            return 0;
1547
                        }
1548
                    }
1549
                    $getType = 'getList';
1550
                    $options = [
1551
                        'where' => [$relation['model']::index(), implode(',', $ids), 'IN'],
1552
                        'array' => (!empty($params['array'])) ? true : false,
1553
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1554
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1555
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1556
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1557
                    ];
1558
                    break;
1559
                case 'many':
1560
                    if (!$this->{$this->index()}) {
1561
                        return [];
1562
                    }
1563
                    $getType = 'getList';
1564
                    $options = [
1565
                        'join' => (isset($relation['join'])) ? $relation['join'] : null,
1566
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1567
                        'array' => (!empty($params['array'])) ? true : false,
1568
                        'forSelect' => (!empty($params['forSelect'])) ? true : false,
1569
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1570
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1571
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1572
                        'appType' => (isset($params['appType'])) ? $params['appType'] : ((isset($relation['appType'])) ? $relation['appType'] : null),
1573
                        'where' => []
1574
                    ];
1575
                    $options['where'][] = [$relation['col'], $this->{$this->index()}];
1576
                    if (!empty($relation['where'])) {
1577
                        $options['where'] = array_merge($options['where'], [$relation['where']]);
1578
                    }
1579
                    if (!empty($params['where'])) {
1580
                        $options['where'] = array_merge($options['where'], [$params['where']]);
1581
                    }
1582
                    break;
1583
                case 'one':
1584
                    $getType = 'get';
1585
                    $options = [$relation['col'], $this->pk()];
1586
                    break;
1587
                default:
1588
                    if ($this->$relation['col'] === NULL) {
1589
                        return null;
1590
                    }
1591
                    $getType = 'get';
1592
                    $options = $this->$relation['col'];
1593
                    $getParams['appType'] = $this->appType;
1594
            }
1595
            if (!empty($params['count'])) {
1596
                if (class_exists($relation['model'])) {
1597
                    return $relation['model']::getCount($options);
1598
                }
1599
                return 0;
1600
            } else {
1601
                if (class_exists($relation['model'])) {
1602
                    $this->loadedRelations[$name][json_encode($params)] = $relation['model']::$getType($options, $getCol, $getParams);
1603
                } else {
1604
                    $this->loadedRelations[$name][json_encode($params)] = [];
1605
                }
1606
            }
1607
            return $this->loadedRelations[$name][json_encode($params)];
1608
        }
1609
        return NULL;
1610
    }
1611
1612
    /**
1613
     * Add relation item
1614
     * 
1615
     * @param string $relName
1616
     * @param \Model $objectId
1617
     * @return \Model|boolean
1618
     */
1619
    public function addRelation($relName, $objectId)
1620
    {
1621
        $relation = $this->getRelation($relName);
1622
        if ($relation) {
1623
            $rel = $relation['relModel']::get([[$relation['model']::index(), $objectId], [$this->index(), $this->pk()]]);
1624
            if (!$rel) {
1625
                $rel = new $relation['relModel']([
1626
                    $relation['model']::index() => $objectId,
1627
                    $this->index() => $this->pk()
1628
                ]);
1629
                $rel->save();
1630
            }
1631
            return $rel;
1632
        }
1633
        return false;
1634
    }
1635
1636
    /**
1637
     * Check user access for form
1638
     * 
1639
     * @param string $formName
1640
     * @return boolean
1641
     */
1642
    public function checkFormAccess($formName)
1643
    {
1644
        if ($formName == 'manage' && !Users\User::$cur->isAdmin()) {
1645
            return false;
1646
        }
1647
        return true;
1648
    }
1649
1650
    /**
1651
     * Check access for model
1652
     * 
1653
     * @param string $mode
1654
     * @param \Users\User $user
1655
     * @return boolean
1656
     */
1657
    public function checkAccess($mode = 'write', $user = null)
1658
    {
1659
        if (!$user) {
1660
            $user = \Users\User::$cur;
1661
        }
1662
        return $user->isAdmin();
1663
    }
1664
1665
    /**
1666
     * Param and relation with params getter
1667
     * 
1668
     * @param string $name
1669
     * @param array $params
1670
     * @return \Value|mixed
1671
     */
1672
    public function __call($name, $params)
1673
    {
1674
        $fixedName = $name;
1675
        static::fixPrefix($fixedName);
1676 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...
1677
            return new Value($this, $fixedName);
1678
        } elseif (isset($this->_params[$name])) {
1679
            return new Value($this, $name);
1680
        }
1681
        return call_user_func_array([$this, 'loadRelation'], array_merge([$name], $params));
1682
    }
1683
1684
    /**
1685
     * Param and relation getter
1686
     * 
1687
     * @param string $name
1688
     * @return mixed
1689
     */
1690
    public function __get($name)
1691
    {
1692
        $fixedName = $name;
1693
        static::fixPrefix($fixedName);
1694
        if (isset($this->_params[$fixedName])) {
1695
            return $this->_params[$fixedName];
1696
        }
1697
        if (isset($this->loadedRelations[$name][json_encode([])])) {
1698
            return $this->loadedRelations[$name][json_encode([])];
1699
        }
1700
        return $this->loadRelation($name);
1701
    }
1702
1703
    /**
1704
     * Return model value in object
1705
     * 
1706
     * @param string $name
1707
     * @return \Value|null
1708
     */
1709
    public function value($name)
1710
    {
1711
        $fixedName = $name;
1712
        static::fixPrefix($fixedName);
1713 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...
1714
            return new Value($this, $fixedName);
1715
        } elseif ($this->_params[$name]) {
1716
            return new Value($this, $name);
1717
        }
1718
        return null;
1719
    }
1720
1721
    /**
1722
     * Return manager filters
1723
     * 
1724
     * @return array
1725
     */
1726
    public static function managerFilters()
1727
    {
1728
        return [];
1729
    }
1730
1731
    /**
1732
     * Return validators for cols
1733
     * 
1734
     * @return array
1735
     */
1736
    public static function validators()
1737
    {
1738
        return [];
1739
    }
1740
1741
    /**
1742
     * Return validator by name
1743
     * 
1744
     * @param string $name
1745
     * @return array
1746
     */
1747
    public static function validator($name)
1748
    {
1749
        $validators = static::validators();
1750
        if (!empty($validators[$name])) {
1751
            return $validators[$name];
1752
        }
1753
        return [];
1754
    }
1755
1756
    /**
1757
     * Set handler for model params
1758
     * 
1759
     * @param string $name
1760
     * @param mixed $value
1761
     */
1762
    public function __set($name, $value)
1763
    {
1764
        static::fixPrefix($name);
1765
        $className = get_called_class();
1766
        $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $name);
1767
        if (!empty($className::$cols[$shortName])) {
1768
            switch ($className::$cols[$shortName]['type']) {
1769
                case 'decimal':
1770
                    $value = (float) $value;
1771
                    break;
1772
                case 'number':
1773
                    $value = (int) $value;
1774
                    break;
1775
                case 'bool':
1776
                    $value = (bool) $value;
1777
                    break;
1778
            }
1779
        }
1780
        if ((isset($this->_params[$name]) && $this->_params[$name] != $value) && !isset($this->_changedParams[$name])) {
1781
            $this->_changedParams[$name] = $this->_params[$name];
1782
        }
1783
1784
        $this->_params[$name] = $value;
1785
    }
1786
1787
    /**
1788
     * Isset handler for model params
1789
     * 
1790
     * @param string $name
1791
     * @return boolean
1792
     */
1793
    public function __isset($name)
1794
    {
1795
        static::fixPrefix($name);
1796
        return isset($this->_params[$name]);
1797
    }
1798
1799
    /**
1800
     * Convert object to string
1801
     * 
1802
     * @return string
1803
     */
1804
    public function __toString()
1805
    {
1806
        return $this->name();
1807
    }
1808
1809
}
1810