Completed
Push — master ( 8717df...fdbe7f )
by Alexey
05:44
created

Model::update()   B

Complexity

Conditions 5
Paths 9

Size

Total Lines 22
Code Lines 13

Duplication

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