Completed
Push — master ( 769e25...bb4ee9 )
by Maxim
02:29
created

MODxAPI::fromJson()   C

Complexity

Conditions 8
Paths 5

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 2 Features 0
Metric Value
c 3
b 2
f 0
dl 0
loc 24
rs 5.7377
cc 8
eloc 15
nc 5
nop 2
1
<?php
2
include_once(MODX_BASE_PATH . 'assets/lib/APIHelpers.class.php');
3
include_once(MODX_BASE_PATH . 'assets/snippets/DocLister/lib/jsonHelper.class.php');
4
include_once(MODX_BASE_PATH . 'assets/snippets/DocLister/lib/DLCollection.class.php');
5
6
use \Doctrine\Common\Cache\Cache;
0 ignored issues
show
Bug introduced by
The type Doctrine\Common\Cache\Cache was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
8
/**
9
 * Class MODxAPIhelpers
10
 */
11
class MODxAPIhelpers
12
{
13
14
    /**
15
     * @param $email
16
     * @param bool $dns
17
     * @return false|string
18
     */
19
    public function emailValidate($email, $dns = true)
20
    {
21
        return \APIhelpers::emailValidate($email, $dns);
0 ignored issues
show
Bug Best Practice introduced by
The expression return APIhelpers::emailValidate($email, $dns) returns the type boolean which is incompatible with the documented return type false|string.
Loading history...
22
    }
23
24
    /**
25
     * @param $len
26
     * @param string $data
27
     * @return string
28
     */
29
    public function genPass($len, $data = '')
30
    {
31
        return \APIhelpers::genPass($len, $data);
32
    }
33
34
    /**
35
     * @param string $out
36
     * @return string
37
     */
38
    public function getUserIP($out = '127.0.0.1')
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
39
    {
40
        return \APIhelpers::getUserIP($out);
41
    }
42
43
    /**
44
     * @param $data
45
     * @return array|mixed|string
46
     */
47
    public function sanitarTag($data)
48
    {
49
        return \APIhelpers::sanitarTag($data);
50
    }
51
52
    /**
53
     * @param $value
54
     * @param int $minLen
55
     * @param array $alph
56
     * @param array $mixArray
57
     * @return bool
58
     */
59
    public function checkString($value, $minLen = 1, $alph = array(), $mixArray = array())
60
    {
61
        return \APIhelpers::checkString($value, $minLen, $alph, $mixArray);
62
    }
63
}
64
65
/**
66
 * Class MODxAPI
67
 */
68
abstract class MODxAPI extends MODxAPIhelpers
69
{
70
    /**
71
     * Объект DocumentParser - основной класс MODX
72
     * @var \DocumentParser
73
     * @access protected
74
     */
75
    protected $modx = null;
76
77
    /**
78
     * @var array
79
     */
80
    protected $log = array();
81
82
    /**
83
     * @var array
84
     */
85
    protected $field = array();
86
87
    /**
88
     * @var array
89
     */
90
    protected $default_field = array();
91
92
    /**
93
     * @var null|integer|string
94
     */
95
    protected $id = null;
96
97
    /**
98
     * @var array
99
     */
100
    protected $set = array();
101
102
    /**
103
     * @var bool
104
     */
105
    protected $newDoc = false;
106
107
    /**
108
     * @var string
109
     */
110
    protected $pkName = 'id';
111
112
    /**
113
     * @var string
114
     */
115
    protected $ignoreError = '';
116
117
    /**
118
     * @var bool
119
     */
120
    protected $_debug = false;
121
122
    /**
123
     * @var array
124
     */
125
    protected $_query = array();
126
127
    /**
128
     * @var array
129
     */
130
    protected $jsonFields = array();
131
132
    /**
133
     * @var array
134
     */
135
    protected $store = array();
136
137
    /**
138
     * @var DLCollection
139
     */
140
    protected $_decodedFields;
141
142
    /**
143
     * @var array
144
     */
145
    private $_table = array();
146
147
    private $cache = false;
148
149
    /**
150
     * MODxAPI constructor.
151
     * @param DocumentParser $modx
152
     * @param bool $debug
153
     * @throws Exception
154
     */
155
    public function __construct(DocumentParser $modx, $debug = false)
156
    {
157
        $this->modx = $modx;
158
        if (function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc()) {
159
            throw new Exception('Magic Quotes is a deprecated and mostly useless setting that should be disabled. Please ask your server administrator to disable it in php.ini or in your webserver config.');
160
        }
161
162
        $this->setDebug($debug);
163
        $this->_decodedFields = new DLCollection($this->modx);
164
        $this->cache = isset($this->modx->cache) && $this->modx->cache instanceof Cache;
165
    }
166
167
    /**
168
     * @param boolean $flag
169
     * @return $this
170
     */
171
    public function setDebug($flag)
172
    {
173
        $this->_debug = (bool)$flag;
174
175
        return $this;
176
    }
177
178
    /**
179
     * @return bool
180
     */
181
    public function getDebug()
182
    {
183
        return $this->_debug;
184
    }
185
186
    /**
187
     * @return array
188
     */
189
    public function getDefaultFields()
190
    {
191
        return $this->default_field;
192
    }
193
194
    /**
195
     * @param $value
196
     * @return int|mixed|string
197
     */
198
    protected function getTime($value)
199
    {
200
        $value = trim($value);
201
        if (!empty($value)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
202
            if (!is_numeric($value)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
203
                $value = (int)strtotime($value);
204
            }
205
            if (!empty($value)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
206
                $value += $this->modxConfig('server_offset_time');
207
            }
208
        }
209
210
        return $value;
211
    }
212
213
    /**
214
     * @param string $name
215
     * @param null $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
216
     * @return mixed
217
     */
218
    final public function modxConfig($name, $default = null)
219
    {
220
        return APIHelpers::getkey($this->modx->config, $name, $default);
221
    }
222
223
    /**
224
     * @param $q
225
     * @return $this
226
     */
227
    public function addQuery($q)
228
    {
229
        if (is_scalar($q) && !empty($q)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
230
            $this->_query[] = $q;
231
        }
232
233
        return $this;
234
    }
235
236
    /**
237
     * @return array
238
     */
239
    public function getQueryList()
240
    {
241
        return $this->_query;
242
    }
243
244
    /**
245
     * @param $SQL
246
     * @return mixed
247
     */
248
    final public function query($SQL)
249
    {
250
        if ($this->getDebug()) {
251
            $this->addQuery($SQL);
252
        }
253
254
        return empty($SQL) ? null : $this->modx->db->query($SQL);
255
    }
256
257
    /**
258
     * @param $value
259
     * @return string|void
260
     */
261
    final public function escape($value)
262
    {
263
        if (!is_scalar($value)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
264
            $value = '';
265
        } else {
266
            $value = $this->modx->db->escape($value);
267
        }
268
269
        return $value;
270
    }
271
272
    /**
273
     * @param string $name
274
     * @param array $data
275
     * @param bool $flag
276
     * @return $this
277
     */
278
    final public function invokeEvent($name, $data = array(), $flag = false)
279
    {
280
        if ((bool)$flag === true) {
281
            $this->modx->invokeEvent($name, $data);
282
        }
283
284
        return $this;
285
    }
286
287
    /**
288
     * @param string $name
289
     * @param array $data
290
     * @param boolean $flag
291
     * @return array|bool
292
     */
293
    final public function getInvokeEventResult($name, $data = array(), $flag = null)
294
    {
295
        $flag = (isset($flag) && $flag != '') ? (bool)$flag : false;
296
297
        return $flag ? $this->modx->invokeEvent($name, $data) : false;
298
    }
299
300
    /**
301
     * @return $this
302
     */
303
    final public function clearLog()
304
    {
305
        $this->log = array();
306
307
        return $this;
308
    }
309
310
    /**
311
     * @return array
312
     */
313
    final public function getLog()
314
    {
315
        return $this->log;
316
    }
317
318
    /**
319
     * @param bool $flush
320
     * @return $this
321
     */
322
    final public function list_log($flush = false)
0 ignored issues
show
Coding Style introduced by
Method name "MODxAPI::list_log" is not in camel caps format
Loading history...
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
323
    {
324
        echo '<pre>' . print_r(APIHelpers::sanitarTag($this->log), true) . '</pre>';
325
        if ($flush) {
326
            $this->clearLog();
327
        }
328
329
        return $this;
330
    }
331
332
    /**
333
     * @param bool $full
334
     * @return string
335
     */
336
    final public function getCachePath($full = true)
337
    {
338
        $path = $this->modx->getCachePath();
339
        if ($full) {
340
            $path = MODX_BASE_PATH . substr($path, strlen(MODX_BASE_URL));
341
        }
342
343
        return $path;
344
    }
345
346
    /**
347
     * @param boolean $fire_events
348
     * @param bool $custom
349
     */
350
    final public function clearCache($fire_events = false, $custom = false)
0 ignored issues
show
Coding Style introduced by
Function's nesting level (5) exceeds 3; consider refactoring the function
Loading history...
351
    {
352
        $IDs = array();
353
        if ($custom === false) {
354
            $this->modx->clearCache();
355
            include_once(MODX_MANAGER_PATH . 'processors/cache_sync.class.processor.php');
356
            $sync = new synccache();
0 ignored issues
show
Bug introduced by
The type synccache was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
357
            $path = $this->getCachePath(true);
358
            $sync->setCachepath($path);
359
            $sync->setReport(false);
360
            $sync->emptyCache();
361
        } else {
362
            if (is_scalar($custom)) {
0 ignored issues
show
introduced by
The condition is_scalar($custom) is always true.
Loading history...
363
                $custom = array($custom);
364
            }
365
            switch ($this->modx->config['cache_type']) {
366
                case 2:
367
                    $cacheFile = "_*.pageCache.php";
368
                    break;
369
                default:
370
                    $cacheFile = ".pageCache.php";
371
            }
372
            if (is_array($custom)) {
0 ignored issues
show
introduced by
The condition is_array($custom) is always true.
Loading history...
373
                foreach ($custom as $id) {
374
                    $tmp = glob(MODX_BASE_PATH . "assets/cache/docid_" . $id . $cacheFile);
0 ignored issues
show
Bug introduced by
Are you sure $id of type true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

374
                    $tmp = glob(MODX_BASE_PATH . "assets/cache/docid_" . /** @scrutinizer ignore-type */ $id . $cacheFile);
Loading history...
375
                    foreach ($tmp as $file) {
376
                        if (is_readable($file)) {
377
                            unlink($file);
378
                        }
379
                        $IDs[] = $id;
380
                    }
381
                }
382
            }
383
            clearstatcache();
384
        }
385
        $this->invokeEvent('OnSiteRefresh', array('IDs' => $IDs), $fire_events);
386
    }
387
388
    /**
389
     * @param integer $id
390
     * @return MODxAPI
391
     */
392
    public function switchObject($id)
393
    {
394
        switch (true) {
395
            //Если загружен другой объект - не тот, с которым мы хотим временно поработать
396
            case ($this->getID() != $id && $id):
397
                $obj = clone $this;
398
                $obj->edit($id);
399
                break;
400
            //Если уже загружен объект, с которым мы хотим временно поработать
401
            case ($this->getID() == $id && $id):
402
                //Если $id не указан, но уже загружен какой-то объект
403
            case (!$id && null !== $this->getID()):
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
404
            default:
405
                $obj = $this;
406
                break;
407
        }
408
409
        return $obj;
410
    }
411
412
    /**
413
     * @param bool $flag
414
     * @return $this
415
     */
416
    public function useIgnore($flag = true)
417
    {
418
        $this->ignoreError = $flag ? 'IGNORE' : '';
419
420
        return $this;
421
    }
422
423
    /**
424
     * @return bool
425
     */
426
    public function hasIgnore()
427
    {
428
        return (bool)$this->ignoreError;
429
    }
430
431
    /**
432
     * @param $key
433
     * @param $value
434
     * @return $this
435
     */
436
    public function set($key, $value)
437
    {
438
        if ((is_scalar($value) || $this->isJsonField($key)) && is_scalar($key) && !empty($key)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
439
            $this->field[$key] = $value;
440
        }
441
442
        return $this;
443
    }
444
445
    /**
446
     * @return null|int
447
     */
448
    final public function getID()
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
449
    {
450
        return $this->id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->id also could return the type string which is incompatible with the documented return type null|integer.
Loading history...
451
    }
452
453
    /**
454
     * @param $key
455
     * @return mixed
456
     */
457
    public function get($key)
458
    {
459
        return APIHelpers::getkey($this->field, $key, null);
460
    }
461
462
    /**
463
     * @param $data
464
     * @return $this
465
     */
466
    public function fromArray($data)
467
    {
468
        if (is_array($data)) {
469
            foreach ($data as $key => $value) {
470
                $this->set($key, $value);
471
            }
472
        }
473
474
        return $this;
475
    }
476
477
    /**
478
     * Формирует массив значений для подстановки в SQL запрос на обновление
479
     *
480
     * @param $key
481
     * @param string $id
482
     * @return $this
483
     * @throws Exception
484
     */
485
    final protected function Uset($key, $id = '')
0 ignored issues
show
Coding Style introduced by
Method name "MODxAPI::Uset" is not in camel caps format
Loading history...
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
486
    {
487
        if (!isset($this->field[$key])) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
488
            $tmp = "`{$key}`=''";
489
            $this->log[] = "{$key} is empty";
490
        } else {
491
            if ($this->issetField($key) && is_scalar($this->field[$key])) {
492
                $tmp = "`{$key}`='{$this->escape($this->field[$key])}'";
493
            } else {
494
                throw new Exception("{$key} is invalid <pre>" . print_r($this->field[$key], true) . "</pre>");
495
            }
496
        }
497
        if (!empty($tmp) && $this->isChanged($key)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
498
            if ($id == '') {
499
                $this->set[] = $tmp;
500
            } else {
501
                $this->set[$id][] = $tmp;
502
            }
503
        }
504
505
        return $this;
506
    }
507
508
    /**
509
     * Сохраняет начальные значения полей
510
     *
511
     * @param array $data
512
     * @return $this
513
     */
514
    public function store($data = array())
515
    {
516
        if (is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($data) is always true.
Loading history...
517
            $this->store = $data;
518
        }
519
520
        return $this;
521
    }
522
523
    /**
524
     * Откатывает изменения отдельного поля или всех полей сразу
525
     *
526
     * @param string $key
527
     * @return MODxAPI
528
     */
529
    public function rollback($key = '')
530
    {
531
        if (!empty($key) && isset($this->store[$key])) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
532
            $this->set($key, $this->store[$key]);
533
        } else {
534
            $this->fromArray($this->store);
535
        }
536
537
        return $this;
538
    }
539
540
    /**
541
     * Проверяет изменилось ли поле
542
     *
543
     * @param $key
544
     * @return bool
545
     */
546
    public function isChanged($key)
547
    {
548
        $flag = !isset($this->store[$key]) || (isset($this->store[$key]) && $this->store[$key] != $this->field[$key]);
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
549
550
        return $flag;
551
    }
552
553
    /**
554
     * @param $IDs
555
     * @param string $sep
556
     * @param integer[] $ignore
557
     * @return array
558
     * @throws Exception
559
     */
560
    final public function cleanIDs($IDs, $sep = ',', $ignore = array())
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
561
    {
562
        $out = APIhelpers::cleanIDs($IDs, $sep, $ignore);
563
564
        return $out;
565
    }
566
567
    /**
568
     * @param $data
569
     * @param null $callback
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $callback is correct as it would always require null to be passed?
Loading history...
570
     * @return $this
571
     * @throws Exception
572
     */
573
    final public function fromJson($data, $callback = null)
574
    {
575
        if (is_scalar($data) && !empty($data)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
576
            $json = json_decode($data);
577
        } else {
578
            throw new Exception("json is not string with json data");
579
        }
580
581
        if ($this->jsonError($json)) {
582
            if (isset($callback) && is_callable($callback)) {
583
                call_user_func_array($callback, array($json));
584
            } else {
585
                if (isset($callback)) {
586
                    throw new Exception("Can't call callback JSON unpack <pre>" . print_r($callback, 1) . "</pre>");
587
                }
588
                foreach ($json as $key => $val) {
589
                    $this->set($key, $val);
590
                }
591
            }
592
        } else {
593
            throw new Exception('Error from JSON decode: <pre>' . print_r($data, 1) . '</pre>');
594
        }
595
596
        return $this;
597
    }
598
599
    /**
600
     * @param null $callback
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $callback is correct as it would always require null to be passed?
Loading history...
601
     * @return string
602
     * @throws Exception
603
     */
604
    final public function toJson($callback = null)
605
    {
606
        $data = $this->toArray();
607
        if (isset($callback) && is_callable($callback)) {
608
            $data = call_user_func_array($callback, array($data));
609
        } else {
610
            if (isset($callback)) {
611
                throw new Exception("Can't call callback JSON pre pack <pre>" . print_r($callback, 1) . "</pre>");
612
            }
613
        }
614
        $json = json_encode($data);
615
616
        if ($this->jsonError($data)) {
617
            throw new Exception('Error from JSON decode: <pre>' . print_r($data, 1) . '</pre>');
618
        }
619
620
        return $json;
621
    }
622
623
    /**
624
     * @param $data
625
     * @return bool
626
     */
627
    final protected function jsonError($data)
628
    {
629
        $flag = false;
630
        if (json_last_error() === JSON_ERROR_NONE && is_object($data) && $data instanceof stdClass) {
631
            $flag = true;
632
        }
633
634
        return $flag;
635
    }
636
637
    /**
638
     * @param string $prefix
639
     * @param string $suffix
640
     * @param string $sep
641
     * @return array
642
     */
643
    public function toArray($prefix = '', $suffix = '', $sep = '_')
644
    {
645
        $tpl = '';
646
        $plh = '[+key+]';
647
        if ($prefix !== '') {
648
            $tpl = $prefix . $sep;
649
        }
650
        $tpl .= $plh;
651
        if ($suffix !== '') {
652
            $tpl .= $sep . $suffix;
653
        }
654
        $out = array();
655
        $fields = $this->field;
656
        $fields[$this->fieldPKName()] = $this->getID();
657
        if ($tpl != $plh) {
658
            foreach ($fields as $key => $value) {
659
                $out[str_replace($plh, $key, $tpl)] = $value;
660
            }
661
        } else {
662
            $out = $fields;
663
        }
664
665
        return $out;
666
    }
667
668
    /**
669
     * @return string
670
     */
671
    final public function fieldPKName()
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
672
    {
673
        return $this->pkName;
674
    }
675
676
    /**
677
     * @param $table
678
     * @return mixed|string
679
     */
680
    final public function makeTable($table)
681
    {
682
        //Без использования APIHelpers::getkey(). Иначе getFullTableName будет всегда выполняться
683
        return (isset($this->_table[$table])) ? $this->_table[$table] : $this->modx->getFullTableName($table);
684
    }
685
686
    /**
687
     * @param $data
688
     * @param string $sep
689
     * @return array|string
690
     */
691
    final public function sanitarIn($data, $sep = ',')
692
    {
693
        if (!is_array($data)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
694
            $data = explode($sep, $data);
695
        }
696
        $out = array();
697
        foreach ($data as $item) {
698
            if ($item !== '') {
699
                $out[] = $this->escape($item);
700
            }
701
        }
702
        $out = empty($out) ? '' : "'" . implode("','", $out) . "'";
703
704
        return $out;
705
    }
706
707
    /**
708
     * @param string $table
709
     * @param string $field
710
     * @param string $PK
711
     * @return bool
712
     */
713
    public function checkUnique($table, $field, $PK = 'id')
714
    {
715
        if (is_array($field)) {
0 ignored issues
show
introduced by
The condition is_array($field) is always false.
Loading history...
716
            $where = array();
717
            foreach ($field as $_field) {
718
                $val = $this->get($_field);
719
                if ($val != '') {
720
                    $where[] = "`" . $this->escape($_field) . "` = '" . $this->escape($val) . "'";
721
                }
722
            }
723
            $where = implode(' AND ', $where);
724
        } else {
725
            $where = '';
726
            $val = $this->get($field);
727
            if ($val != '') {
728
                $where = "`" . $this->escape($field) . "` = '" . $this->escape($val) . "'";
729
            }
730
        }
731
732
        if ($where != '') {
733
            $sql = $this->query("SELECT `" . $this->escape($PK) . "` FROM " . $this->makeTable($table) . " WHERE " . $where);
734
            $id = $this->modx->db->getValue($sql);
735
            if (!$id || (!$this->newDoc && $id == $this->getID())) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
736
                $flag = true;
737
            } else {
738
                $flag = false;
739
            }
740
        } else {
741
            $flag = false;
742
        }
743
744
        return $flag;
745
    }
746
747
    /**
748
     * @param array $data
749
     * @return $this
750
     */
751
    public function create($data = array())
752
    {
753
        $this->close();
754
        $this->fromArray($data);
755
756
        return $this;
757
    }
758
759
    /**
760
     * @param $id
761
     * @return $this
762
     */
763
    public function copy($id)
764
    {
765
        $this->edit($id)->id = 0;
766
        $this->newDoc = true;
767
        $this->store = array();
768
769
        return $this;
770
    }
771
772
    /**
773
     *
774
     */
775
    public function close()
776
    {
777
        $this->newDoc = true;
778
        $this->id = null;
779
        $this->field = array();
780
        $this->set = array();
781
        $this->store = array();
782
        $this->markAllDecode();
783
    }
784
785
    /**
786
     * @param $key
787
     * @return bool
788
     */
789
    public function issetField($key)
790
    {
791
        return (is_scalar($key) && array_key_exists($key, $this->default_field));
792
    }
793
794
    /**
795
     * @param $id
796
     * @return mixed
797
     */
798
    abstract public function edit($id);
799
800
    /**
801
     * @param bool $fire_events
802
     * @param bool $clearCache
803
     * @return mixed
804
     */
805
    abstract public function save($fire_events = false, $clearCache = false);
806
807
    /**
808
     * @param $ids
809
     * @param null $fire_events
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $fire_events is correct as it would always require null to be passed?
Loading history...
810
     * @return mixed
811
     */
812
    abstract public function delete($ids, $fire_events = null);
813
814
    /**
815
     * @param $data
816
     * @return array|mixed|string
817
     */
818
    final public function sanitarTag($data)
819
    {
820
        return parent::sanitarTag($this->modx->stripTags($data));
821
    }
822
823
    /**
824
     * @param string $version
825
     * @param bool $dmi3yy
826
     * @return bool
827
     */
828
    final protected function checkVersion($version, $dmi3yy = true)
829
    {
830
        $flag = false;
831
        $currentVer = $this->modx->getVersionData('version');
832
        if (is_array($currentVer)) {
833
            $currentVer = APIHelpers::getkey($currentVer, 'version', '');
834
        }
835
        $tmp = substr($currentVer, 0, strlen($version));
836
        if (version_compare($tmp, $version, '>=')) {
837
            $flag = true;
838
            if ($dmi3yy) {
839
                $flag = (boolean)preg_match('/^' . $tmp . '(.*)\-d/', $currentVer);
840
            }
841
        }
842
843
        return $flag;
844
    }
845
846
    /**
847
     * @param string $name
848
     * @return bool|mixed
849
     */
850
    protected function eraseField($name)
851
    {
852
        $flag = false;
853
        if (array_key_exists($name, $this->field)) {
854
            $flag = $this->field[$name];
855
            unset($this->field[$name]);
856
        }
857
858
        return $flag;
859
    }
860
861
    /**
862
     * Может ли содержать данное поле json массив
863
     * @param  string $field имя поля
864
     * @return boolean
865
     */
866
    public function isJsonField($field)
867
    {
868
        return (is_scalar($field) && in_array($field, $this->jsonFields));
869
    }
870
871
    /**
872
     * Пометить поле как распакованное
873
     * @param  string $field имя поля
874
     * @return $this
875
     */
876
    public function markAsDecode($field)
877
    {
878
        if (is_scalar($field)) {
0 ignored issues
show
introduced by
The condition is_scalar($field) is always true.
Loading history...
879
            $this->_decodedFields->set($field, false);
880
        }
881
882
        return $this;
883
    }
884
885
    /**
886
     * Пометить поле как запакованное
887
     * @param  string $field имя поля
888
     * @return $this
889
     */
890
    public function markAsEncode($field)
891
    {
892
        if (is_scalar($field)) {
0 ignored issues
show
introduced by
The condition is_scalar($field) is always true.
Loading history...
893
            $this->_decodedFields->set($field, true);
894
        }
895
896
        return $this;
897
    }
898
899
    /**
900
     * Пометить все поля как запакованные
901
     * @return $this
902
     */
903
    public function markAllEncode()
904
    {
905
        $this->_decodedFields->clear();
906
        foreach ($this->jsonFields as $field) {
907
            $this->markAsEncode($field);
908
        }
909
910
        return $this;
911
    }
912
913
    /**
914
     * Пометить все поля как распакованные
915
     * @return $this
916
     */
917
    public function markAllDecode()
918
    {
919
        $this->_decodedFields->clear();
920
        foreach ($this->jsonFields as $field) {
921
            $this->markAsDecode($field);
922
        }
923
924
        return $this;
925
    }
926
927
    /**
928
     * Получить список не запакованных полей
929
     * @return DLCollection
930
     */
931
    public function getNoEncodeFields()
932
    {
933
        return $this->_decodedFields->filter(function ($value) {
934
            return ($value === false);
935
        });
936
    }
937
938
    /**
939
     * Получить список не распакованных полей
940
     * @return DLCollection
941
     */
942
    public function getNoDecodeFields()
943
    {
944
        return $this->_decodedFields->filter(function ($value) {
945
            return ($value === true);
946
        });
947
    }
948
949
    /**
950
     * Можно ли данное декодировать с помощью json_decode
951
     * @param  string $field имя поля
952
     * @return boolean
953
     */
954
    public function isDecodableField($field)
955
    {
956
        $data = $this->get($field);
957
958
        /**
959
         * Если поле скалярного типа и оно не распаковывалось раньше
960
         */
961
962
        return (is_scalar($data) && is_scalar($field) && $this->_decodedFields->get($field) === true);
963
    }
964
965
    /**
966
     * Можно ли закодировать данные с помощью json_encode
967
     * @param  string $field имя поля
968
     * @return boolean
969
     */
970
    public function isEncodableField($field)
971
    {
972
        /**
973
         * Если поле было распаковано ранее и еще не упаковано
974
         */
975
        return (is_scalar($field) && $this->_decodedFields->get($field) === false);
976
    }
977
978
    /**
979
     * Декодирует конкретное поле
980
     * @param  string $field Имя поля
981
     * @param  bool $store обновить распакованное поле
982
     * @return array ассоциативный массив с данными из json строки
983
     */
984
    public function decodeField($field, $store = false)
985
    {
986
        $out = array();
987
        if ($this->isDecodableField($field)) {
988
            $data = $this->get($field);
989
            $out = jsonHelper::jsonDecode($data, array('assoc' => true), true);
990
        }
991
        if ($store) {
992
            $this->field[$field] = $out;
993
            $this->markAsDecode($field);
994
        }
995
996
        return $out;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $out also could return the type xNop which is incompatible with the documented return type array.
Loading history...
997
    }
998
999
    /**
1000
     * Декодирование всех json полей
1001
     * @return $this
1002
     */
1003
    protected function decodeFields()
1004
    {
1005
        foreach ($this->getNoDecodeFields() as $field => $flag) {
1006
            $this->decodeField($field, true);
1007
        }
1008
1009
        return $this;
1010
    }
1011
1012
    /**
1013
     * Запаковывает конкретное поле в JSON
1014
     * @param  string $field Имя поля
1015
     * @param  bool $store обновить запакованное поле
1016
     * @return string|null json строка
1017
     */
1018
    public function encodeField($field, $store = false)
1019
    {
1020
        $out = null;
1021
        if ($this->isEncodableField($field)) {
1022
            $data = $this->get($field);
1023
            $out = json_encode($data);
1024
        }
1025
        if ($store) {
1026
            $this->field[$field] = $out;
1027
            $this->markAsEncode($field);
1028
        }
1029
1030
        return $out;
1031
    }
1032
1033
    /**
1034
     * Запаковка всех json полей
1035
     * @return $this
1036
     */
1037
    protected function encodeFields()
1038
    {
1039
        foreach ($this->getNoEncodeFields() as $field => $flag) {
1040
            $this->encodeField($field, true);
1041
        }
1042
1043
        return $this;
1044
    }
1045
1046
    /**
1047
     * @param mixed $data
1048
     * @param string $key
1049
     * @return bool
1050
     */
1051
    protected function saveToCache($data, $key)
1052
    {
1053
        $out = false;
1054
        if ($this->cache) {
1055
            $out = $this->modx->cache->save($key, $data, 0);
1056
        }
1057
1058
        return $out;
1059
    }
1060
1061
    /**
1062
     * @param string $key
1063
     * @return mixed
1064
     */
1065
    protected function loadFromCache($key)
1066
    {
1067
        $out = false;
1068
        if ($this->cache) {
1069
            $out = $this->modx->cache->fetch($key);
1070
        }
1071
1072
        return $out;
1073
    }
1074
1075
}
1076