Completed
Pull Request — master (#263)
by
unknown
02:10
created

modResource::encodeField()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 8
nop 2
dl 0
loc 18
rs 8.8571
c 0
b 0
f 0
1
<?php
2
require_once('MODx.php');
3
4
/**
5
 * Class modResource
6
 */
7
class modResource extends MODxAPI
8
{
9
    /**
10
     * @var string
11
     */
12
    protected $mode = 'new';
13
    /**
14
     * @var array
15
     */
16
    protected $default_field = array(
17
        'type'            => 'document',
18
        'contentType'     => 'text/html',
19
        'pagetitle'       => 'New document',
20
        'longtitle'       => '',
21
        'description'     => '',
22
        'alias'           => '',
23
        'link_attributes' => '',
24
        'published'       => 1,
25
        'pub_date'        => 0,
26
        'unpub_date'      => 0,
27
        'parent'          => 0,
28
        'isfolder'        => 0,
29
        'introtext'       => '',
30
        'content'         => '',
31
        'richtext'        => 1,
32
        'template'        => 0,
33
        'menuindex'       => 0,
34
        'searchable'      => 1,
35
        'cacheable'       => 1,
36
        'createdon'       => 0,
37
        'createdby'       => 0,
38
        'editedon'        => 0,
39
        'editedby'        => 0,
40
        'deleted'         => 0,
41
        'deletedon'       => 0,
42
        'deletedby'       => 0,
43
        'publishedon'     => 0,
44
        'publishedby'     => 0,
45
        'menutitle'       => '',
46
        'donthit'         => 0,
47
        'haskeywords'     => 0,
48
        'hasmetatags'     => 0,
49
        'privateweb'      => 0,
50
        'privatemgr'      => 0,
51
        'content_dispo'   => 0,
52
        'hidemenu'        => 0,
53
        'alias_visible'   => 1
54
    );
55
    /**
56
     * @var array
57
     */
58
    private $table = array(
59
        '"' => '_',
60
        "'" => '_',
61
        ' ' => '_',
62
        '.' => '_',
63
        ',' => '_',
64
        'а' => 'a',
65
        'б' => 'b',
66
        'в' => 'v',
67
        'г' => 'g',
68
        'д' => 'd',
69
        'е' => 'e',
70
        'ё' => 'e',
71
        'ж' => 'zh',
72
        'з' => 'z',
73
        'и' => 'i',
74
        'й' => 'y',
75
        'к' => 'k',
76
        'л' => 'l',
77
        'м' => 'm',
78
        'н' => 'n',
79
        'о' => 'o',
80
        'п' => 'p',
81
        'р' => 'r',
82
        'с' => 's',
83
        'т' => 't',
84
        'у' => 'u',
85
        'ф' => 'f',
86
        'х' => 'h',
87
        'ц' => 'c',
88
        'ч' => 'ch',
89
        'ш' => 'sh',
90
        'щ' => 'sch',
91
        'ь' => '',
92
        'ы' => 'y',
93
        'ъ' => '',
94
        'э' => 'e',
95
        'ю' => 'yu',
96
        'я' => 'ya',
97
        'А' => 'A',
98
        'Б' => 'B',
99
        'В' => 'V',
100
        'Г' => 'G',
101
        'Д' => 'D',
102
        'Е' => 'E',
103
        'Ё' => 'E',
104
        'Ж' => 'Zh',
105
        'З' => 'Z',
106
        'И' => 'I',
107
        'Й' => 'Y',
108
        'К' => 'K',
109
        'Л' => 'L',
110
        'М' => 'M',
111
        'Н' => 'N',
112
        'О' => 'O',
113
        'П' => 'P',
114
        'Р' => 'R',
115
        'С' => 'S',
116
        'Т' => 'T',
117
        'У' => 'U',
118
        'Ф' => 'F',
119
        'Х' => 'H',
120
        'Ц' => 'C',
121
        'Ч' => 'Ch',
122
        'Ш' => 'Sh',
123
        'Щ' => 'Sch',
124
        'Ь' => '',
125
        'Ы' => 'Y',
126
        'Ъ' => '',
127
        'Э' => 'E',
128
        'Ю' => 'Yu',
129
        'Я' => 'Ya',
130
    );
131
    /**
132
     * @var array массив ТВшек где name это ключ массива, а ID это значение
133
     */
134
    private $tv = array();
135
    /**
136
     * @var array массив ТВшек где ID это ключ массива, а name это значение
137
     */
138
    private $tvid = array();
139
    /**
140
     * @var array значения по умолчанию для ТВ параметров
141
     */
142
    private $tvd = array();
143
144
    /** @var array связи ТВ и шаблонов */
145
    private $tvTpl = array();
146
147
    /** @var array параметры ТВ с массивами */
148
    protected $tvaFields = array();
149
150
    /**
151
     * Массив администраторов
152
     * @var DLCollection
153
     */
154
    private $managerUsers = null;
155
156
    /**
157
     * modResource constructor.
158
     * @param DocumentParser $modx
159
     * @param bool $debug
160
     */
161
    public function __construct($modx, $debug = false)
162
    {
163
        parent::__construct($modx, $debug);
164
        $this->get_TV();
165
        $uTable = $this->makeTable("manager_users");
166
        $aTable = $this->makeTable("user_attributes");
167
        $query = "SELECT `u`.`id`, `a`.`email`, `u`.`username`  FROM " . $aTable . " as `a` LEFT JOIN " . $uTable . " as `u` ON `u`.`id`=`a`.`internalKey`";
168
        $query = $this->query($query);
169
        $this->managerUsers = new DLCollection($modx, empty($query) ? array() : $query);
170
    }
171
172
    /**
173
     * @return array
174
     */
175
    public function toArrayMain()
176
    {
177
        $out = array_intersect_key(parent::toArray(), $this->default_field);
178
179
        return $out;
180
    }
181
182
    /**
183
     * @param bool $render
184
     * @return array
185
     */
186
    public function toArrayTV($render = false)
187
    {
188
        $out = array_diff_key(parent::toArray(), $this->default_field);
189
        $tpl = $this->get('template');
190
        $tvTPL = APIHelpers::getkey($this->tvTpl, $tpl, array());
191
        foreach ($tvTPL as $item) {
192
            if (isset($this->tvid[$item]) && !array_key_exists($this->tvid[$item], $out)) {
193
                $out[$this->tvid[$item]] = $this->get($this->tvid[$item]);
194
            }
195
        }
196
        if ($render) {
197
            foreach ($out as $key => $val) {
198
                $out[$key] = $this->renderTV($key);
199
            }
200
        }
201
202
        return $out;
203
    }
204
205
    /**
206
     * @param string $prefix
207
     * @param string $suffix
208
     * @param string $sep
209
     * @param bool $render
210
     * @return array
211
     */
212
    public function toArray($prefix = '', $suffix = '', $sep = '_', $render = true)
213
    {
214
        $out = array_merge(
215
            $this->toArrayMain(),
216
            $this->toArrayTV($render),
217
            array($this->fieldPKName() => $this->getID())
218
        );
219
220
        return \APIhelpers::renameKeyArr($out, $prefix, $suffix, $sep);
221
    }
222
223
    /**
224
     * @return null|string
225
     */
226
    public function getUrl()
227
    {
228
        $out = null;
229
        $id = (int)$this->getID();
230
        if (!empty($id)) {
231
            $out = $this->modx->makeUrl($id);
232
        }
233
234
        return $out;
235
    }
236
237
    /**
238
     * @param string $main
239
     * @param string $second
240
     * @return mixed
241
     */
242
    public function getTitle($main = 'menutitle', $second = 'pagetitle')
243
    {
244
        $title = $this->get($main);
245
        if (empty($title) && $title !== '0') {
246
            $title = $this->get($second);
247
        }
248
249
        return $title;
250
    }
251
252
    /**
253
     * @return bool
254
     */
255
    public function isWebShow()
256
    {
257
        $pub = ($this->get('publishedon') < time() && $this->get('published'));
258
        $unpub = ($this->get('unpub_date') == 0 || $this->get('unpub_date') > time());
259
        $del = ($this->get('deleted') == 0 && ($this->get('deletedon') == 0 || $this->get('deletedon') > time()));
260
261
        return ($pub && $unpub && $del);
262
    }
263
264
    /**
265
     * @return $this
266
     */
267
    public function touch()
268
    {
269
        $this->set('editedon', time());
270
271
        return $this;
272
    }
273
274
    /**
275
     * @param $tvname
276
     * @return null|string
277
     */
278
    public function renderTV($tvname)
279
    {
280
        $out = null;
281
        if ($this->getID() > 0) {
282
            include_once MODX_MANAGER_PATH . "includes/tmplvars.format.inc.php";
283
            include_once MODX_MANAGER_PATH . "includes/tmplvars.commands.inc.php";
284
            $tvval = $this->get($tvname);
285
            if ($this->isTVarrayField($tvname) && is_array($tvval)) {
286
                $tvval = implode('||', $tvval);
287
            }
288
            $param = APIHelpers::getkey($this->tvd, $tvname, array());
289
            $display = APIHelpers::getkey($param, 'display', '');
290
            $display_params = APIHelpers::getkey($param, 'display_params', '');
291
            $type = APIHelpers::getkey($param, 'type', '');
292
            $out = getTVDisplayFormat($tvname, $tvval, $display, $display_params, $type, $this->getID(), '');
293
        }
294
295
        return $out;
296
    }
297
298
    /**
299
     * @param $key
300
     * @return mixed
301
     */
302
    public function get($key)
303
    {
304
        $out = parent::get($key);
305
        if (isset($this->tv[$key])) {
306
            $tpl = $this->get('template');
307
            $tvTPL = APIHelpers::getkey($this->tvTpl, $tpl, array());
308
            $tvID = APIHelpers::getkey($this->tv, $key, 0);
309
            if (in_array($tvID, $tvTPL) && is_null($out)) {
310
                $out = APIHelpers::getkey($this->tvd[$key], 'value', null);
311
            }
312
        }
313
314
        return $out;
315
    }
316
317
    /**
318
     * @param $key
319
     * @param $value
320
     * @return $this
321
     */
322
    public function set($key, $value)
323
    {
324
        if ((is_scalar($value) || $this->isTVarrayField($key) || $this->isJsonField($key)) && is_scalar($key) && !empty($key)) {
325
            switch ($key) {
326
                case 'parent':
327
                    $value = (int)$value;
328
                    break;
329
                case 'template':
330
                    $value = trim($value);
331
                    $value = $this->setTemplate($value);
332
                    break;
333
                case 'published':
334
                    $value = (int)((bool)$value);
335
                    if ($value) {
336
                        $this->field['publishedon'] = time() + $this->modxConfig('server_offset_time');
337
                    }
338
                    break;
339
                case 'pub_date':
340
                    $value = $this->getTime($value);
341
                    if ($value > 0 && time() + $this->modxConfig('server_offset_time') > $value) {
342
                        $this->field['published'] = 1;
343
                        $this->field['publishedon'] = $value;
344
                    }
345
                    break;
346
                case 'unpub_date':
347
                    $value = $this->getTime($value);
348
                    if ($value > 0 && time() + $this->modxConfig('server_offset_time') > $value) {
349
                        $this->field['published'] = 0;
350
                        $this->field['publishedon'] = 0;
351
                    }
352
                    break;
353
                case 'deleted':
354
                    $value = (int)((bool)$value);
355
                    if ($value) {
356
                        $this->field['deletedon'] = time() + $this->modxConfig('server_offset_time');
357
                    } else {
358
                        $this->field['deletedon'] = 0;
359
                    }
360
                    break;
361
                case 'deletedon':
362
                    $value = $this->getTime($value);
363
                    if ($value > 0 && time() + $this->modxConfig('server_offset_time') < $value) {
364
                        $value = 0;
365
                    }
366
                    if ($value) {
367
                        $this->field['deleted'] = 1;
368
                    }
369
                    break;
370
                case 'editedon':
371
                case 'createdon':
372
                case 'publishedon':
373
                    $value = $this->getTime($value);
374
                    break;
375
                case 'publishedby':
376
                case 'editedby':
377
                case 'createdby':
378
                case 'deletedby':
379
                    $value = $this->getUser($value, $this->default_field[$key]);
380
                    break;
381
            }
382
            $this->field[$key] = $value;
383
        }
384
385
        return $this;
386
    }
387
388
    /**
389
     * @param $value
390
     * @param int $default
391
     * @return int|mixed
392
     */
393
    protected function getUser($value, $default = 0)
394
    {
395
        $currentAdmin = APIHelpers::getkey($_SESSION, 'mgrInternalKey', 0);
396
        $value = (int)$value;
397
        if (!empty($value)) {
398
            $by = $this->findUserBy($value);
399
            $exists = $this->managerUsers->exists(function ($key, Helpers\Collection $val) use ($by, $value) {
400
                return ($val->containsKey($by) && $val->get($by) === (string)$value);
401
            });
402
            if (!$exists) {
403
                $value = 0;
404
            }
405
        }
406
        if (empty($value)) {
407
            $value = empty($currentAdmin) ? $default : $currentAdmin;
408
        }
409
410
        return $value;
411
    }
412
413
    /**
414
     * @param $data
415
     * @return bool|string
416
     */
417
    protected function findUserBy($data)
418
    {
419
        switch (true) {
420
            case (is_int($data) || ((int)$data > 0 && (string)intval($data) === $data)):
421
                $find = 'id';
422
                break;
423
            case filter_var($data, FILTER_VALIDATE_EMAIL):
424
                $find = 'email';
425
                break;
426
            case is_scalar($data):
427
                $find = 'username';
428
                break;
429
            default:
430
                $find = false;
431
        }
432
433
        return $find;
434
    }
435
436
    /**
437
     * @param $value
438
     * @return int|mixed|string
439
     */
440
    protected function getTime($value)
441
    {
442
        $value = trim($value);
443
        if (!empty($value)) {
444
            if (!is_numeric($value)) {
445
                $value = (int)strtotime($value);
446
            }
447
            if (!empty($value)) {
448
                $value += $this->modxConfig('server_offset_time');
449
            }
450
        }
451
452
        return $value;
453
    }
454
455
    /**
456
     * @param array $data
457
     * @return $this
458
     */
459
    public function create($data = array())
460
    {
461
        $this->close();
462
        $fld = array();
463
        foreach ($this->tvd as $name => $tv) {
464
            $fld[$name] = $tv['value'];
465
        };
466
        $this->store($fld);
467
468
        $this->fromArray(array_merge($fld, $data));
469
        $this->set('createdby', null)
470
            ->set('editedby', null)
471
            ->set('createdon', time())
472
            ->touch();
473
474
        return $this;
475
    }
476
477
    /**
478
     * @param $id
479
     * @return $this
480
     */
481
    public function edit($id)
482
    {
483
        $id = is_scalar($id) ? trim($id) : '';
484
        if ($this->getID() != $id) {
485
            $this->close();
486
            $this->markAllEncode();
487
            $this->newDoc = false;
488
489
            $result = $this->query("SELECT * from {$this->makeTable('site_content')} where `id`=" . (int)$id);
490
            $this->fromArray($this->modx->db->getRow($result));
491
            $result = $this->query("SELECT * from {$this->makeTable('site_tmplvar_contentvalues')} where `contentid`=" . (int)$id);
492
            while ($row = $this->modx->db->getRow($result)) {
493
                $this->field[$this->tvid[$row['tmplvarid']]] = $row['value'];
494
            }
495
            if (empty($this->field['id'])) {
496
                $this->id = null;
497
            } else {
498
                $this->id = $this->field['id'];
499
                $this->set('editedby', null)->touch();
500
                $this->decodeFields();
501
            }
502
            $this->store($this->toArray(null, null, null, false));
503
            unset($this->field['id']);
504
        }
505
506
        return $this;
507
    }
508
509
    /**
510
     * @param bool $fire_events
511
     * @param bool $clearCache
512
     * @return bool|null|void
513
     */
514
    public function save($fire_events = false, $clearCache = false)
515
    {
516
        $parent = null;
517
        if ($this->field['pagetitle'] == '') {
518
            $this->log['emptyPagetitle'] = 'Pagetitle is empty in <pre>' . print_r($this->field, true) . '</pre>';
519
520
            return false;
521
        }
522
523
        $uid = $this->modx->getLoginUserID('mgr');
524
525
        if (
526
            $this->field['parent'] == 0 &&
527
            !$this->modxConfig('udperms_allowroot') &&
528
            !($uid && isset($_SESSION['mgrRole']) && $_SESSION['mgrRole'] == 1)
529
        ) {
530
            $this->log['rootForbidden'] = 'Only Administrators can create documents in the root folder because udperms_allowroot setting is off';
531
532
            return false;
533
        }
534
535
        $this->set('alias', $this->getAlias());
536
537
        $this->invokeEvent('OnBeforeDocFormSave', array(
538
            'mode'   => $this->newDoc ? "new" : "upd",
539
            'id'     => $this->id ? $this->id : '',
540
            'doc'    => $this->toArray(),
541
            'docObj' => $this
542
        ), $fire_events);
543
544
        $fld = $this->encodeFields()->toArray(null, null, null, false);
545
        foreach ($this->default_field as $key => $value) {
546
            $tmp = $this->get($key);
547
            if ($this->newDoc && (!is_int($tmp) && $tmp == '')) {
548
                if ($tmp == $value) {
549
                    switch ($key) {
550
                        case 'cacheable':
551
                            $value = $this->modxConfig('cache_default');
552
                            break;
553
                        case 'template':
554
                            $value = $value = $this->modxConfig('default_template');
555
                            break;
556
                        case 'published':
557
                            $value = $this->modxConfig('publish_default');
558
                            break;
559
                        case 'searchable':
560
                            $value = $this->modxConfig('search_default');
561
                            break;
562
                        case 'donthit':
563
                            $value = $this->modxConfig('track_visitors');
564
                            break;
565
                    }
566
                }
567
                $this->field[$key] = $value;
568
            }
569
            switch (true) {
570
                case $key == 'parent':
571
                    $parent = (int)$this->get($key);
572
                    $q = $this->query("SELECT count(`id`) FROM {$this->makeTable('site_content')} WHERE `id`='{$parent}'");
573
                    if ($this->modx->db->getValue($q) != 1) {
574
                        $parent = 0;
575
                    }
576
                    $this->field[$key] = $parent;
577
                    $this->Uset($key);
578
                    break;
579
                case ($key == 'alias_visible' && !$this->checkVersion('1.0.10', true)):
580
                    $this->eraseField('alias_visible');
581
                    break;
582
                default:
583
                    $this->Uset($key);
584
            }
585
            unset($fld[$key]);
586
        }
587
588
        if (!empty($this->set)) {
589
            if ($this->newDoc) {
590
                $SQL = "INSERT into {$this->makeTable('site_content')} SET " . implode(', ', $this->set);
591
            } else {
592
                $SQL = "UPDATE {$this->makeTable('site_content')} SET " . implode(', ',
593
                        $this->set) . " WHERE `id` = " . $this->id;
594
            }
595
            $this->query($SQL);
596
597
            if ($this->newDoc) {
598
                $this->id = $this->modx->db->getInsertId();
599
            }
600
601
            if ($parent > 0) {
602
                $this->query("UPDATE {$this->makeTable('site_content')} SET `isfolder`='1' WHERE `id`='{$parent}'");
603
            }
604
        }
605
606
        $_deleteTVs = $_updateTVs = $_insertTVs = array();
607
        foreach ($fld as $key => $value) {
608
            if (empty($this->tv[$key]) || !$this->isChanged($key)) {
609
                continue;
610
            } elseif ($value === '') {
611
                $_deleteTVs[] = $this->tv[$key];
612
            } else {
613
                $_insertTVs[$this->tv[$key]] = $this->escape($value);
614
            }
615
        }
616
617
        if (!$this->newDoc && !empty($_insertTVs)) {
618
            $ids = implode(',', array_keys($_insertTVs));
619
            $result = $this->query("SELECT `tmplvarid` FROM {$this->makeTable('site_tmplvar_contentvalues')} WHERE `contentid`={$this->id} AND `tmplvarid` IN ({$ids})");
620
            $existedTVs = $this->modx->db->getColumn('tmplvarid', $result);
621
            foreach ($existedTVs as $id) {
622
                $_updateTVs[$id] = $_insertTVs[$id];
623
                unset($_insertTVs[$id]);
624
            }
625
        }
626
627
        if (!empty($_updateTVs)) {
628
            foreach ($_updateTVs as $id => $value) {
629
                $this->query("UPDATE {$this->makeTable('site_tmplvar_contentvalues')} SET `value` = '{$value}' WHERE `contentid` = {$this->id} AND `tmplvarid` = {$id}");
630
            }
631
        }
632
633
        if (!empty($_insertTVs)) {
634
            $values = array();
635
            foreach ($_insertTVs as $id => $value) {
636
                $values[] = "({$this->id}, {$id}, '{$value}')";
637
            }
638
            $values = implode(',', $values);
639
            $this->query("INSERT into {$this->makeTable('site_tmplvar_contentvalues')} (`contentid`,`tmplvarid`,`value`) VALUES {$values}");
640
        }
641
642
        if (!empty($_deleteTVs)) {
643
            $ids = implode(',', $_deleteTVs);
644
            $this->query("DELETE FROM {$this->makeTable('site_tmplvar_contentvalues')} WHERE `contentid` = '{$this->id}' AND `tmplvarid` IN ({$ids})");
645
        }
646
647
        if (!isset($this->mode)) {
648
            $this->mode = $this->newDoc ? "new" : "upd";
649
            $this->newDoc = false;
650
        }
651
        $this->invokeEvent('OnDocFormSave', array(
652
            'mode'   => $this->mode,
653
            'id'     => $this->id,
654
            'doc'    => $this->toArray(),
655
            'docObj' => $this
656
        ), $fire_events);
657
658
        if ($clearCache) {
659
            $this->clearCache($fire_events);
660
        }
661
        $this->decodeFields();
662
663
        return $this->id;
664
    }
665
666
    /**
667
     * @param $ids
668
     * @return $this
669
     * @throws Exception
670
     */
671
    public function toTrash($ids)
672
    {
673
        $ignore = $this->systemID();
674
        $_ids = $this->cleanIDs($ids, ',', $ignore);
675
        if (is_array($_ids) && $_ids != array()) {
676
            $id = $this->sanitarIn($_ids);
677
            $uid = (int)$this->modx->getLoginUserId();
678
            $deletedon = time() + $this->modxConfig('server_offset_time');
679
            $this->query("UPDATE {$this->makeTable('site_content')} SET `deleted`=1, `deletedby`={$uid}, `deletedon`={$deletedon} WHERE `id` IN ({$id})");
680
        } else {
681
            throw new Exception('Invalid IDs list for mark trash: <pre>' . print_r($ids,
682
                    1) . '</pre> please, check ignore list: <pre>' . print_r($ignore, 1) . '</pre>');
683
        }
684
685
        return $this;
686
    }
687
688
    /**
689
     * @param bool $fire_events
690
     * @return $this
691
     */
692
    public function clearTrash($fire_events = false)
693
    {
694
        $q = $this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `deleted`='1'");
695
        $_ids = $this->modx->db->getColumn('id', $q);
696
        if (is_array($_ids) && $_ids != array()) {
697
            $this->invokeEvent('OnBeforeEmptyTrash', array(
698
                "ids" => $_ids
699
            ), $fire_events);
700
701
            $id = $this->sanitarIn($_ids);
702
            $this->query("DELETE from {$this->makeTable('site_content')} where `id` IN ({$id})");
703
            $this->query("DELETE from {$this->makeTable('site_tmplvar_contentvalues')} where `contentid` IN ({$id})");
704
705
            $this->invokeEvent('OnEmptyTrash', array(
706
                "ids" => $_ids
707
            ), $fire_events);
708
        }
709
710
        return $this;
711
    }
712
713
    /**
714
     * @param $ids
715
     * @param int|bool $depth
716
     * @return array
717
     */
718
    public function children($ids, $depth)
719
    {
720
        $_ids = $this->cleanIDs($ids, ',');
721
        if (is_array($_ids) && $_ids != array()) {
722
            $id = $this->sanitarIn($_ids);
723
            if (!empty($id)) {
724
                $q = $this->query("SELECT `id` FROM {$this->makeTable('site_content')} where `parent` IN ({$id})");
725
                $id = $this->modx->db->getColumn('id', $q);
726
                if ($depth > 0 || $depth === true) {
727
                    $id = $this->children($id, is_bool($depth) ? $depth : ($depth - 1));
728
                }
729
                $_ids = array_merge($_ids, $id);
730
            }
731
        }
732
733
        return $_ids;
734
    }
735
736
    /**
737
     * @param string|array $ids
738
     * @param bool $fire_events
739
     * @return $this
740
     * @throws Exception
741
     */
742
    public function delete($ids, $fire_events = false)
743
    {
744
        $ids = $this->children($ids, true);
745
        $_ids = $this->cleanIDs($ids, ',', $this->systemID());
746
        $this->invokeEvent('OnBeforeDocFormDelete', array(
747
            'ids' => $_ids
748
        ), $fire_events);
749
        $this->toTrash($_ids);
750
        $this->invokeEvent('OnDocFormDelete', array(
751
            'ids' => $_ids
752
        ), $fire_events);
753
754
        return $this;
755
    }
756
757
    /**
758
     * @return array
759
     */
760
    private function systemID()
761
    {
762
        $ignore = array(
763
            0, //empty document
764
            (int)$this->modxConfig('site_start'),
765
            (int)$this->modxConfig('error_page'),
766
            (int)$this->modxConfig('unauthorized_page'),
767
            (int)$this->modxConfig('site_unavailable_page')
768
        );
769
        $data = $this->query("SELECT DISTINCT setting_value FROM {$this->makeTable('web_user_settings')} WHERE `setting_name`='login_home' AND `setting_value`!=''");
770
        $data = $this->modx->db->makeArray($data);
771
        foreach ($data as $item) {
772
            $ignore[] = (int)$item['setting_value'];
773
        }
774
775
        return array_unique($ignore);
776
777
    }
778
779
    /**
780
     * @param $alias
781
     * @return string
782
     */
783
    protected function checkAlias($alias)
784
    {
785
        $alias = strtolower($alias);
786
        if ($this->modxConfig('friendly_urls')) {
787
            $_alias = $this->escape($alias);
788
            if ((!$this->modxConfig('allow_duplicate_alias') && !$this->modxConfig('use_alias_path')) || ($this->modxConfig('allow_duplicate_alias') && $this->modxConfig('use_alias_path'))) {
789
                $flag = $this->modx->db->getValue($this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `alias`='{$_alias}' AND `parent`={$this->get('parent')} LIMIT 1"));
790
            } else {
791
                $flag = $this->modx->db->getValue($this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `alias`='{$_alias}' LIMIT 1"));
792
            }
793
            if (($flag && $this->newDoc) || (!$this->newDoc && $flag && $this->id != $flag)) {
794
                $suffix = substr($alias, -2);
795
                if (preg_match('/-(\d+)/', $suffix, $tmp) && isset($tmp[1]) && (int)$tmp[1] > 1) {
796
                    $suffix = (int)$tmp[1] + 1;
797
                    $alias = substr($alias, 0, -2) . '-' . $suffix;
798
                } else {
799
                    $alias .= '-2';
800
                }
801
                $alias = $this->checkAlias($alias);
802
            }
803
        }
804
805
        return $alias;
806
    }
807
808
    /**
809
     * @param $key
810
     * @return bool
811
     */
812
    public function issetField($key)
813
    {
814
        return (array_key_exists($key, $this->default_field) || array_key_exists($key, $this->tv));
815
    }
816
817
    /**
818
     * @param bool $reload
819
     * @return $this
820
     */
821
    protected function get_TV($reload = false)
822
    {
823
        if (empty($this->modx->_TVnames) || $reload) {
824
            $result = $this->query('SELECT `id`,`name`,`type` FROM ' . $this->makeTable('site_tmplvars'));
825
            while ($row = $this->modx->db->GetRow($result)) {
826
                $this->modx->_TVnames[$row['name']] = array(
827
                    "id"   => $row['id'],
828
                    "type" => $row['type']
829
                );
830
            }
831
        }
832
        $arrayTypes = array('checkbox', 'listbox-multiple');
833
        $arrayTVs = array();
834
        foreach ($this->modx->_TVnames as $name => $data) {
835
            $this->tvid[$data['id']] = $name;
836
            $this->tv[$name] = $data['id'];
837
            if (in_array($data['type'], $arrayTypes)) {
838
                $arrayTVs[] = $name;
839
            }
840
        }
841
        if (empty($this->tvaFields)) $this->tvaFields = $arrayTVs;
842
        $this->loadTVTemplate()->loadTVDefault(array_values($this->tv));
843
844
        return $this;
845
    }
846
847
    /**
848
     * @return $this
849
     */
850
    protected function loadTVTemplate()
851
    {
852
        $q = $this->query("SELECT `tmplvarid`, `templateid` FROM " . $this->makeTable('site_tmplvar_templates'));
853
        $q = $this->modx->db->makeArray($q);
854
        $this->tvTpl = array();
855
        foreach ($q as $item) {
856
            $this->tvTpl[$item['templateid']][] = $item['tmplvarid'];
857
        }
858
859
        return $this;
860
    }
861
862
    /**
863
     * @param array $tvId
864
     * @return $this
865
     */
866
    protected function loadTVDefault(array $tvId = array())
867
    {
868
        if (is_array($tvId) && !empty($tvId)) {
869
            $tbl_site_tmplvars = $this->makeTable('site_tmplvars');
870
            $fields = 'id,name,default_text as value,display,display_params,type';
871
            $implodeTvId = implode(',', $tvId);
872
            $rs = $this->query("SELECT {$fields} FROM {$tbl_site_tmplvars} WHERE id IN({$implodeTvId})");
873
            $rows = $this->modx->db->makeArray($rs);
874
            $this->tvd = array();
875
            foreach ($rows as $item) {
876
                $this->tvd[$item['name']] = $item;
877
            }
878
        }
879
880
        return $this;
881
    }
882
883
    /**
884
     * @param $tpl
885
     * @return int
886
     * @throws Exception
887
     */
888
    public function setTemplate($tpl)
889
    {
890
        if (!is_numeric($tpl) || $tpl != (int)$tpl) {
891
            if (is_scalar($tpl)) {
892
                $sql = "SELECT `id` FROM {$this->makeTable('site_templates')} WHERE `templatename` = '" . $this->escape($tpl) . "'";
893
                $rs = $this->query($sql);
894
                if (!$rs || $this->modx->db->getRecordCount($rs) <= 0) {
895
                    throw new Exception("Template {$tpl} is not exists");
896
                }
897
                $tpl = $this->modx->db->getValue($rs);
898
            } else {
899
                throw new Exception("Invalid template name: " . print_r($tpl, 1));
900
            }
901
        }
902
903
        return (int)$tpl;
904
    }
905
906
    /**
907
     * @return string
908
     */
909
    protected function getAlias()
910
    {
911
        if ($this->modxConfig('friendly_urls') && $this->modxConfig('automatic_alias') && $this->get('alias') == '') {
912
            $alias = strtr($this->get('pagetitle'), $this->table);
913
        } else {
914
            if ($this->get('alias') != '') {
915
                $alias = $this->get('alias');
916
            } else {
917
                $alias = '';
918
            }
919
        }
920
        $alias = $this->modx->stripAlias($alias);
921
922
        return $this->checkAlias($alias);
923
    }
924
925
    /**
926
     * @param int $parent
927
     * @param string $criteria
928
     * @param string $dir
929
     * @return $this
930
     *
931
     * Пересчет menuindex по полю таблицы site_content
932
     */
933
    public function updateMenuindex($parent, $criteria = 'id', $dir = 'asc')
934
    {
935
        $dir = strtolower($dir) == 'desc' ? 'desc' : 'asc';
936
        if (is_integer($parent) && $criteria !== '') {
937
            $this->query("SET @index := 0");
938
            $this->query("UPDATE {$this->makeTable('site_content')} SET `menuindex` = (@index := @index + 1) WHERE `parent`={$parent} ORDER BY {$criteria} {$dir}");
939
        }
940
941
        return $this;
942
    }
943
944
    /**
945
     * Устанавливает значение шаблона согласно системной настройке
946
     *
947
     * @return $this
948
     */
949
    public function setDefaultTemplate()
950
    {
951
        $parent = $this->get('parent');
952
        $template = $this->modxConfig('default_template');
953
        switch ($this->modxConfig('auto_template_logic')) {
954
            case 'sibling':
955
                if (!$parent) {
956
                    $site_start = $this->modxConfig('site_start');
957
                    $where = "sc.isfolder=0 AND sc.id!={$site_start}";
958
                    $sibl = $this->modx->getDocumentChildren($parent, 1, 0, 'template', $where, 'menuindex', 'ASC', 1);
959
                    if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') {
960
                        $template = $sibl[0]['template'];
961
                    }
962
                } else {
963
                    $sibl = $this->modx->getDocumentChildren($parent, 1, 0, 'template', 'isfolder=0', 'menuindex',
964
                        'ASC', 1);
965
                    if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') {
966
                        $template = $sibl[0]['template'];
967
                    } else {
968
                        $sibl = $this->modx->getDocumentChildren($parent, 0, 0, 'template', 'isfolder=0', 'menuindex',
969
                            'ASC', 1);
970
                        if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') {
971
                            $template = $sibl[0]['template'];
972
                        }
973
                    }
974
                }
975
                break;
976
            case 'parent':
977
                if ($parent) {
978
                    $_parent = $this->modx->getPageInfo($parent, 0, 'template');
979
                    if (isset($_parent['template'])) {
980
                        $template = $_parent['template'];
981
                    }
982
                }
983
                break;
984
        }
985
        $this->set('template', $template);
986
987
        return $this;
988
    }
989
990
    /**
991
     * Декодирует конкретное поле
992
     * @param  string $field Имя поля
993
     * @param  bool $store обновить распакованное поле
994
     * @return array ассоциативный массив с данными из json строки
995
     */
996
    public function decodeField($field, $store = false)
997
    {
998
        $out = array();
999
        if ($this->isDecodableField($field)) {
1000
            $data = $this->get($field);
1001
            if ($this->isTVarrayField($field)) {
1002
                $out = explode('||', $data);
1003
            } else {
1004
                $out = jsonHelper::jsonDecode($data, array('assoc' => true), true);
1005
            }
1006
        }
1007
        if ($store) {
1008
            $this->field[$field] = $out;
1009
            $this->markAsDecode($field);
1010
        }
1011
1012
        return $out;
1013
    }
1014
1015
    /**
1016
     * Запаковывает конкретное поле в JSON
1017
     * @param  string $field Имя поля
1018
     * @param  bool $store обновить запакованное поле
1019
     * @return string|null json строка
1020
     */
1021
    public function encodeField($field, $store = false)
1022
    {
1023
        $out = null;
1024
        if ($this->isEncodableField($field)) {
1025
            $data = $this->get($field);
1026
            if ($this->isTVarrayField($field)) {
1027
                $out = is_array($data) ? implode('||', $data) : $data;
1028
            } else {
1029
                $out = json_encode($data);
1030
            }
1031
        }
1032
        if ($store) {
1033
            $this->field[$field] = $out;
1034
            $this->markAsEncode($field);
1035
        }
1036
1037
        return $out;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $out; (object|integer|double|string|null|boolean) is incompatible with the return type of the parent method MODxAPI::encodeField of type string|null.

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...
1038
    }
1039
1040
    /**
1041
     * Может ли содержать данное поле json массив
1042
     * @param  string $field имя поля
1043
     * @return boolean
1044
     */
1045
    public function isTVarrayField($field)
1046
    {
1047
        return (is_scalar($field) && in_array($field, $this->tvaFields));
1048
    }
1049
1050
    /**
1051
     * Пометить все поля как запакованные
1052
     * @return $this
1053
     */
1054
    public function markAllEncode()
1055
    {
1056
        parent::markAllEncode();
1057
        foreach ($this->tvaFields as $field) {
1058
            $this->markAsEncode($field);
1059
        }
1060
1061
        return $this;
1062
    }
1063
1064
    /**
1065
     * Пометить все поля как распакованные
1066
     * @return $this
1067
     */
1068
    public function markAllDecode()
1069
    {
1070
        parent::markAllDecode();
1071
        foreach ($this->tvaFields as $field) {
1072
            $this->markAsDecode($field);
1073
        }
1074
1075
        return $this;
1076
    }
1077
}
1078