Completed
Push — master ( 297a7b...8e3f41 )
by
unknown
02:03
created

modResource::setDocumentGroups()   C

Complexity

Conditions 8
Paths 6

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 15
nc 6
nop 2
dl 0
loc 22
rs 6.6037
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
    /** @var array группы документов */
156
    protected $groupIds = array();
157
    /**
158
     * modResource constructor.
159
     * @param DocumentParser $modx
160
     * @param bool $debug
161
     */
162
    public function __construct($modx, $debug = false)
163
    {
164
        parent::__construct($modx, $debug);
165
        $this->get_TV();
166
        $uTable = $this->makeTable("manager_users");
167
        $aTable = $this->makeTable("user_attributes");
168
        $query = "SELECT `u`.`id`, `a`.`email`, `u`.`username`  FROM " . $aTable . " as `a` LEFT JOIN " . $uTable . " as `u` ON `u`.`id`=`a`.`internalKey`";
169
        $query = $this->query($query);
170
        $this->managerUsers = new DLCollection($modx, empty($query) ? array() : $query);
171
    }
172
173
    /**
174
     * @return array
175
     */
176
    public function toArrayMain()
177
    {
178
        $out = array_intersect_key(parent::toArray(), $this->default_field);
179
180
        return $out;
181
    }
182
183
    /**
184
     * @param bool $render
185
     * @return array
186
     */
187
    public function toArrayTV($render = false)
188
    {
189
        $out = array_diff_key(parent::toArray(), $this->default_field);
190
        $tpl = $this->get('template');
191
        $tvTPL = APIHelpers::getkey($this->tvTpl, $tpl, array());
192
        foreach ($tvTPL as $item) {
193
            if (isset($this->tvid[$item]) && !array_key_exists($this->tvid[$item], $out)) {
194
                $out[$this->tvid[$item]] = $this->get($this->tvid[$item]);
195
            }
196
        }
197
        if ($render) {
198
            foreach ($out as $key => $val) {
199
                $out[$key] = $this->renderTV($key);
200
            }
201
        }
202
203
        return $out;
204
    }
205
206
    /**
207
     * @param string $prefix
208
     * @param string $suffix
209
     * @param string $sep
210
     * @param bool $render
211
     * @return array
212
     */
213
    public function toArray($prefix = '', $suffix = '', $sep = '_', $render = true)
214
    {
215
        $out = array_merge(
216
            $this->toArrayMain(),
217
            $this->toArrayTV($render),
218
            array($this->fieldPKName() => $this->getID())
219
        );
220
221
        return \APIhelpers::renameKeyArr($out, $prefix, $suffix, $sep);
222
    }
223
224
    /**
225
     * @return null|string
226
     */
227
    public function getUrl()
228
    {
229
        $out = null;
230
        $id = (int)$this->getID();
231
        if (!empty($id)) {
232
            $out = $this->modx->makeUrl($id);
233
        }
234
235
        return $out;
236
    }
237
238
    /**
239
     * @param string $main
240
     * @param string $second
241
     * @return mixed
242
     */
243
    public function getTitle($main = 'menutitle', $second = 'pagetitle')
244
    {
245
        $title = $this->get($main);
246
        if (empty($title) && $title !== '0') {
247
            $title = $this->get($second);
248
        }
249
250
        return $title;
251
    }
252
253
    /**
254
     * @return bool
255
     */
256
    public function isWebShow()
257
    {
258
        $pub = ($this->get('publishedon') < time() && $this->get('published'));
259
        $unpub = ($this->get('unpub_date') == 0 || $this->get('unpub_date') > time());
260
        $del = ($this->get('deleted') == 0 && ($this->get('deletedon') == 0 || $this->get('deletedon') > time()));
261
262
        return ($pub && $unpub && $del);
263
    }
264
265
    /**
266
     * @return $this
267
     */
268
    public function touch()
269
    {
270
        $this->set('editedon', time());
271
272
        return $this;
273
    }
274
275
    /**
276
     * @param $tvname
277
     * @return null|string
278
     */
279
    public function renderTV($tvname)
280
    {
281
        $out = null;
282
        if ($this->getID() > 0) {
283
            include_once MODX_MANAGER_PATH . "includes/tmplvars.format.inc.php";
284
            include_once MODX_MANAGER_PATH . "includes/tmplvars.commands.inc.php";
285
            $tvval = $this->get($tvname);
286
            if ($this->isTVarrayField($tvname) && is_array($tvval)) {
287
                $tvval = implode('||', $tvval);
288
            }
289
            $param = APIHelpers::getkey($this->tvd, $tvname, array());
290
            $display = APIHelpers::getkey($param, 'display', '');
291
            $display_params = APIHelpers::getkey($param, 'display_params', '');
292
            $type = APIHelpers::getkey($param, 'type', '');
293
            $out = getTVDisplayFormat($tvname, $tvval, $display, $display_params, $type, $this->getID(), '');
294
        }
295
296
        return $out;
297
    }
298
299
    /**
300
     * @param $key
301
     * @return mixed
302
     */
303
    public function get($key)
304
    {
305
        $out = parent::get($key);
306
        if (isset($this->tv[$key])) {
307
            $tpl = $this->get('template');
308
            $tvTPL = APIHelpers::getkey($this->tvTpl, $tpl, array());
309
            $tvID = APIHelpers::getkey($this->tv, $key, 0);
310
            if (in_array($tvID, $tvTPL) && is_null($out)) {
311
                $out = APIHelpers::getkey($this->tvd[$key], 'value', null);
312
            }
313
        }
314
315
        return $out;
316
    }
317
318
    /**
319
     * @param $key
320
     * @param $value
321
     * @return $this
322
     */
323
    public function set($key, $value)
324
    {
325
        if ((is_scalar($value) || $this->isTVarrayField($key) || $this->isJsonField($key)) && is_scalar($key) && !empty($key)) {
326
            switch ($key) {
327
                case 'parent':
328
                    $value = (int)$value;
329
                    break;
330
                case 'template':
331
                    $value = trim($value);
332
                    $value = $this->setTemplate($value);
333
                    break;
334
                case 'published':
335
                    $value = (int)((bool)$value);
336
                    if ($value) {
337
                        $this->field['publishedon'] = time() + $this->modxConfig('server_offset_time');
338
                    }
339
                    break;
340
                case 'pub_date':
341
                    $value = $this->getTime($value);
342
                    if ($value > 0 && time() + $this->modxConfig('server_offset_time') > $value) {
343
                        $this->field['published'] = 1;
344
                        $this->field['publishedon'] = $value;
345
                    }
346
                    break;
347
                case 'unpub_date':
348
                    $value = $this->getTime($value);
349
                    if ($value > 0 && time() + $this->modxConfig('server_offset_time') > $value) {
350
                        $this->field['published'] = 0;
351
                        $this->field['publishedon'] = 0;
352
                    }
353
                    break;
354
                case 'deleted':
355
                    $value = (int)((bool)$value);
356
                    if ($value) {
357
                        $this->field['deletedon'] = time() + $this->modxConfig('server_offset_time');
358
                    } else {
359
                        $this->field['deletedon'] = 0;
360
                    }
361
                    break;
362
                case 'deletedon':
363
                    $value = $this->getTime($value);
364
                    if ($value > 0 && time() + $this->modxConfig('server_offset_time') < $value) {
365
                        $value = 0;
366
                    }
367
                    if ($value) {
368
                        $this->field['deleted'] = 1;
369
                    }
370
                    break;
371
                case 'editedon':
372
                case 'createdon':
373
                case 'publishedon':
374
                    $value = $this->getTime($value);
375
                    break;
376
                case 'publishedby':
377
                case 'editedby':
378
                case 'createdby':
379
                case 'deletedby':
380
                    $value = $this->getUser($value, $this->default_field[$key]);
381
                    break;
382
            }
383
            $this->field[$key] = $value;
384
        }
385
386
        return $this;
387
    }
388
389
    /**
390
     * @param $value
391
     * @param int $default
392
     * @return int|mixed
393
     */
394
    protected function getUser($value, $default = 0)
395
    {
396
        $currentAdmin = APIHelpers::getkey($_SESSION, 'mgrInternalKey', 0);
397
        $value = (int)$value;
398
        if (!empty($value)) {
399
            $by = $this->findUserBy($value);
400
            $exists = $this->managerUsers->exists(function ($key, Helpers\Collection $val) use ($by, $value) {
401
                return ($val->containsKey($by) && $val->get($by) === (string)$value);
402
            });
403
            if (!$exists) {
404
                $value = 0;
405
            }
406
        }
407
        if (empty($value)) {
408
            $value = empty($currentAdmin) ? $default : $currentAdmin;
409
        }
410
411
        return $value;
412
    }
413
414
    /**
415
     * @param $data
416
     * @return bool|string
417
     */
418
    protected function findUserBy($data)
419
    {
420
        switch (true) {
421
            case (is_int($data) || ((int)$data > 0 && (string)intval($data) === $data)):
422
                $find = 'id';
423
                break;
424
            case filter_var($data, FILTER_VALIDATE_EMAIL):
425
                $find = 'email';
426
                break;
427
            case is_scalar($data):
428
                $find = 'username';
429
                break;
430
            default:
431
                $find = false;
432
        }
433
434
        return $find;
435
    }
436
437
    /**
438
     * @param $value
439
     * @return int|mixed|string
440
     */
441
    protected function getTime($value)
442
    {
443
        $value = trim($value);
444
        if (!empty($value)) {
445
            if (!is_numeric($value)) {
446
                $value = (int)strtotime($value);
447
            }
448
            if (!empty($value)) {
449
                $value += $this->modxConfig('server_offset_time');
450
            }
451
        }
452
453
        return $value;
454
    }
455
456
    /**
457
     * @param array $data
458
     * @return $this
459
     */
460
    public function create($data = array())
461
    {
462
        $this->close();
463
        $fld = array();
464
        foreach ($this->tvd as $name => $tv) {
465
            $fld[$name] = $tv['value'];
466
        };
467
        $this->store($fld);
468
469
        $this->fromArray(array_merge($fld, $data));
470
        $this->set('createdby', null)
471
            ->set('editedby', null)
472
            ->set('createdon', time())
473
            ->touch();
474
475
        return $this;
476
    }
477
478
    /**
479
     * @param $id
480
     * @return $this
481
     */
482
    public function edit($id)
483
    {
484
        $id = is_scalar($id) ? trim($id) : '';
485
        if ($this->getID() != $id) {
486
            $this->close();
487
            $this->markAllEncode();
488
            $this->newDoc = false;
489
490
            $result = $this->query("SELECT * from {$this->makeTable('site_content')} where `id`=" . (int)$id);
491
            $this->fromArray($this->modx->db->getRow($result));
492
            $result = $this->query("SELECT * from {$this->makeTable('site_tmplvar_contentvalues')} where `contentid`=" . (int)$id);
493
            while ($row = $this->modx->db->getRow($result)) {
494
                $this->field[$this->tvid[$row['tmplvarid']]] = $row['value'];
495
            }
496
            if (empty($this->field['id'])) {
497
                $this->id = null;
498
            } else {
499
                $this->id = $this->field['id'];
500
                $this->set('editedby', null)->touch();
501
                $this->decodeFields();
502
            }
503
            $this->store($this->toArray(null, null, null, false));
504
            unset($this->field['id']);
505
        }
506
507
        return $this;
508
    }
509
510
    /**
511
     * @param bool $fire_events
512
     * @param bool $clearCache
513
     * @return bool|null
514
     */
515
    public function save($fire_events = false, $clearCache = false)
516
    {
517
        $parent = null;
518
        if ($this->field['pagetitle'] == '') {
519
            $this->log['emptyPagetitle'] = 'Pagetitle is empty in <pre>' . print_r($this->field, true) . '</pre>';
520
521
            return false;
522
        }
523
524
        $uid = $this->modx->getLoginUserID('mgr');
525
526
        if (
527
            $this->field['parent'] == 0 &&
528
            !$this->modxConfig('udperms_allowroot') &&
529
            !($uid && isset($_SESSION['mgrRole']) && $_SESSION['mgrRole'] == 1)
530
        ) {
531
            $this->log['rootForbidden'] = 'Only Administrators can create documents in the root folder because udperms_allowroot setting is off';
532
533
            return false;
534
        }
535
536
        $this->set('alias', $this->getAlias());
537
538
        $this->invokeEvent('OnBeforeDocFormSave', array(
539
            'mode'   => $this->newDoc ? "new" : "upd",
540
            'id'     => $this->id ? $this->id : '',
541
            'doc'    => $this->toArray(),
542
            'docObj' => $this
543
        ), $fire_events);
544
545
        $fld = $this->encodeFields()->toArray(null, null, null, false);
546
        foreach ($this->default_field as $key => $value) {
547
            $tmp = $this->get($key);
548
            if ($this->newDoc && (!is_int($tmp) && $tmp == '')) {
549
                if ($tmp == $value) {
550
                    switch ($key) {
551
                        case 'cacheable':
552
                            $value = $this->modxConfig('cache_default');
553
                            break;
554
                        case 'template':
555
                            $value = $value = $this->modxConfig('default_template');
556
                            break;
557
                        case 'published':
558
                            $value = $this->modxConfig('publish_default');
559
                            break;
560
                        case 'searchable':
561
                            $value = $this->modxConfig('search_default');
562
                            break;
563
                        case 'donthit':
564
                            $value = $this->modxConfig('track_visitors');
565
                            break;
566
                    }
567
                }
568
                $this->field[$key] = $value;
569
            }
570
            switch (true) {
571
                case $key == 'parent':
572
                    $parent = (int)$this->get($key);
573
                    $q = $this->query("SELECT count(`id`) FROM {$this->makeTable('site_content')} WHERE `id`='{$parent}'");
574
                    if ($this->modx->db->getValue($q) != 1) {
575
                        $parent = 0;
576
                    }
577
                    $this->field[$key] = $parent;
578
                    $this->Uset($key);
579
                    break;
580
                case ($key == 'alias_visible' && !$this->checkVersion('1.0.10', true)):
581
                    $this->eraseField('alias_visible');
582
                    break;
583
                default:
584
                    $this->Uset($key);
585
            }
586
            unset($fld[$key]);
587
        }
588
589
        if (!empty($this->set)) {
590
            if ($this->newDoc) {
591
                $SQL = "INSERT into {$this->makeTable('site_content')} SET " . implode(', ', $this->set);
592
            } else {
593
                $SQL = "UPDATE {$this->makeTable('site_content')} SET " . implode(', ',
594
                        $this->set) . " WHERE `id` = " . $this->id;
595
            }
596
            $this->query($SQL);
597
598
            if ($this->newDoc) {
599
                $this->id = $this->modx->db->getInsertId();
600
            }
601
602
            if ($parent > 0) {
603
                $this->query("UPDATE {$this->makeTable('site_content')} SET `isfolder`='1' WHERE `id`='{$parent}'");
604
            }
605
        }
606
607
        $_deleteTVs = $_updateTVs = $_insertTVs = array();
608
        foreach ($fld as $key => $value) {
609
            if (empty($this->tv[$key]) || !$this->isChanged($key)) {
610
                continue;
611
            } elseif ($value === '') {
612
                $_deleteTVs[] = $this->tv[$key];
613
            } else {
614
                $_insertTVs[$this->tv[$key]] = $this->escape($value);
615
            }
616
        }
617
618
        if (!$this->newDoc && !empty($_insertTVs)) {
619
            $ids = implode(',', array_keys($_insertTVs));
620
            $result = $this->query("SELECT `tmplvarid` FROM {$this->makeTable('site_tmplvar_contentvalues')} WHERE `contentid`={$this->id} AND `tmplvarid` IN ({$ids})");
621
            $existedTVs = $this->modx->db->getColumn('tmplvarid', $result);
622
            foreach ($existedTVs as $id) {
623
                $_updateTVs[$id] = $_insertTVs[$id];
624
                unset($_insertTVs[$id]);
625
            }
626
        }
627
628
        if (!empty($_updateTVs)) {
629
            foreach ($_updateTVs as $id => $value) {
630
                $this->query("UPDATE {$this->makeTable('site_tmplvar_contentvalues')} SET `value` = '{$value}' WHERE `contentid` = {$this->id} AND `tmplvarid` = {$id}");
631
            }
632
        }
633
634
        if (!empty($_insertTVs)) {
635
            $values = array();
636
            foreach ($_insertTVs as $id => $value) {
637
                $values[] = "({$this->id}, {$id}, '{$value}')";
638
            }
639
            $values = implode(',', $values);
640
            $this->query("INSERT into {$this->makeTable('site_tmplvar_contentvalues')} (`contentid`,`tmplvarid`,`value`) VALUES {$values}");
641
        }
642
643
        if (!empty($_deleteTVs)) {
644
            $ids = implode(',', $_deleteTVs);
645
            $this->query("DELETE FROM {$this->makeTable('site_tmplvar_contentvalues')} WHERE `contentid` = '{$this->id}' AND `tmplvarid` IN ({$ids})");
646
        }
647
648
        if (!isset($this->mode)) {
649
            $this->mode = $this->newDoc ? "new" : "upd";
650
            $this->newDoc = false;
651
        }
652
653
        if ($this->groupIds) $this->setDocumentGroups($this->id, $this->groupIds);
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->groupIds of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
654
        $this->invokeEvent('OnDocFormSave', array(
655
            'mode'   => $this->mode,
656
            'id'     => $this->id,
657
            'doc'    => $this->toArray(),
658
            'docObj' => $this
659
        ), $fire_events);
660
661
        if ($clearCache) {
662
            $this->clearCache($fire_events);
663
        }
664
        $this->decodeFields();
665
666
        return $this->id;
667
    }
668
669
    /**
670
     * @param $ids
671
     * @return $this
672
     * @throws Exception
673
     */
674
    public function toTrash($ids)
675
    {
676
        $ignore = $this->systemID();
677
        $_ids = $this->cleanIDs($ids, ',', $ignore);
678
        if (is_array($_ids) && $_ids != array()) {
679
            $id = $this->sanitarIn($_ids);
680
            $uid = (int)$this->modx->getLoginUserId();
681
            $deletedon = time() + $this->modxConfig('server_offset_time');
682
            $this->query("UPDATE {$this->makeTable('site_content')} SET `deleted`=1, `deletedby`={$uid}, `deletedon`={$deletedon} WHERE `id` IN ({$id})");
683
        } else {
684
            throw new Exception('Invalid IDs list for mark trash: <pre>' . print_r($ids,
685
                    1) . '</pre> please, check ignore list: <pre>' . print_r($ignore, 1) . '</pre>');
686
        }
687
688
        return $this;
689
    }
690
691
    /**
692
     * @param bool $fire_events
693
     * @return $this
694
     */
695
    public function clearTrash($fire_events = false)
696
    {
697
        $q = $this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `deleted`='1'");
698
        $_ids = $this->modx->db->getColumn('id', $q);
699
        if (is_array($_ids) && $_ids != array()) {
700
            $this->invokeEvent('OnBeforeEmptyTrash', array(
701
                "ids" => $_ids
702
            ), $fire_events);
703
704
            $id = $this->sanitarIn($_ids);
705
            $this->query("DELETE from {$this->makeTable('site_content')} where `id` IN ({$id})");
706
            $this->query("DELETE from {$this->makeTable('site_tmplvar_contentvalues')} where `contentid` IN ({$id})");
707
708
            $this->invokeEvent('OnEmptyTrash', array(
709
                "ids" => $_ids
710
            ), $fire_events);
711
        }
712
713
        return $this;
714
    }
715
716
    /**
717
     * @param $ids
718
     * @param int|bool $depth
719
     * @return array
720
     */
721
    public function children($ids, $depth)
722
    {
723
        $_ids = $this->cleanIDs($ids, ',');
724
        if (is_array($_ids) && $_ids != array()) {
725
            $id = $this->sanitarIn($_ids);
726
            if (!empty($id)) {
727
                $q = $this->query("SELECT `id` FROM {$this->makeTable('site_content')} where `parent` IN ({$id})");
728
                $id = $this->modx->db->getColumn('id', $q);
729
                if ($depth > 0 || $depth === true) {
730
                    $id = $this->children($id, is_bool($depth) ? $depth : ($depth - 1));
731
                }
732
                $_ids = array_merge($_ids, $id);
733
            }
734
        }
735
736
        return $_ids;
737
    }
738
739
    /**
740
     * @param string|array $ids
741
     * @param bool $fire_events
742
     * @return $this
743
     * @throws Exception
744
     */
745
    public function delete($ids, $fire_events = false)
746
    {
747
        $ids = $this->children($ids, true);
748
        $_ids = $this->cleanIDs($ids, ',', $this->systemID());
749
        $this->invokeEvent('OnBeforeDocFormDelete', array(
750
            'ids' => $_ids
751
        ), $fire_events);
752
        $this->toTrash($_ids);
753
        $this->invokeEvent('OnDocFormDelete', array(
754
            'ids' => $_ids
755
        ), $fire_events);
756
757
        return $this;
758
    }
759
760
    /**
761
     * @return array
762
     */
763
    private function systemID()
764
    {
765
        $ignore = array(
766
            0, //empty document
767
            (int)$this->modxConfig('site_start'),
768
            (int)$this->modxConfig('error_page'),
769
            (int)$this->modxConfig('unauthorized_page'),
770
            (int)$this->modxConfig('site_unavailable_page')
771
        );
772
        $data = $this->query("SELECT DISTINCT setting_value FROM {$this->makeTable('web_user_settings')} WHERE `setting_name`='login_home' AND `setting_value`!=''");
773
        $data = $this->modx->db->makeArray($data);
774
        foreach ($data as $item) {
775
            $ignore[] = (int)$item['setting_value'];
776
        }
777
778
        return array_unique($ignore);
779
780
    }
781
782
    /**
783
     * @param $alias
784
     * @return string
785
     */
786
    protected function checkAlias($alias)
787
    {
788
        $alias = strtolower($alias);
789
        if ($this->modxConfig('friendly_urls')) {
790
            $_alias = $this->escape($alias);
791
            if ((!$this->modxConfig('allow_duplicate_alias') && !$this->modxConfig('use_alias_path')) || ($this->modxConfig('allow_duplicate_alias') && $this->modxConfig('use_alias_path'))) {
792
                $flag = $this->modx->db->getValue($this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `alias`='{$_alias}' AND `parent`={$this->get('parent')} LIMIT 1"));
793
            } else {
794
                $flag = $this->modx->db->getValue($this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `alias`='{$_alias}' LIMIT 1"));
795
            }
796
            if (($flag && $this->newDoc) || (!$this->newDoc && $flag && $this->id != $flag)) {
797
                $suffix = substr($alias, -2);
798
                if (preg_match('/-(\d+)/', $suffix, $tmp) && isset($tmp[1]) && (int)$tmp[1] > 1) {
799
                    $suffix = (int)$tmp[1] + 1;
800
                    $alias = substr($alias, 0, -2) . '-' . $suffix;
801
                } else {
802
                    $alias .= '-2';
803
                }
804
                $alias = $this->checkAlias($alias);
805
            }
806
        }
807
808
        return $alias;
809
    }
810
811
    /**
812
     * @param $key
813
     * @return bool
814
     */
815
    public function issetField($key)
816
    {
817
        return (array_key_exists($key, $this->default_field) || array_key_exists($key, $this->tv));
818
    }
819
820
    /**
821
     * @param bool $reload
822
     * @return $this
823
     */
824
    protected function get_TV($reload = false)
825
    {
826
        if (empty($this->modx->_TVnames) || $reload) {
827
            $result = $this->query('SELECT `id`,`name`,`type` FROM ' . $this->makeTable('site_tmplvars'));
828
            while ($row = $this->modx->db->GetRow($result)) {
829
                $this->modx->_TVnames[$row['name']] = array(
830
                    "id"   => $row['id'],
831
                    "type" => $row['type']
832
                );
833
            }
834
        }
835
        $arrayTypes = array('checkbox', 'listbox-multiple');
836
        $arrayTVs = array();
837
        foreach ($this->modx->_TVnames as $name => $data) {
838
            $this->tvid[$data['id']] = $name;
839
            $this->tv[$name] = $data['id'];
840
            if (in_array($data['type'], $arrayTypes)) {
841
                $arrayTVs[] = $name;
842
            }
843
        }
844
        if (empty($this->tvaFields)) $this->tvaFields = $arrayTVs;
845
        $this->loadTVTemplate()->loadTVDefault(array_values($this->tv));
846
847
        return $this;
848
    }
849
850
    /**
851
     * @return $this
852
     */
853
    protected function loadTVTemplate()
854
    {
855
        $q = $this->query("SELECT `tmplvarid`, `templateid` FROM " . $this->makeTable('site_tmplvar_templates'));
856
        $q = $this->modx->db->makeArray($q);
857
        $this->tvTpl = array();
858
        foreach ($q as $item) {
859
            $this->tvTpl[$item['templateid']][] = $item['tmplvarid'];
860
        }
861
862
        return $this;
863
    }
864
865
    /**
866
     * @param array $tvId
867
     * @return $this
868
     */
869
    protected function loadTVDefault(array $tvId = array())
870
    {
871
        if (is_array($tvId) && !empty($tvId)) {
872
            $tbl_site_tmplvars = $this->makeTable('site_tmplvars');
873
            $fields = 'id,name,default_text as value,display,display_params,type';
874
            $implodeTvId = implode(',', $tvId);
875
            $rs = $this->query("SELECT {$fields} FROM {$tbl_site_tmplvars} WHERE id IN({$implodeTvId})");
876
            $rows = $this->modx->db->makeArray($rs);
877
            $this->tvd = array();
878
            foreach ($rows as $item) {
879
                $this->tvd[$item['name']] = $item;
880
            }
881
        }
882
883
        return $this;
884
    }
885
886
    /**
887
     * @param $tpl
888
     * @return int
889
     * @throws Exception
890
     */
891
    public function setTemplate($tpl)
892
    {
893
        if (!is_numeric($tpl) || $tpl != (int)$tpl) {
894
            if (is_scalar($tpl)) {
895
                $sql = "SELECT `id` FROM {$this->makeTable('site_templates')} WHERE `templatename` = '" . $this->escape($tpl) . "'";
896
                $rs = $this->query($sql);
897
                if (!$rs || $this->modx->db->getRecordCount($rs) <= 0) {
898
                    throw new Exception("Template {$tpl} is not exists");
899
                }
900
                $tpl = $this->modx->db->getValue($rs);
901
            } else {
902
                throw new Exception("Invalid template name: " . print_r($tpl, 1));
903
            }
904
        }
905
906
        return (int)$tpl;
907
    }
908
909
    /**
910
     * @return string
911
     */
912
    protected function getAlias()
913
    {
914
        if ($this->modxConfig('friendly_urls') && $this->modxConfig('automatic_alias') && $this->get('alias') == '') {
915
            $alias = strtr($this->get('pagetitle'), $this->table);
916
        } else {
917
            if ($this->get('alias') != '') {
918
                $alias = $this->get('alias');
919
            } else {
920
                $alias = '';
921
            }
922
        }
923
        $alias = $this->modx->stripAlias($alias);
924
925
        return $this->checkAlias($alias);
926
    }
927
928
    /**
929
     * @param int $parent
930
     * @param string $criteria
931
     * @param string $dir
932
     * @return $this
933
     *
934
     * Пересчет menuindex по полю таблицы site_content
935
     */
936
    public function updateMenuindex($parent, $criteria = 'id', $dir = 'asc')
937
    {
938
        $dir = strtolower($dir) == 'desc' ? 'desc' : 'asc';
939
        if (is_integer($parent) && $criteria !== '') {
940
            $this->query("SET @index := 0");
941
            $this->query("UPDATE {$this->makeTable('site_content')} SET `menuindex` = (@index := @index + 1) WHERE `parent`={$parent} ORDER BY {$criteria} {$dir}");
942
        }
943
944
        return $this;
945
    }
946
947
    /**
948
     * Устанавливает значение шаблона согласно системной настройке
949
     *
950
     * @return $this
951
     */
952
    public function setDefaultTemplate()
953
    {
954
        $parent = $this->get('parent');
955
        $template = $this->modxConfig('default_template');
956
        switch ($this->modxConfig('auto_template_logic')) {
957
            case 'sibling':
958
                if (!$parent) {
959
                    $site_start = $this->modxConfig('site_start');
960
                    $where = "sc.isfolder=0 AND sc.id!={$site_start}";
961
                    $sibl = $this->modx->getDocumentChildren($parent, 1, 0, 'template', $where, 'menuindex', 'ASC', 1);
962
                    if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') {
963
                        $template = $sibl[0]['template'];
964
                    }
965
                } else {
966
                    $sibl = $this->modx->getDocumentChildren($parent, 1, 0, 'template', 'isfolder=0', 'menuindex',
967
                        'ASC', 1);
968
                    if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') {
969
                        $template = $sibl[0]['template'];
970
                    } else {
971
                        $sibl = $this->modx->getDocumentChildren($parent, 0, 0, 'template', 'isfolder=0', 'menuindex',
972
                            'ASC', 1);
973
                        if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') {
974
                            $template = $sibl[0]['template'];
975
                        }
976
                    }
977
                }
978
                break;
979
            case 'parent':
980
                if ($parent) {
981
                    $_parent = $this->modx->getPageInfo($parent, 0, 'template');
982
                    if (isset($_parent['template'])) {
983
                        $template = $_parent['template'];
984
                    }
985
                }
986
                break;
987
        }
988
        $this->set('template', $template);
989
990
        return $this;
991
    }
992
993
    /**
994
     * Декодирует конкретное поле
995
     * @param  string $field Имя поля
996
     * @param  bool $store обновить распакованное поле
997
     * @return array ассоциативный массив с данными из json строки
998
     */
999
    public function decodeField($field, $store = false)
1000
    {
1001
        $out = array();
1002
        if ($this->isDecodableField($field)) {
1003
            $data = $this->get($field);
1004
            if ($this->isTVarrayField($field)) {
1005
                $out = explode('||', $data);
1006
            } else {
1007
                $out = jsonHelper::jsonDecode($data, array('assoc' => true), true);
1008
            }
1009
        }
1010
        if ($store) {
1011
            $this->field[$field] = $out;
1012
            $this->markAsDecode($field);
1013
        }
1014
1015
        return $out;
1016
    }
1017
1018
    /**
1019
     * Запаковывает конкретное поле в JSON
1020
     * @param  string $field Имя поля
1021
     * @param  bool $store обновить запакованное поле
1022
     * @return string|null json строка
1023
     */
1024
    public function encodeField($field, $store = false)
1025
    {
1026
        $out = null;
1027
        if ($this->isEncodableField($field)) {
1028
            $data = $this->get($field);
1029
            if ($this->isTVarrayField($field)) {
1030
                $out = is_array($data) ? implode('||', $data) : $data;
1031
            } else {
1032
                $out = json_encode($data);
1033
            }
1034
        }
1035
        if ($store) {
1036
            $this->field[$field] = $out;
1037
            $this->markAsEncode($field);
1038
        }
1039
1040
        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...
1041
    }
1042
1043
    /**
1044
     * Может ли содержать данное поле json массив
1045
     * @param  string $field имя поля
1046
     * @return boolean
1047
     */
1048
    public function isTVarrayField($field)
1049
    {
1050
        return (is_scalar($field) && in_array($field, $this->tvaFields));
1051
    }
1052
1053
    /**
1054
     * Пометить все поля как запакованные
1055
     * @return $this
1056
     */
1057
    public function markAllEncode()
1058
    {
1059
        parent::markAllEncode();
1060
        foreach ($this->tvaFields as $field) {
1061
            $this->markAsEncode($field);
1062
        }
1063
1064
        return $this;
1065
    }
1066
1067
    /**
1068
     * Пометить все поля как распакованные
1069
     * @return $this
1070
     */
1071
    public function markAllDecode()
1072
    {
1073
        parent::markAllDecode();
1074
        foreach ($this->tvaFields as $field) {
1075
            $this->markAsDecode($field);
1076
        }
1077
1078
        return $this;
1079
    }
1080
1081
    /**
1082
     * @param int $docId
1083
     */
1084
    public function getDocumentGroups($docId = 0) {
1085
        $out = array();
1086
        $doc = $this->switchObject($docId);
1087
        if (null !== $doc->getID()) {
1088
            $doc_groups = $this->modx->getFullTableName('document_groups');
1089
            $sql = "SELECT `document_group` FROM {$doc_groups} WHERE `document` = " . $doc->getID();
1090
            $out = $this->modx->db->getColumn('document_group', $this->query($sql));
1091
1092
        }
1093
        unset($doc);
1094
1095
        return $out;
1096
    }
1097
1098
    /**
1099
     * @param int $docId
1100
     * @param array $groupIds
1101
     * @return $this
1102
     */
1103
    public function setDocumentGroups($docId = 0, $groupIds = array())
1104
    {
1105
        if (!is_array($groupIds)) return $this;
1106
        if ($this->newDoc && $docId == 0) {
1107
            $this->groupIds = $groupIds;
1108
        } else {
1109
            $doc = $this->switchObject($docId);
1110
            if ($id = $doc->getID()) {
1111
                foreach ($groupIds as $gid) {
1112
                    $this->query("REPLACE INTO {$this->makeTable('document_groups')} (`document_group`, `document`) VALUES ('{$gid}', '{$id}')");
1113
                }
1114
                if (!$this->newDoc) {
1115
                    $groupIds = empty($groupIds) ? '0' : implode(',', $groupIds);
1116
                    $this->query("DELETE FROM {$this->makeTable('document_groups')} WHERE `document`={$id} AND `document_group` NOT IN ({$groupIds})");
1117
                }
1118
            }
1119
            unset($doc);
1120
            $this->groupIds = array();
1121
        }
1122
1123
        return $this;
1124
    }
1125
1126
}
1127