Test Failed
Branch master (5aadec)
by Agel_Nash
04:00
created

modResource::getAlias()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 14
c 1
b 1
f 0
rs 8.8571
cc 5
eloc 9
nc 3
nop 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
        'privateweb'      => 0,
48
        'privatemgr'      => 0,
49
        'content_dispo'   => 0,
50
        'hidemenu'        => 0,
51
        'alias_visible'   => 1
52
    );
53
    /**
54
     * @var array
55
     */
56
    private $table = array(
57
        '"' => '_',
58
        "'" => '_',
59
        ' ' => '_',
60
        '.' => '_',
61
        ',' => '_',
62
        'а' => 'a',
63
        'б' => 'b',
64
        'в' => 'v',
65
        'г' => 'g',
66
        'д' => 'd',
67
        'е' => 'e',
68
        'ё' => 'e',
69
        'ж' => 'zh',
70
        'з' => 'z',
71
        'и' => 'i',
72
        'й' => 'y',
73
        'к' => 'k',
74
        'л' => 'l',
75
        'м' => 'm',
76
        'н' => 'n',
77
        'о' => 'o',
78
        'п' => 'p',
79
        'р' => 'r',
80
        'с' => 's',
81
        'т' => 't',
82
        'у' => 'u',
83
        'ф' => 'f',
84
        'х' => 'h',
85
        'ц' => 'c',
86
        'ч' => 'ch',
87
        'ш' => 'sh',
88
        'щ' => 'sch',
89
        'ь' => '',
90
        'ы' => 'y',
91
        'ъ' => '',
92
        'э' => 'e',
93
        'ю' => 'yu',
94
        'я' => 'ya',
95
        'А' => 'A',
96
        'Б' => 'B',
97
        'В' => 'V',
98
        'Г' => 'G',
99
        'Д' => 'D',
100
        'Е' => 'E',
101
        'Ё' => 'E',
102
        'Ж' => 'Zh',
103
        'З' => 'Z',
104
        'И' => 'I',
105
        'Й' => 'Y',
106
        'К' => 'K',
107
        'Л' => 'L',
108
        'М' => 'M',
109
        'Н' => 'N',
110
        'О' => 'O',
111
        'П' => 'P',
112
        'Р' => 'R',
113
        'С' => 'S',
114
        'Т' => 'T',
115
        'У' => 'U',
116
        'Ф' => 'F',
117
        'Х' => 'H',
118
        'Ц' => 'C',
119
        'Ч' => 'Ch',
120
        'Ш' => 'Sh',
121
        'Щ' => 'Sch',
122
        'Ь' => '',
123
        'Ы' => 'Y',
124
        'Ъ' => '',
125
        'Э' => 'E',
126
        'Ю' => 'Yu',
127
        'Я' => 'Ya',
128
    );
129
    /**
130
     * @var array массив ТВшек где name это ключ массива, а ID это значение
131
     */
132
    private $tv = array();
133
    /**
134
     * @var array массив ТВшек где ID это ключ массива, а name это значение
135
     */
136
    private $tvid = array();
137
    /**
138
     * @var array значения по умолчанию для ТВ параметров
139
     */
140
    private $tvd = array();
141
142
    /** @var array связи ТВ и шаблонов */
143
    private $tvTpl = array();
144
145
    /** @var array параметры ТВ с массивами */
146
    protected $tvaFields = array();
147
148
    /**
149
     * Массив администраторов
150
     * @var DLCollection
151
     */
152
    private $managerUsers = null;
153
    /** @var array группы документов */
154
    protected $groupIds = array();
155
    /**
156
     * modResource constructor.
157
     * @param DocumentParser $modx
1 ignored issue
show
Bug introduced by
The type DocumentParser 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...
158
     * @param bool $debug
159
     */
160
    public function __construct($modx, $debug = false)
161
    {
162
        parent::__construct($modx, $debug);
163
        $this->get_TV();
164
        $uTable = $this->makeTable("manager_users");
165
        $aTable = $this->makeTable("user_attributes");
166
        $query = "SELECT `u`.`id`, `a`.`email`, `u`.`username`  FROM " . $aTable . " as `a` LEFT JOIN " . $uTable . " as `u` ON `u`.`id`=`a`.`internalKey`";
167
        $query = $this->query($query);
168
        $this->managerUsers = new DLCollection($modx, empty($query) ? array() : $query);
169
    }
170
171
    /**
172
     * @return array
173
     */
174
    public function toArrayMain()
175
    {
176
        $out = array_intersect_key(parent::toArray(), $this->default_field);
177
178
        return $out;
179
    }
180
181
    /**
182
     * @param bool $render
183
     * @return array
184
     */
185
    public function toArrayTV($render = false)
186
    {
187
        $out = array_diff_key(parent::toArray(), $this->default_field);
188
        $tpl = $this->get('template');
189
        $tvTPL = APIHelpers::getkey($this->tvTpl, $tpl, array());
190
        foreach ($tvTPL as $item) {
191
            if (isset($this->tvid[$item]) && !array_key_exists($this->tvid[$item], $out)) {
192
                $out[$this->tvid[$item]] = $this->get($this->tvid[$item]);
193
            }
194
        }
195
        if ($render) {
196
            foreach ($out as $key => $val) {
197
                $out[$key] = $this->renderTV($key);
198
            }
199
        }
200
201
        return $out;
202
    }
203
204
    /**
205
     * @param string $prefix
206
     * @param string $suffix
207
     * @param string $sep
208
     * @param bool $render
209
     * @return array
210
     */
211
    public function toArray($prefix = '', $suffix = '', $sep = '_', $render = true)
212
    {
213
        $out = array_merge(
214
            $this->toArrayMain(),
215
            $this->toArrayTV($render),
216
            array($this->fieldPKName() => $this->getID())
217
        );
218
219
        return \APIhelpers::renameKeyArr($out, $prefix, $suffix, $sep);
220
    }
221
222
    /**
223
     * @return null|string
224
     */
225
    public function getUrl()
226
    {
227
        $out = null;
228
        $id = (int)$this->getID();
229
        if (!empty($id)) {
230
            $out = $this->modx->makeUrl($id);
231
        }
232
233
        return $out;
234
    }
235
236
    /**
237
     * @param string $main
238
     * @param string $second
239
     * @return mixed
240
     */
241
    public function getTitle($main = 'menutitle', $second = 'pagetitle')
242
    {
243
        $title = $this->get($main);
244
        if (empty($title) && $title !== '0') {
245
            $title = $this->get($second);
246
        }
247
248
        return $title;
249
    }
250
251
    /**
252
     * @return bool
253
     */
254
    public function isWebShow()
255
    {
256
        $pub = ($this->get('publishedon') < time() && $this->get('published'));
257
        $unpub = ($this->get('unpub_date') == 0 || $this->get('unpub_date') > time());
258
        $del = ($this->get('deleted') == 0 && ($this->get('deletedon') == 0 || $this->get('deletedon') > time()));
259
260
        return ($pub && $unpub && $del);
261
    }
262
263
    /**
264
     * @return $this
265
     */
266
    public function touch()
267
    {
268
        $this->set('editedon', time());
269
270
        return $this;
271
    }
272
273
    /**
274
     * @param $tvname
275
     * @return null|string
276
     */
277
    public function renderTV($tvname)
278
    {
279
        $out = null;
280
        if ($this->getID() > 0) {
281
            include_once MODX_MANAGER_PATH . "includes/tmplvars.format.inc.php";
1 ignored issue
show
Bug introduced by
The constant MODX_MANAGER_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
282
            include_once MODX_MANAGER_PATH . "includes/tmplvars.commands.inc.php";
283
            $tvval = $this->get($tvname);
284
            if ($this->isTVarrayField($tvname) && is_array($tvval)) {
285
                $tvval = implode('||', $tvval);
286
            }
287
            $param = APIHelpers::getkey($this->tvd, $tvname, array());
288
            $display = APIHelpers::getkey($param, 'display', '');
289
            $display_params = APIHelpers::getkey($param, 'display_params', '');
290
            $type = APIHelpers::getkey($param, 'type', '');
291
            $out = getTVDisplayFormat($tvname, $tvval, $display, $display_params, $type, $this->getID(), '');
0 ignored issues
show
Bug introduced by
The function getTVDisplayFormat was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

291
            $out = /** @scrutinizer ignore-call */ getTVDisplayFormat($tvname, $tvval, $display, $display_params, $type, $this->getID(), '');
Loading history...
292
        }
293
294
        return $out;
295
    }
296
297
    /**
298
     * @param $key
299
     * @return mixed
300
     */
301
    public function get($key)
302
    {
303
        $out = parent::get($key);
304
        if (isset($this->tv[$key])) {
305
            $tpl = $this->get('template');
306
            $tvTPL = APIHelpers::getkey($this->tvTpl, $tpl, array());
307
            $tvID = APIHelpers::getkey($this->tv, $key, 0);
308
            if (in_array($tvID, $tvTPL) && is_null($out)) {
309
                $out = APIHelpers::getkey($this->tvd[$key], 'value', null);
310
            }
311
        }
312
313
        return $out;
314
    }
315
316
    /**
317
     * @param $key
318
     * @param $value
319
     * @return $this
320
     */
321
    public function set($key, $value)
322
    {
323
        if ((is_scalar($value) || $this->isTVarrayField($key) || $this->isJsonField($key)) && is_scalar($key) && !empty($key)) {
324
            switch ($key) {
325
                case 'parent':
326
                    $value = (int)$value;
327
                    break;
328
                case 'template':
329
                    $value = trim($value);
330
                    $value = $this->setTemplate($value);
331
                    break;
332
                case 'published':
333
                    $value = (int)((bool)$value);
334
                    if ($value) {
335
                        $this->field['publishedon'] = time() + $this->modxConfig('server_offset_time');
336
                    }
337
                    break;
338
                case 'pub_date':
339
                    $value = $this->getTime($value);
340
                    if ($value > 0 && time() + $this->modxConfig('server_offset_time') > $value) {
341
                        $this->field['published'] = 1;
342
                        $this->field['publishedon'] = $value;
343
                    }
344
                    break;
345
                case 'unpub_date':
346
                    $value = $this->getTime($value);
347
                    if ($value > 0 && time() + $this->modxConfig('server_offset_time') > $value) {
348
                        $this->field['published'] = 0;
349
                        $this->field['publishedon'] = 0;
350
                    }
351
                    break;
352
                case 'deleted':
353
                    $value = (int)((bool)$value);
354
                    if ($value) {
355
                        $this->field['deletedon'] = time() + $this->modxConfig('server_offset_time');
356
                    } else {
357
                        $this->field['deletedon'] = 0;
358
                    }
359
                    break;
360
                case 'deletedon':
361
                    $value = $this->getTime($value);
362
                    if ($value > 0 && time() + $this->modxConfig('server_offset_time') < $value) {
363
                        $value = 0;
364
                    }
365
                    if ($value) {
366
                        $this->field['deleted'] = 1;
367
                    }
368
                    break;
369
                case 'editedon':
370
                case 'createdon':
371
                case 'publishedon':
372
                    $value = $this->getTime($value);
373
                    break;
374
                case 'publishedby':
375
                case 'editedby':
376
                case 'createdby':
377
                case 'deletedby':
378
                    $value = $this->getUser($value, $this->default_field[$key]);
379
                    break;
380
            }
381
            $this->field[$key] = $value;
382
        }
383
384
        return $this;
385
    }
386
387
    /**
388
     * @param $value
389
     * @param int $default
390
     * @return int|mixed
391
     */
392
    protected function getUser($value, $default = 0)
393
    {
394
        $currentAdmin = APIHelpers::getkey($_SESSION, 'mgrInternalKey', 0);
395
        $value = (int)$value;
396
        if (!empty($value)) {
397
            $by = $this->findUserBy($value);
398
            $exists = $this->managerUsers->exists(function ($key, Helpers\Collection $val) use ($by, $value) {
399
                return ($val->containsKey($by) && $val->get($by) === (string)$value);
400
            });
401
            if (!$exists) {
402
                $value = 0;
403
            }
404
        }
405
        if (empty($value)) {
406
            $value = empty($currentAdmin) ? $default : $currentAdmin;
407
        }
408
409
        return $value;
410
    }
411
412
    /**
413
     * @param $data
414
     * @return bool|string
415
     */
416
    protected function findUserBy($data)
417
    {
418
        switch (true) {
419
            case (is_int($data) || ((int)$data > 0 && (string)intval($data) === $data)):
420
                $find = 'id';
421
                break;
422
            case filter_var($data, FILTER_VALIDATE_EMAIL):
423
                $find = 'email';
424
                break;
425
            case is_scalar($data):
426
                $find = 'username';
427
                break;
428
            default:
429
                $find = false;
430
        }
431
432
        return $find;
433
    }
434
435
    /**
436
     * @param array $data
437
     * @return $this
438
     */
439
    public function create($data = array())
440
    {
441
        $this->close();
442
        $fld = array();
443
        foreach ($this->tvd as $name => $tv) {
444
            $fld[$name] = $tv['value'];
445
        };
446
        $this->store($fld);
447
448
        $this->fromArray(array_merge($fld, $data));
449
        $this->set('createdby', null)
450
            ->set('editedby', null)
451
            ->set('createdon', time())
452
            ->touch();
453
454
        return $this;
455
    }
456
457
    /**
458
     * @param $id
459
     * @return $this
460
     */
461
    public function edit($id)
462
    {
463
        $id = is_scalar($id) ? trim($id) : '';
464
        if ($this->getID() != $id) {
465
            $this->close();
466
            $this->markAllEncode();
467
            $this->newDoc = false;
468
469
            $result = $this->query("SELECT * from {$this->makeTable('site_content')} where `id`=" . (int)$id);
470
            $this->fromArray($this->modx->db->getRow($result));
471
            $result = $this->query("SELECT * from {$this->makeTable('site_tmplvar_contentvalues')} where `contentid`=" . (int)$id);
472
            while ($row = $this->modx->db->getRow($result)) {
473
                $this->field[$this->tvid[$row['tmplvarid']]] = $row['value'];
474
            }
475
            if (empty($this->field['id'])) {
476
                $this->id = null;
477
            } else {
478
                $this->id = $this->field['id'];
479
                $this->set('editedby', null)->touch();
480
                $this->decodeFields();
481
            }
482
            $this->store($this->toArray(null, null, null, false));
483
            unset($this->field['id']);
484
        }
485
486
        return $this;
487
    }
488
489
    /**
490
     * @param bool $fire_events
491
     * @param bool $clearCache
492
     * @return bool|null
493
     */
494
    public function save($fire_events = false, $clearCache = false)
495
    {
496
        $parent = null;
497
        if ($this->field['pagetitle'] == '') {
498
            $this->log['emptyPagetitle'] = 'Pagetitle is empty in <pre>' . print_r($this->field, true) . '</pre>';
499
500
            return false;
501
        }
502
503
        $uid = $this->modx->getLoginUserID('mgr');
504
505
        if (
506
            $this->field['parent'] == 0 &&
507
            !$this->modxConfig('udperms_allowroot') &&
508
            !($uid && isset($_SESSION['mgrRole']) && $_SESSION['mgrRole'] == 1)
509
        ) {
510
            $this->log['rootForbidden'] = 'Only Administrators can create documents in the root folder because udperms_allowroot setting is off';
511
512
            return false;
513
        }
514
515
        $this->set('alias', $this->getAlias());
516
517
        $this->invokeEvent('OnBeforeDocFormSave', array(
518
            'mode'   => $this->newDoc ? "new" : "upd",
519
            'id'     => isset($this->id) ? $this->id : '',
520
            'doc'    => $this->toArray(),
521
            'docObj' => $this
522
        ), $fire_events);
523
524
        $fld = $this->encodeFields()->toArray(null, null, null, false);
525
        foreach ($this->default_field as $key => $value) {
526
            $tmp = $this->get($key);
527
            if ($this->newDoc && (!is_int($tmp) && $tmp == '')) {
528
                if ($tmp == $value) {
529
                    switch ($key) {
530
                        case 'cacheable':
531
                            $value = $this->modxConfig('cache_default');
532
                            break;
533
                        case 'template':
534
                            $value = $value = $this->modxConfig('default_template');
0 ignored issues
show
Unused Code introduced by
The assignment to $value is dead and can be removed.
Loading history...
535
                            break;
536
                        case 'published':
537
                            $value = $this->modxConfig('publish_default');
538
                            break;
539
                        case 'searchable':
540
                            $value = $this->modxConfig('search_default');
541
                            break;
542
                        case 'donthit':
543
                            $value = $this->modxConfig('track_visitors');
544
                            break;
545
                    }
546
                }
547
                $this->field[$key] = $value;
548
            }
549
            switch (true) {
550
                case $key == 'parent':
551
                    $parent = (int)$this->get($key);
552
                    $q = $this->query("SELECT count(`id`) FROM {$this->makeTable('site_content')} WHERE `id`='{$parent}'");
553
                    if ($this->modx->db->getValue($q) != 1) {
554
                        $parent = 0;
555
                    }
556
                    $this->field[$key] = $parent;
557
                    $this->Uset($key);
558
                    break;
559
                case ($key == 'alias_visible' && !$this->checkVersion('1.0.10', true)):
560
                    $this->eraseField('alias_visible');
561
                    break;
562
                default:
563
                    $this->Uset($key);
564
            }
565
            unset($fld[$key]);
566
        }
567
568
        if (!empty($this->set)) {
569
            if ($this->newDoc) {
570
                $SQL = "INSERT into {$this->makeTable('site_content')} SET " . implode(', ', $this->set);
571
            } else {
572
                $SQL = "UPDATE {$this->makeTable('site_content')} SET " . implode(', ',
573
                        $this->set) . " WHERE `id` = " . $this->id;
574
            }
575
            $this->query($SQL);
576
577
            if ($this->newDoc) {
578
                $this->id = $this->modx->db->getInsertId();
579
            }
580
581
            if ($parent > 0) {
582
                $this->query("UPDATE {$this->makeTable('site_content')} SET `isfolder`='1' WHERE `id`='{$parent}'");
583
            }
584
        }
585
586
        $_deleteTVs = $_insertTVs = array();
587
        foreach ($fld as $key => $value) {
588
            if (empty($this->tv[$key]) || !$this->isChanged($key) || !$this->belongsToTemplate($this->tv[$key])) {
589
                continue;
590
            } elseif ($value === '') {
591
                $_deleteTVs[] = $this->tv[$key];
592
            } else {
593
                $_insertTVs[$this->tv[$key]] = $this->escape($value);
594
            }
595
        }
596
597
        if (!empty($_insertTVs)) {
598
            $values = array();
599
            foreach ($_insertTVs as $id => $value) {
600
                $values[] = "({$this->id}, {$id}, '{$value}')";
601
            }
602
            $values = implode(',', $values);
603
            $this->query("INSERT INTO {$this->makeTable('site_tmplvar_contentvalues')} (`contentid`,`tmplvarid`,`value`) VALUES {$values} ON DUPLICATE KEY UPDATE
604
    `value` = VALUES(`value`)");
605
        }
606
607
        if (!empty($_deleteTVs)) {
608
            $ids = implode(',', $_deleteTVs);
609
            $this->query("DELETE FROM {$this->makeTable('site_tmplvar_contentvalues')} WHERE `contentid` = '{$this->id}' AND `tmplvarid` IN ({$ids})");
610
        }
611
612
        if (!isset($this->mode)) {
613
            $this->mode = $this->newDoc ? "new" : "upd";
614
            $this->newDoc = false;
615
        }
616
617
        if (!empty($this->groupIds)) $this->setDocumentGroups($this->id, $this->groupIds);
0 ignored issues
show
Bug introduced by
It seems like $this->id can also be of type string; however, parameter $docId of modResource::setDocumentGroups() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

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