Completed
Push — master ( c2ec3d...a14cfe )
by Alexey
05:11
created

Model::__isset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
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
                $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
        if (static::$storage['type'] == 'moduleConfig') {
515
            return true;
516
        }
517
        if (!App::$cur->db) {
518
            return false;
519
        }
520
521
        $query = App::$cur->db->newQuery();
522
        if (!$query) {
523
            return false;
524
        }
525
526
        if (!isset($this)) {
527
            $tableName = static::table();
528
            $colPrefix = static::colPrefix();
529
            $indexes = static::indexes();
530
        } else {
531
            $tableName = $this->table();
532
            $colPrefix = $this->colPrefix();
533
            $indexes = $this->indexes();
534
        }
535
        if (App::$cur->db->tableExist($tableName)) {
536
            return true;
537
        }
538
        $cols = [
539
            $colPrefix . 'id' => 'pk'
540
        ];
541
        $className = get_called_class();
542
        if (!empty($className::$cols)) {
543
            foreach ($className::$cols as $colName => $colParams) {
544
                if ($colName == 'date_create') {
545
                    $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
546
                    continue;
547
                }
548
                $params = $className::genColParams($colName);
549
                if ($params) {
550
                    $cols[$colPrefix . $colName] = $params;
551
                }
552
            }
553
        }
554
        if (empty($cols[$colPrefix . 'date_create'])) {
555
            $cols[$colPrefix . 'date_create'] = 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP';
556
        }
557
        $tableIndexes = [];
558
        if ($indexes) {
559
            foreach ($indexes as $indexName => $index) {
560
                $tableIndexes[] = $index['type'] . ' ' . App::$cur->db->table_prefix . $indexName . ' (' . implode(',', $index['cols']) . ')';
561
            }
562
        }
563
564
        $query->createTable($tableName, $cols, $tableIndexes);
565
        return true;
566
    }
567
568
    /**
569
     * Return table name
570
     * 
571
     * @return string
572
     */
573
    public static function table()
574
    {
575
        return strtolower(str_replace('\\', '_', get_called_class()));
576
    }
577
578
    /**
579
     * Return table index col name
580
     * 
581
     * @return string
582
     */
583
    public static function index()
584
    {
585
586
        return static::colPrefix() . 'id';
587
    }
588
589
    /**
590
     * Return col prefix
591
     * 
592
     * @return string
593
     */
594
    public static function colPrefix()
595
    {
596
        $classPath = explode('\\', get_called_class());
597
        $classPath = array_slice($classPath, 1);
598
        return strtolower(implode('_', $classPath)) . '_';
599
    }
600
601
    /**
602
     * return relations list
603
     * 
604
     * @return array
605
     */
606
    public static function relations()
607
    {
608
        return [];
609
    }
610
611
    /**
612
     * Return name of col with object name
613
     * 
614
     * @return string
615
     */
616
    public static function nameCol()
617
    {
618
        return 'name';
619
    }
620
621
    /**
622
     * Return object name
623
     * 
624
     * @return string
625
     */
626
    public function name()
627
    {
628
        return $this->{$this->nameCol()} ? $this->{$this->nameCol()} : $this->pk();
629
    }
630
631
    /**
632
     * Get single object from data base
633
     * 
634
     * @param mixed $param
635
     * @param string $col
636
     * @param array $options
637
     * @return boolean|\Model
638
     */
639
    public static function get($param, $col = null, $options = [])
640
    {
641
        if (static::$storage['type'] == 'moduleConfig') {
642
            return static::getFromModuleStorage($param, $col, $options);
643
        }
644
        if (!empty($col)) {
645
            static::fixPrefix($col);
646
        }
647
648
        if (is_array($param)) {
649
            static::fixPrefix($param, 'first');
650
        }
651
        foreach (static::$relJoins as $join) {
652
            App::$cur->db->join($join[0], $join[1]);
653
        }
654
        static::$relJoins = [];
655
        foreach (static::$needJoin as $rel) {
656
            $relations = static::relations();
657
            if (isset($relations[$rel])) {
658
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
659
                switch ($type) {
660
                    case 'to':
661
                        $relCol = $relations[$rel]['col'];
662
                        static::fixPrefix($relCol);
663
                        App::$cur->db->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
664
                        break;
665
                    case 'one':
666
                        $col = $relations[$rel]['col'];
667
                        $relations[$rel]['model']::fixPrefix($col);
668
                        App::$cur->db->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
669
                        break;
670
                }
671
            }
672
        }
673
        static::$needJoin = [];
674
        if (is_array($param)) {
675
            App::$cur->db->where($param);
676
        } else {
677
            if ($col === null) {
678
679
                $col = static::index();
680
            }
681
            if ($param !== null) {
682
                $cols = static::cols();
683
                if (!isset($cols[$col]) && isset($cols[static::colPrefix() . $col])) {
684
                    $col = static::colPrefix() . $col;
685
                }
686
                App::$cur->db->where($col, $param);
687
            } else {
688
                return false;
689
            }
690
        }
691
        if (!App::$cur->db->where) {
692
            return false;
693
        }
694
        try {
695
            $result = App::$cur->db->select(static::table());
696
        } catch (PDOException $exc) {
697
            if ($exc->getCode() == '42S02') {
698
                static::createTable();
699
            }
700
            $result = App::$cur->db->select(static::table());
701
        }
702
        if (!$result) {
703
            return false;
704
        }
705
        return $result->fetch(get_called_class());
706
    }
707
708
    /**
709
     * Old method
710
     * 
711
     * @param type $options
712
     * @return Array
713
     */
714
    public static function get_list($options = [])
715
    {
716
        $query = App::$cur->db->newQuery();
717
        if (!$query) {
718
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Model::get_list of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
719
        }
720
        if (!empty($options['where']))
721
            $query->where($options['where']);
722
        if (!empty($options['group'])) {
723
            $query->group($options['group']);
724
        }
725
        if (!empty($options['order']))
726
            $query->order($options['order']);
727
        if (!empty($options['join']))
728
            $query->join($options['join']);
729
        if (!empty($options['distinct']))
730
            $query->distinct = $options['distinct'];
731
732
        foreach (static::$relJoins as $join) {
733
            $query->join($join[0], $join[1]);
734
        }
735
        static::$relJoins = [];
736 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...
737
            $relations = static::relations();
738
            if (isset($relations[$rel])) {
739
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
740
                switch ($type) {
741
                    case 'to':
742
                        $relCol = $relations[$rel]['col'];
743
                        static::fixPrefix($relCol);
744
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
745
                        break;
746
                    case 'one':
747
                        $col = $relations[$rel]['col'];
748
                        $relations[$rel]['model']::fixPrefix($col);
749
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
750
                        break;
751
                }
752
            }
753
        }
754
        static::$needJoin = [];
755
756 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...
757
            $limit = (int) $options['limit'];
758
        else {
759
            $limit = 0;
760
        }
761 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...
762
            $start = (int) $options['start'];
763
        else {
764
            $start = 0;
765
        }
766
        if ($limit || $start) {
767
            $query->limit($start, $limit);
768
        }
769
        if (isset($options['key'])) {
770
            $key = $options['key'];
771
        } else {
772
            $key = static::index();
773
        }
774
        try {
775
            $result = $query->select(static::table());
776
        } catch (PDOException $exc) {
777
            if ($exc->getCode() == '42S02') {
778
                static::createTable();
779
            }
780
            $result = $query->select(static::table());
781
        }
782
783
        if (!empty($options['array'])) {
784
            return $result->getArray($key);
785
        }
786
        $list = $result->getObjects(get_called_class(), $key);
787 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...
788
            $return = [];
789
            foreach ($list as $key => $item) {
790
                $return[$key] = $item->name();
791
            }
792
            return $return;
793
        }
794
        return $list;
795
    }
796
797
    /**
798
     * Return list of objects from data base
799
     * 
800
     * @param type $options
801
     * @return type
802
     */
803
    public static function getList($options = [])
804
    {
805
        if (static::$storage['type'] != 'db') {
806
            return static::getListFromModuleStorage($options);
807
        }
808
        if (!empty($options['where'])) {
809
            static::fixPrefix($options['where'], 'first');
810
        }
811
        if (!empty($options['order'])) {
812
            static::fixPrefix($options['order'], 'first');
813
        }
814
        return static::get_list($options);
815
    }
816
817
    /**
818
     * Get single item from module storage
819
     * 
820
     * @param array $param
821
     * @param string $col
822
     * @param array $options
823
     * @return boolean|\Model
824
     */
825
    public static function getFromModuleStorage($param = null, $col = null, $options = [])
826
    {
827
        if ($col === null) {
828
829
            $col = static::index();
830
        }
831
        if ($param == null) {
832
            return false;
833
        }
834
        $classPath = explode('\\', get_called_class());
835 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...
836
            $moduleConfig = Config::share($classPath[0]);
837
        } else {
838
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
839
        }
840
        $appType = App::$cur->type;
841 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...
842
            if (!empty($options['appType'])) {
843
                $appType = $options['appType'];
844
            }
845
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
846
        } else {
847
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
848
        }
849
        if (!empty($storage[$classPath[1]])) {
850
            $items = $storage[$classPath[1]];
851
            $class = get_called_class();
852
            foreach ($items as $key => $item) {
853
                if ($item[$col] == $param) {
854
                    if (!empty($options['array'])) {
855
                        return $item;
856
                    }
857
                    $item = new $class($item);
858
                    $item->appType = $appType;
859
                    return $item;
860
                }
861
            }
862
        }
863
        return false;
864
    }
865
866
    /**
867
     * Return list items from module storage
868
     * 
869
     * @param array $options
870
     * @return array
871
     */
872
    public static function getListFromModuleStorage($options = [])
873
    {
874
        $classPath = explode('\\', get_called_class());
875 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...
876
            $moduleConfig = Config::share($classPath[0]);
877
        } else {
878
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
879
        }
880 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...
881
            if (empty($options['appType'])) {
882
                $appType = App::$cur->type;
883
            } else {
884
                $appType = $options['appType'];
885
            }
886
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
887
        } else {
888
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
889
        }
890
        if (!empty($storage[$classPath[1]])) {
891
            $items = [];
892
            $class = get_called_class();
893
            if (isset($options['key'])) {
894
                $arrayKey = $options['key'];
895
            } else {
896
                $arrayKey = static::index();
897
            }
898
            foreach ($storage[$classPath[1]] as $key => $item) {
899
                if (!empty($options['where']) && !Model::checkWhere($item, $options['where'])) {
900
                    continue;
901
                }
902
                $items[$item[$arrayKey]] = new $class($item);
903
            }
904
            if (!empty($options['order'])) {
905
                usort($items, function($a, $b) use($options) {
906
                    if ($a->{$options['order'][0]} > $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
907
                        return 1;
908
                    } elseif ($a->{$options['order'][0]} < $b->{$options['order'][0]} && $options['order'][1] = 'asc') {
909
                        return -1;
910
                    }
911
                    return 0;
912
                });
913
            }
914 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...
915
                $return = [];
916
                foreach ($items as $key => $item) {
917
                    $return[$key] = $item->name();
918
                }
919
                return $return;
920
            }
921
            return $items;
922
        }
923
        return [];
924
    }
925
926
    /**
927
     * Return count of records from module storage
928
     * 
929
     * @param array $options
930
     * @return int
931
     */
932
    public static function getCountFromModuleStorage($options = [])
933
    {
934
935
        $classPath = explode('\\', get_called_class());
936
        $count = 0;
937
        if (empty($options['appType'])) {
938
            $appType = App::$cur->type;
939
        } else {
940
            $appType = $options['appType'];
941
        }
942 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...
943
            $moduleConfig = Config::share($classPath[0]);
944
        } else {
945
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
946
        }
947
        if (!empty($moduleConfig['storage'][$appType][$classPath[1]])) {
948
            $items = $moduleConfig['storage'][$appType][$classPath[1]];
949
            if (empty($options['where'])) {
950
                return count($items);
951
            }
952
            foreach ($items as $key => $item) {
953
                if (!empty($options['where'])) {
954
                    if (Model::checkWhere($item, $options['where'])) {
955
                        $count++;
956
                    }
957
                } else {
958
                    $count++;
959
                }
960
            }
961
        }
962
        return $count;
963
    }
964
965
    /**
966
     * Check where for module storage query
967
     * 
968
     * @param array $item
969
     * @param array|string $where
970
     * @param string $value
971
     * @param string $operation
972
     * @param string $concatenation
973
     * @return boolean
974
     */
975
    public static function checkWhere($item = [], $where = '', $value = '', $operation = '=', $concatenation = 'AND')
976
    {
977
978
        if (is_array($where)) {
979
            if (is_array($where[0])) {
980
                foreach ($where as $whereItem) {
981
                    $result = forward_static_call_array(['Model', 'checkWhere'], array_merge([$item], $whereItem));
982
                    if (!$result) {
983
                        return false;
984
                    }
985
                }
986
                return true;
987
            } else {
988
                return forward_static_call_array(['Model', 'checkWhere'], array_merge([$item], $where));
989
            }
990
        }
991
992
        if (!isset($item[$where]) && !$value) {
993
            return true;
994
        }
995
        if (!isset($item[$where]) && $value) {
996
            return false;
997
        }
998
        if ($item[$where] == $value) {
999
            return true;
1000
        }
1001
        return false;
1002
    }
1003
1004
    /**
1005
     * Return count of records from data base
1006
     * 
1007
     * @param array $options
1008
     * @return array|int
1009
     */
1010
    public static function getCount($options = [])
1011
    {
1012
        if (static::$storage['type'] == 'moduleConfig') {
1013
            return static::getCountFromModuleStorage($options);
1014
        }
1015
        $query = App::$cur->db->newQuery();
1016
        if (!$query) {
1017
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Model::getCount of type array|integer.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1018
        }
1019
        if (!empty($options['where'])) {
1020
            static::fixPrefix($options['where'], 'first');
1021
        }
1022
        if (!empty($options['where']))
1023
            $query->where($options['where']);
1024
        if (!empty($options['join']))
1025
            $query->join($options['join']);
1026
        if (!empty($options['order'])) {
1027
            $query->order($options['order']);
1028
        }
1029 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...
1030
            $limit = (int) $options['limit'];
1031
        else {
1032
            $limit = 0;
1033
        }
1034 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...
1035
            $start = (int) $options['start'];
1036
        else {
1037
            $start = 0;
1038
        }
1039
        if ($limit || $start) {
1040
            $query->limit($start, $limit);
1041
        }
1042
1043
        foreach (static::$relJoins as $join) {
1044
            $query->join($join[0], $join[1]);
1045
        }
1046
        static::$relJoins = [];
1047 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...
1048
            $relations = static::relations();
1049
            if (isset($relations[$rel])) {
1050
                $type = empty($relations[$rel]['type']) ? 'to' : $relations[$rel]['type'];
1051
                switch ($type) {
1052
                    case 'to':
1053
                        $relCol = $relations[$rel]['col'];
1054
                        static::fixPrefix($relCol);
1055
                        $query->join($relations[$rel]['model']::table(), $relations[$rel]['model']::index() . ' = ' . $relCol);
1056
                        break;
1057
                    case 'one':
1058
                        $col = $relations[$rel]['col'];
1059
                        $relations[$rel]['model']::fixPrefix($col);
1060
                        $query->join($relations[$rel]['model']::table(), static::index() . ' = ' . $col);
1061
                        break;
1062
                }
1063
            }
1064
        }
1065
        static::$needJoin = [];
1066
        $cols = 'COUNT(';
1067
1068
        if (!empty($options['distinct'])) {
1069
            if (is_bool($options['distinct'])) {
1070
                $cols .= 'DISTINCT *';
1071
            } else {
1072
                $cols .= "DISTINCT {$options['distinct']}";
1073
            }
1074
        } else {
1075
            $cols .= '*';
1076
        }
1077
        $cols .=') as `count`' . (!empty($options['cols']) ? ',' . $options['cols'] : '');
1078
        $query->cols = $cols;
1079
        if (!empty($options['group'])) {
1080
            $query->group($options['group']);
1081
        }
1082
        try {
1083
            $result = $query->select(static::table());
1084
        } catch (PDOException $exc) {
1085
            var_dump($exc->getMessage());
0 ignored issues
show
Security Debugging Code introduced by
var_dump($exc->getMessage()); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
1086
            if ($exc->getCode() == '42S02') {
1087
                static::createTable();
1088
            }
1089
            $result = $query->select(static::table());
1090
        }
1091
        if (!empty($options['group'])) {
1092
            $count = $result->getArray();
1093
            return $count;
1094
        } else {
1095
            $count = $result->fetch();
1096
            return $count['count'];
1097
        }
1098
    }
1099
1100
    /**
1101
     * Update records in data base
1102
     * 
1103
     * @param array $params
1104
     * @param array $where
1105
     * @return boolean
1106
     */
1107
    public static function update($params, $where = [])
1108
    {
1109
        static::fixPrefix($params);
1110
1111
        $cols = self::cols();
1112
1113
        $values = [];
1114
        foreach ($cols as $col => $param) {
1115
            if (isset($params[$col]))
1116
                $values[$col] = $params[$col];
1117
        }
1118
        if (empty($values)) {
1119
            return false;
1120
        }
1121
1122
        if (!empty($where)) {
1123
            static::fixPrefix($where, 'key');
1124
1125
            App::$cur->db->where($where);
1126
        }
1127
        App::$cur->db->update(static::table(), $values);
1128
    }
1129
1130
    /**
1131
     * Return primary key of object
1132
     * 
1133
     * @return mixed
1134
     */
1135
    public function pk()
1136
    {
1137
        return $this->{$this->index()};
1138
    }
1139
1140
    /**
1141
     * Before save trigger
1142
     */
1143
    public function beforeSave()
1144
    {
1145
        
1146
    }
1147
1148
    /**
1149
     * Save object to module storage
1150
     * 
1151
     * @param array $options
1152
     * @return boolean
1153
     */
1154
    public function saveModuleStorage($options)
1155
    {
1156
1157
        $col = static::index();
1158
        $id = $this->pk();
1159
        $appType = '';
1160
        $classPath = explode('\\', get_called_class());
1161
1162 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...
1163
            $moduleConfig = Config::share($classPath[0]);
1164
        } else {
1165
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1166
        }
1167
1168 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...
1169
            if (empty($options['appType'])) {
1170
                $appType = App::$cur->type;
1171
            } else {
1172
                $appType = $options['appType'];
1173
            }
1174
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1175
        } else {
1176
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1177
        }
1178
        if (empty($storage[$classPath[1]])) {
1179
            $storage[$classPath[1]] = [];
1180
        }
1181
        if ($id) {
1182 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...
1183
                if ($item[$col] == $id) {
1184
                    $storage[$classPath[1]][$key] = $this->_params;
1185
                    break;
1186
                }
1187
            }
1188
        } else {
1189
            $id = !empty($storage['scheme'][$classPath[1]]['ai']) ? $storage['scheme'][$classPath[1]]['ai'] : 1;
1190
            $this->$col = $id;
1191
            $storage['scheme'][$classPath[1]]['ai'] = $id + 1;
1192
            $storage[$classPath[1]][] = $this->_params;
1193
        }
1194 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...
1195
            $moduleConfig['storage'][$appType] = $storage;
1196
        } else {
1197
            $moduleConfig['storage'] = $storage;
1198
        }
1199 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...
1200
            Config::save('module', $moduleConfig, $classPath[0]);
1201
        } else {
1202
            Config::save('share', $moduleConfig, $classPath[0]);
1203
        }
1204
        return true;
1205
    }
1206
1207
    /**
1208
     * Update tree path category
1209
     */
1210
    public function changeCategoryTree()
1211
    {
1212
        $class = get_class($this);
1213
        $itemModel = $class::$treeCategory;
1214
        $oldPath = $this->tree_path;
1215
        $this->tree_path = $this->getCatalogTree($this);
1216
        $itemsTable = \App::$cur->db->table_prefix . $itemModel::table();
1217
        $itemTreeCol = $itemModel::colPrefix() . 'tree_path';
1218
1219
        $categoryTreeCol = $this->colPrefix() . 'tree_path';
1220
        $categoryTable = \App::$cur->db->table_prefix . $this->table();
1221
        if ($oldPath) {
1222
            \App::$cur->db->query('UPDATE
1223
                ' . $categoryTable . ' 
1224
                    SET 
1225
                        ' . $categoryTreeCol . ' = REPLACE(' . $categoryTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1226
                    WHERE ' . $categoryTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1227
1228
            \App::$cur->db->query('UPDATE
1229
                ' . $itemsTable . '
1230
                    SET 
1231
                        ' . $itemTreeCol . ' = REPLACE(' . $itemTreeCol . ', "' . $oldPath . $this->id . '/' . '", "' . $this->tree_path . $this->id . '/' . '") 
1232
                    WHERE ' . $itemTreeCol . ' LIKE "' . $oldPath . $this->id . '/' . '%"');
1233
        }
1234
        $itemModel::update([$itemTreeCol => $this->tree_path . $this->id . '/'], [$itemModel::colPrefix() . $this->index(), $this->id]);
1235
    }
1236
1237
    /**
1238
     * Return tree path
1239
     * 
1240
     * @param \Model $catalog
1241
     * @return string
1242
     */
1243
    public function getCatalogTree($catalog)
1244
    {
1245
        $catalogClass = get_class($catalog);
1246
        $catalogParent = $catalogClass::get($catalog->parent_id);
1247
        if ($catalog && $catalogParent) {
1248
            if ($catalogParent->tree_path) {
1249
                return $catalogParent->tree_path . $catalogParent->id . '/';
1250
            } else {
1251
                return $this->getCatalogTree($catalogParent) . $catalogParent->id . '/';
1252
            }
1253
        }
1254
        return '/';
1255
    }
1256
1257
    /**
1258
     * Update tree path item
1259
     */
1260
    public function changeItemTree()
1261
    {
1262
        $class = get_class($this);
1263
        $categoryModel = $class::$categoryModel;
1264
        $category = $categoryModel::get($this->{$categoryModel::index()});
1265
        if ($category) {
1266
            $this->tree_path = $category->tree_path . $category->pk() . '/';
1267
        } else {
1268
            $this->tree_path = '/';
1269
        }
1270
    }
1271
1272
    /**
1273
     * Save object to data base
1274
     * 
1275
     * @param array $options
1276
     * @return boolean|int
1277
     */
1278
    public function save($options = [])
1279
    {
1280
1281
        if (static::$storage['type'] == 'moduleConfig') {
1282
            return static::saveModuleStorage($options);
1283
        }
1284
        $class = get_class($this);
1285
        if ($class::$categoryModel) {
1286
            $this->changeItemTree();
1287
        }
1288
        if ($class::$treeCategory) {
1289
            $this->changeCategoryTree();
1290
        }
1291
        if (!empty($this->_changedParams) && $this->pk()) {
1292
            Inji::$inst->event('modelItemParamsChanged-' . get_called_class(), $this);
1293
        }
1294
        $this->beforeSave();
1295
1296
        $values = [];
1297
1298
        foreach ($this->cols() as $col => $param) {
1299
            if (isset($this->_params[$col]))
1300
                $values[$col] = $this->_params[$col];
1301
        }
1302
        if (empty($values) && empty($options['empty'])) {
1303
            return false;
1304
        }
1305
1306
        if ($this->pk()) {
1307
            $new = false;
1308
            if ($this->get($this->_params[$this->index()])) {
1309
                App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1310
                App::$cur->db->update($this->table(), $values);
1311
            } else {
1312
1313
                $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1314
            }
1315
        } else {
1316
            $new = true;
1317
            $this->_params[$this->index()] = App::$cur->db->insert($this->table(), $values);
1318
        }
1319
        App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1320
        try {
1321
            $result = App::$cur->db->select($this->table());
1322
        } catch (PDOException $exc) {
1323
            if ($exc->getCode() == '42S02') {
1324
                $this->createTable();
1325
            }
1326
            $result = App::$cur->db->select($this->table());
1327
        }
1328
        $this->_params = $result->fetch();
1329
        if ($new) {
1330
            Inji::$inst->event('modelCreatedItem-' . get_called_class(), $this);
1331
        }
1332
        $this->afterSave();
1333
        return $this->{$this->index()};
1334
    }
1335
1336
    /**
1337
     * After save trigger
1338
     */
1339
    public function afterSave()
1340
    {
1341
        
1342
    }
1343
1344
    /**
1345
     * Before delete trigger
1346
     */
1347
    public function beforeDelete()
1348
    {
1349
        
1350
    }
1351
1352
    /**
1353
     * Delete item from module storage
1354
     * 
1355
     * @param array $options
1356
     * @return boolean
1357
     */
1358
    public function deleteFromModuleStorage($options)
1359
    {
1360
1361
        $col = static::index();
1362
        $id = $this->pk();
1363
        $appType = '';
1364
        $classPath = explode('\\', get_called_class());
1365 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...
1366
            $moduleConfig = Config::share($classPath[0]);
1367
        } else {
1368
            $moduleConfig = Config::module($classPath[0], strpos(static::$storage['type'], 'system') !== false);
1369
        }
1370
1371 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...
1372
            if (empty($options['appType'])) {
1373
                $appType = App::$cur->type;
1374
            } else {
1375
                $appType = $options['appType'];
1376
            }
1377
            $storage = !empty($moduleConfig['storage'][$appType]) ? $moduleConfig['storage'][$appType] : [];
1378
        } else {
1379
            $storage = !empty($moduleConfig['storage']) ? $moduleConfig['storage'] : [];
1380
        }
1381
        if (empty($storage[$classPath[1]])) {
1382
            $storage[$classPath[1]] = [];
1383
        }
1384 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...
1385
1386
            if ($item[$col] == $id) {
1387
                unset($storage[$classPath[1]][$key]);
1388
                break;
1389
            }
1390
        }
1391 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...
1392
            $moduleConfig['storage'][$appType] = $storage;
1393
        } else {
1394
            $moduleConfig['storage'] = $storage;
1395
        }
1396 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...
1397
            Config::save('module', $moduleConfig, $classPath[0]);
1398
        } else {
1399
            Config::save('share', $moduleConfig, $classPath[0]);
1400
        }
1401
        return true;
1402
    }
1403
1404
    /**
1405
     * Delete item from data base
1406
     * 
1407
     * @param array $options
1408
     * @return boolean
1409
     */
1410
    public function delete($options = [])
1411
    {
1412
        $this->beforeDelete();
1413
1414
        if (static::$storage['type'] == 'moduleConfig') {
1415
            return static::deleteFromModuleStorage($options);
1416
        }
1417
        if (!empty($this->_params[$this->index()])) {
1418
            App::$cur->db->where($this->index(), $this->_params[$this->index()]);
1419
            $result = App::$cur->db->delete($this->table());
1420
            if ($result) {
1421
                $this->afterDelete();
1422
                return $result;
1423
            }
1424
        }
1425
        return false;
1426
    }
1427
1428
    /**
1429
     * Delete items from data base
1430
     * 
1431
     * @param array $where
1432
     */
1433
    public static function deleteList($where)
1434
    {
1435
        if (!empty($where)) {
1436
            static::fixPrefix($where, 'first');
1437
            App::$cur->db->where($where);
1438
        }
1439
        App::$cur->db->delete(static::table());
1440
    }
1441
1442
    /**
1443
     * After delete trigger
1444
     */
1445
    public function afterDelete()
1446
    {
1447
        
1448
    }
1449
1450
    /**
1451
     * find relation for col name
1452
     * 
1453
     * @param string $col
1454
     * @return array|null
1455
     */
1456
    public static function findRelation($col)
1457
    {
1458
1459
        foreach (static::relations() as $relName => $rel) {
1460
            if ($rel['col'] == $col)
1461
                return $relName;
1462
        }
1463
        return NULL;
1464
    }
1465
1466
    /**
1467
     * Set params for model
1468
     * 
1469
     * @param array $params
1470
     */
1471
    public function setParams($params)
1472
    {
1473
        static::fixPrefix($params);
1474
        $className = get_called_class();
1475
        foreach ($params as $paramName => $value) {
1476
            $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $paramName);
1477
            if (!empty($className::$cols[$shortName])) {
1478
                switch ($className::$cols[$shortName]['type']) {
1479
                    case 'decimal':
1480
                        $params[$paramName] = (float) $value;
1481
                        break;
1482
                    case 'number':
1483
                        $params[$paramName] = (int) $value;
1484
                        break;
1485
                    case 'bool':
1486
                        $params[$paramName] = (bool) $value;
1487
                        break;
1488
                }
1489
            }
1490
        }
1491
        $this->_params = array_merge($this->_params, $params);
1492
    }
1493
1494
    /**
1495
     * Return relation
1496
     * 
1497
     * @param string $relName
1498
     * @return array|boolean
1499
     */
1500
    public static function getRelation($relName)
1501
    {
1502
        $relations = static::relations();
1503
        return !empty($relations[$relName]) ? $relations[$relName] : false;
1504
    }
1505
1506
    /**
1507
     * Load relation
1508
     * 
1509
     * @param string $name
1510
     * @param array $params
1511
     * @return null|array|integer|\Model
1512
     */
1513
    public function loadRelation($name, $params = [])
1514
    {
1515
        $relation = static::getRelation($name);
1516
        if ($relation) {
1517
            if (!isset($relation['type'])) {
1518
                $type = 'to';
1519
            } else {
1520
                $type = $relation['type'];
1521
            }
1522
            $getCol = null;
1523
            $getParams = [];
1524
            switch ($type) {
1525
                case 'relModel':
1526
                    if (!$this->pk()) {
1527
                        return [];
1528
                    }
1529
                    $fixedCol = $relation['model']::index();
1530
                    $relation['relModel']::fixPrefix($fixedCol);
1531
                    $ids = array_keys($relation['relModel']::getList(['where' => [$this->index(), $this->pk()], 'array' => true, 'key' => $fixedCol]));
1532
                    if (empty($ids)) {
1533
                        if (empty($params['count'])) {
1534
                            return [];
1535
                        } else {
1536
                            return 0;
1537
                        }
1538
                    }
1539
                    $getType = 'getList';
1540
                    $options = [
1541
                        'where' => [$relation['model']::index(), implode(',', $ids), 'IN'],
1542
                        'array' => (!empty($params['array'])) ? true : false,
1543
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1544
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1545
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1546
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1547
                    ];
1548
                    break;
1549
                case 'many':
1550
                    if (!$this->{$this->index()}) {
1551
                        return [];
1552
                    }
1553
                    $getType = 'getList';
1554
                    $options = [
1555
                        'join' => (isset($relation['join'])) ? $relation['join'] : null,
1556
                        'key' => (isset($params['key'])) ? $params['key'] : ((isset($relation['resultKey'])) ? $relation['resultKey'] : null),
1557
                        'array' => (!empty($params['array'])) ? true : false,
1558
                        'forSelect' => (!empty($params['forSelect'])) ? true : false,
1559
                        'order' => (isset($params['order'])) ? $params['order'] : ((isset($relation['order'])) ? $relation['order'] : null),
1560
                        'start' => (isset($params['start'])) ? $params['start'] : ((isset($relation['start'])) ? $relation['start'] : null),
1561
                        'limit' => (isset($params['limit'])) ? $params['limit'] : ((isset($relation['limit'])) ? $relation['limit'] : null),
1562
                        'appType' => (isset($params['appType'])) ? $params['appType'] : ((isset($relation['appType'])) ? $relation['appType'] : null),
1563
                        'where' => []
1564
                    ];
1565
                    $options['where'][] = [$relation['col'], $this->{$this->index()}];
1566
                    if (!empty($relation['where'])) {
1567
                        $options['where'] = array_merge($options['where'], [$relation['where']]);
1568
                    }
1569
                    if (!empty($params['where'])) {
1570
                        $options['where'] = array_merge($options['where'], [$params['where']]);
1571
                    }
1572
                    break;
1573
                case 'one':
1574
                    $getType = 'get';
1575
                    $options = [$relation['col'], $this->pk()];
1576
                    break;
1577
                default:
1578
                    if ($this->$relation['col'] === NULL) {
1579
                        return null;
1580
                    }
1581
                    $getType = 'get';
1582
                    $options = $this->$relation['col'];
1583
                    $getParams['appType'] = $this->appType;
1584
            }
1585
            if (!empty($params['count'])) {
1586
                if (class_exists($relation['model'])) {
1587
                    return $relation['model']::getCount($options);
1588
                }
1589
                return 0;
1590
            } else {
1591
                if (class_exists($relation['model'])) {
1592
                    $this->loadedRelations[$name][json_encode($params)] = $relation['model']::$getType($options, $getCol, $getParams);
1593
                } else {
1594
                    $this->loadedRelations[$name][json_encode($params)] = [];
1595
                }
1596
            }
1597
            return $this->loadedRelations[$name][json_encode($params)];
1598
        }
1599
        return NULL;
1600
    }
1601
1602
    /**
1603
     * Add relation item
1604
     * 
1605
     * @param string $relName
1606
     * @param \Model $objectId
1607
     * @return boolean
1608
     */
1609
    public function addRelation($relName, $objectId)
1610
    {
1611
        $relations = $this->relations();
1612
        if (isset($relations[$relName])) {
1613
            $relation = $relations[$relName];
1614
            App::$cur->db->where($relation['relTablePrefix'] . $this->index(), $this->pk());
1615
            App::$cur->db->where($relation['relTablePrefix'] . $relation['model']::index(), $objectId);
1616
            $isset = App::$cur->db->select($relation['relTable'])->fetch_assoc();
1617
            if ($isset)
1618
                return true;
1619
1620
            App::$cur->db->insert($relation['relTable'], [
1621
                $relation['relTablePrefix'] . $this->index() => $this->{$this->index()},
1622
                $relation['relTablePrefix'] . $relation['model']::index() => $objectId
1623
            ]);
1624
            return true;
1625
        }
1626
        return false;
1627
    }
1628
1629
    /**
1630
     * Check user access for form
1631
     * 
1632
     * @param string $formName
1633
     * @return boolean
1634
     */
1635
    public function checkFormAccess($formName)
1636
    {
1637
        if ($formName == 'manage' && !Users\User::$cur->isAdmin()) {
1638
            return false;
1639
        }
1640
        return true;
1641
    }
1642
1643
    /**
1644
     * Check access for model
1645
     * 
1646
     * @param string $mode
1647
     * @param \Users\User $user
1648
     * @return boolean
1649
     */
1650
    public function checkAccess($mode = 'write', $user = null)
1651
    {
1652
        if (!$user) {
1653
            $user = \Users\User::$cur;
1654
        }
1655
        return $user->isAdmin();
1656
    }
1657
1658
    /**
1659
     * Param and relation with params getter
1660
     * 
1661
     * @param string $name
1662
     * @param array $params
1663
     * @return \Value|mixed
1664
     */
1665
    public function __call($name, $params)
1666
    {
1667
        $fixedName = $name;
1668
        static::fixPrefix($fixedName);
1669 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...
1670
            return new Value($this, $fixedName);
1671
        } elseif (isset($this->_params[$name])) {
1672
            return new Value($this, $name);
1673
        }
1674
        return call_user_func_array([$this, 'loadRelation'], array_merge([$name], $params));
1675
    }
1676
1677
    /**
1678
     * Param and relation getter
1679
     * 
1680
     * @param string $name
1681
     * @return mixed
1682
     */
1683
    public function __get($name)
1684
    {
1685
        $fixedName = $name;
1686
        static::fixPrefix($fixedName);
1687
        if (isset($this->_params[$fixedName])) {
1688
            return $this->_params[$fixedName];
1689
        }
1690
        if (isset($this->loadedRelations[$name][json_encode([])])) {
1691
            return $this->loadedRelations[$name][json_encode([])];
1692
        }
1693
        return $this->loadRelation($name);
1694
    }
1695
1696
    /**
1697
     * Return model value in object
1698
     * 
1699
     * @param string $name
1700
     * @return \Value|null
1701
     */
1702
    public function value($name)
1703
    {
1704
        $fixedName = $name;
1705
        static::fixPrefix($fixedName);
1706 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...
1707
            return new Value($this, $fixedName);
1708
        } elseif ($this->_params[$name]) {
1709
            return new Value($this, $name);
1710
        }
1711
        return null;
1712
    }
1713
1714
    /**
1715
     * Return manager filters
1716
     * 
1717
     * @return array
1718
     */
1719
    public static function managerFilters()
1720
    {
1721
        return [];
1722
    }
1723
1724
    /**
1725
     * Return validators for cols
1726
     * 
1727
     * @return array
1728
     */
1729
    public static function validators()
1730
    {
1731
        return [];
1732
    }
1733
1734
    /**
1735
     * Return validator by name
1736
     * 
1737
     * @param string $name
1738
     * @return array
1739
     */
1740
    public static function validator($name)
1741
    {
1742
        $validators = static::validators();
1743
        if (!empty($validators[$name])) {
1744
            return $validators[$name];
1745
        }
1746
        return [];
1747
    }
1748
1749
    /**
1750
     * Set handler for model params
1751
     * 
1752
     * @param string $name
1753
     * @param mixed $value
1754
     */
1755
    public function __set($name, $value)
1756
    {
1757
        static::fixPrefix($name);
1758
        $className = get_called_class();
1759
        $shortName = preg_replace('!' . $this->colPrefix() . '!', '', $name);
1760
        if (!empty($className::$cols[$shortName])) {
1761
            switch ($className::$cols[$shortName]['type']) {
1762
                case 'decimal':
1763
                    $value = (float) $value;
1764
                    break;
1765
                case 'number':
1766
                    $value = (int) $value;
1767
                    break;
1768
                case 'bool':
1769
                    $value = (bool) $value;
1770
                    break;
1771
            }
1772
        }
1773
        if ((isset($this->_params[$name]) && $this->_params[$name] != $value) && !isset($this->_changedParams[$name])) {
1774
            $this->_changedParams[$name] = $this->_params[$name];
1775
        }
1776
1777
        $this->_params[$name] = $value;
1778
    }
1779
1780
    /**
1781
     * Isset handler for model params
1782
     * 
1783
     * @param string $name
1784
     * @return boolean
1785
     */
1786
    public function __isset($name)
1787
    {
1788
        static::fixPrefix($name);
1789
        return isset($this->_params[$name]);
1790
    }
1791
1792
    /**
1793
     * Convert object to string
1794
     * 
1795
     * @return string
1796
     */
1797
    public function __toString()
1798
    {
1799
        return $this->name();
1800
    }
1801
1802
}
1803