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

DLTemplate::setTwigTemplateVars()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
c 0
b 0
f 0
rs 10
cc 2
eloc 2
nc 2
nop 1
1
<?php
2
3
include_once(MODX_BASE_PATH . 'assets/lib/APIHelpers.class.php');
1 ignored issue
show
Bug introduced by
The constant MODX_BASE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
4
5
/**
6
 * Class DLTemplate
7
 */
8
class DLTemplate
9
{
10
    /**
11
     * Объект DocumentParser - основной класс MODX
12
     * @var \DocumentParser
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...
13
     * @access protected
14
     */
15
    protected $modx = null;
16
17
    /**
18
     * @var DLTemplate cached reference to singleton instance
19
     */
20
    protected static $instance;
21
22
    protected $templatePath = 'assets/templates/';
23
24
    protected $templateExtension = 'html';
25
26
    /**
27
     * @var null|Twig_Environment twig object
0 ignored issues
show
Bug introduced by
The type Twig_Environment 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...
28
     */
29
    protected $twig = null;
30
31
    protected $twigEnabled = false;
32
33
    protected $twigTemplateVars = array();
34
35
    public $phx = null;
36
37
    /**
38
     * gets the instance via lazy initialization (created on first usage)
39
     *
40
     * @return self
41
     */
42
    public static function getInstance(DocumentParser $modx)
43
    {
44
45
        if (null === self::$instance) {
46
            self::$instance = new self($modx);
47
        }
48
49
        return self::$instance;
50
    }
51
52
    /**
53
     * is not allowed to call from outside: private!
54
     *
55
     */
56
    private function __construct(DocumentParser $modx)
57
    {
58
        $this->modx = $modx;
59
    }
60
61
    /**
62
     * prevent the instance from being cloned
63
     *
64
     * @return void
65
     */
66
    private function __clone()
67
    {
68
69
    }
70
71
    /**
72
     * prevent from being unserialized
73
     *
74
     * @return void
75
     */
76
    private function __wakeup()
77
    {
78
79
    }
80
81
    /**
82
     * Задает относительный путь к папке с шаблонами
83
     *
84
     * @param $path
85
     * @return $this
86
     */
87
    public function setTemplatePath($path)
88
    {
89
        $path = trim($path);
90
        $path = preg_replace(array(
91
            '/\.*[\/|\\\]/i',
92
            '/[\/|\\\]+/i'
93
        ), array('/', '/'), $path);
94
95
        if (!empty($path)) {
96
            $this->templatePath = $path;
97
        }
98
99
        return $this;
100
    }
101
102
    /**
103
     * Задает расширение файла с шаблоном
104
     *
105
     * @param $ext
106
     * @return $this
107
     */
108
    public function setTemplateExtension($ext)
109
    {
110
        $ext = trim($ext, ". \t\n\r\0\x0B");
111
        if (!empty($ext)) {
112
            $this->templateExtension = $ext;
113
        }
114
115
        return $this;
116
    }
117
118
    /**
119
     * Additional data for twig templates
120
     *
121
     * @param array $data
122
     * @return $this
123
     */
124
    public function setTwigTemplateVars($data = array()) {
125
        if (is_array($data)) $this->twigTemplateVars = $data;
0 ignored issues
show
introduced by
The condition is_array($data) can never be false.
Loading history...
126
        return $this;
127
    }
128
129
    /**
130
     * Сохранение данных в массив плейсхолдеров
131
     *
132
     * @param mixed $data данные
133
     * @param int $set устанавливать ли глобальнй плейсхолдер MODX
134
     * @param string $key ключ локального плейсхолдера
135
     * @param string $prefix префикс для ключей массива
136
     * @return string
137
     */
138
    public function toPlaceholders($data, $set = 0, $key = 'contentPlaceholder', $prefix = '')
139
    {
140
        $out = '';
141
        if ($set != 0) {
142
            $this->modx->toPlaceholder($key, $data, $prefix);
143
        } else {
144
            $out = $data;
145
        }
146
147
        return $out;
148
    }
149
150
    /**
151
     * refactor $modx->getChunk();
152
     *
153
     * @param string $name Template: chunk name || @CODE: template || @FILE: file with template
154
     * @return string html template with placeholders without data
155
     */
156
    public function getChunk($name)
157
    {
158
        $tpl = '';
159
        $this->twigEnabled = substr($name,0,3) == '@T_';
160
        if ($name != '' && !isset($this->modx->chunkCache[$name])) {
161
            $mode = (preg_match('/^((@[A-Z_]+)[:]{0,1})(.*)/Asu', trim($name),
162
                    $tmp) && isset($tmp[2], $tmp[3])) ? $tmp[2] : false;
163
            $subTmp = (isset($tmp[3])) ? trim($tmp[3]) : null;
164
            if ($this->twigEnabled) $mode = '@'.substr($mode,3);
0 ignored issues
show
Bug introduced by
It seems like $mode can also be of type false; however, parameter $string of substr() does only seem to accept string, 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

164
            if ($this->twigEnabled) $mode = '@'.substr(/** @scrutinizer ignore-type */ $mode,3);
Loading history...
165
            switch ($mode) {
166
                case '@FILE':
167
                    if ($subTmp != '') {
168
                        $real = realpath(MODX_BASE_PATH . $this->templatePath);
1 ignored issue
show
Bug introduced by
The constant MODX_BASE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
169
                        $path = realpath(MODX_BASE_PATH . $this->templatePath . preg_replace(array(
170
                                '/\.*[\/|\\\]/i',
171
                                '/[\/|\\\]+/i'
172
                            ), array('/', '/'), $subTmp) . '.' . $this->templateExtension);
173
                        $fname = explode(".", $path);
174
                        if ($real == substr($path, 0,
175
                                strlen($real)) && end($fname) == $this->templateExtension && file_exists($path)
176
                        ) {
177
                            $tpl = file_get_contents($path);
178
                        }
179
                    }
180
                    break;
181
                case '@CHUNK':
182
                    if ($subTmp != '') {
183
                        $tpl = $this->modx->getChunk($subTmp);
184
                    }
185
                    break;
186
                case '@INLINE':
187
                case '@TPL':
188
                case '@CODE':
189
                    $tpl = $tmp[3]; //without trim
190
                    break;
191
                case '@DOCUMENT':
192
                case '@DOC':
193
                    switch (true) {
194
                        case ((int)$subTmp > 0):
195
                            $tpl = $this->modx->getPageInfo((int)$subTmp, 0, "content");
196
                            $tpl = isset($tpl['content']) ? $tpl['content'] : '';
197
                            break;
198
                        case ((int)$subTmp == 0):
199
                            $tpl = $this->modx->documentObject['content'];
200
                            break;
201
                    }
202
                    break;
203
                case '@PLH':
204
                case '@PLACEHOLDER':
205
                    if ($subTmp != '') {
206
                        $tpl = $this->modx->getPlaceholder($subTmp);
207
                    }
208
                    break;
209
                case '@CFG':
210
                case '@CONFIG':
211
                case '@OPTIONS':
212
                    if ($subTmp != '') {
213
                        $tpl = $this->modx->getConfig($subTmp);
214
                    }
215
                    break;
216
                case '@SNIPPET':
217
                    if ($subTmp != '') {
218
                        $tpl = $this->modx->runSnippet($subTmp, $this->modx->event->params);
219
                    }
220
                    break;
221
                case '@RENDERPAGE':
222
                    $tpl = $this->renderDoc($subTmp, false);
0 ignored issues
show
Bug introduced by
It seems like $subTmp can also be of type string; however, parameter $id of DLTemplate::renderDoc() 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

222
                    $tpl = $this->renderDoc(/** @scrutinizer ignore-type */ $subTmp, false);
Loading history...
223
                    break;
224
                case '@LOADPAGE':
225
                    $tpl = $this->renderDoc($subTmp, true);
226
                    break;
227
                case '@TEMPLATE':
228
                    $tpl = $this->getTemplate($subTmp);
0 ignored issues
show
Bug introduced by
It seems like $subTmp can also be of type string; however, parameter $id of DLTemplate::getTemplate() 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

228
                    $tpl = $this->getTemplate(/** @scrutinizer ignore-type */ $subTmp);
Loading history...
229
                    break;
230
                default:
231
                    $tpl = $this->modx->getChunk($name);
232
            }
233
            $this->modx->chunkCache[$name] = $tpl;
234
        } else {
235
            if ($name != '') {
236
                $tpl = $this->modx->getChunk($name);
237
            }
238
        }
239
240
        return $tpl;
241
    }
242
243
    /**
244
     * Рендер документа с подстановкой плейсхолдеров и выполнением сниппетов
245
     *
246
     * @param int $id ID документа
247
     * @param bool $events Во время рендера документа стоит ли вызывать события OnLoadWebDocument и OnLoadDocumentObject (внутри метода getDocumentObject).
248
     * @param mixed $tpl Шаблон с которым необходимо отрендерить документ. Возможные значения:
249
     *                       null - Использовать шаблон который назначен документу
250
     *                       int(0-n) - Получить шаблон из базы данных с указанным ID и применить его к документу
251
     *                       string - Применить шаблон указанный в строке к документу
252
     * @return string
253
     *
254
     * Событие OnLoadWebDocument дополнительно передает параметры:
255
     *       - с источиком от куда произошел вызов события
256
     *       - оригинальный экземпляр класса DocumentParser
257
     */
258
    public function renderDoc($id, $events = false, $tpl = null)
259
    {
260
        if ((int)$id <= 0) {
261
            return '';
262
        }
263
264
        $m = clone $this->modx; //Чтобы была возможность вызывать события
265
        $m->documentObject = $m->getDocumentObject('id', (int)$id, $events ? 'prepareResponse' : null);
266
        if ($m->documentObject['type'] == "reference") {
267
            if (is_numeric($m->documentObject['content']) && $m->documentObject['content'] > 0) {
268
                $m->documentObject['content'] = $this->renderDoc($m->documentObject['content'], $events);
269
            }
270
        }
271
        switch (true) {
272
            case is_integer($tpl):
273
                $tpl = $this->getTemplate($tpl);
274
                break;
275
            case is_string($tpl):
276
                break;
277
            case is_null($tpl):
278
            default:
279
                $tpl = $this->getTemplate($m->documentObject['template']);
280
        }
281
        $m->documentContent = $tpl;
282
        if ($events) {
283
            $m->invokeEvent("OnLoadWebDocument", array(
284
                'source'   => 'DLTemplate',
285
                'mainModx' => $this->modx,
286
            ));
287
        }
288
289
        return $this->parseDocumentSource($m->documentContent, $m);
290
    }
291
292
    /**
293
     * Получить содержимое шаблона с определенным номером
294
     * @param int $id Номер шаблона
295
     * @return string HTML код шаблона
296
     */
297
    public function getTemplate($id)
298
    {
299
        $tpl = null;
300
        if ($id > 0) {
301
            $tpl = $this->modx->db->getValue("SELECT `content` FROM {$this->modx->getFullTableName("site_templates")} WHERE `id` = '{$id}'");
302
        }
303
        if (is_null($tpl)) {
304
            $tpl = '[*content*]';
305
        }
306
307
        return $tpl;
308
    }
309
310
    /**
311
     * refactor $modx->parseChunk();
312
     *
313
     * @param string $name Template: chunk name || @CODE: template || @FILE: file with template
314
     * @param array $data paceholder
315
     * @param bool $parseDocumentSource render html template via DocumentParser::parseDocumentSource()
316
     * @return string html template with data without placeholders
317
     */
318
    public function parseChunk($name, $data = array(), $parseDocumentSource = false)
319
    {
320
        $out = $this->getChunk($name);
321
        if ($this->twigEnabled && ($out != '') && ($twig = $this->getTwig($name, $out))) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $twig is correct as $this->getTwig($name, $out) targeting DLTemplate::getTwig() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
322
            $plh = $this->twigTemplateVars;
323
            $plh['data'] = $data;
324
            $plh['modx'] = $this->modx;
325
            $out = $twig->render(md5($name),$plh);
326
        } else {
327
            if (is_array($data) && ($out != '')) {
328
                if (preg_match("/\[\+[A-Z0-9\.\_\-]+\+\]/is", $out)) {
329
                    $item = $this->renameKeyArr($data, '[', ']', '+');
330
                    $out = str_replace(array_keys($item), array_values($item), $out);
331
                }
332
                if (preg_match("/:([^:=]+)(?:=`(.*?)`(?=:[^:=]+|$))?/is", $out)) {
333
                    if (is_null($this->phx) || !($this->phx instanceof DLphx)) {
334
                        $this->phx = $this->createPHx(0, 1000);
335
                    }
336
                    $this->phx->placeholders = array();
337
                    $this->setPHxPlaceholders($data);
338
                    $out = $this->phx->Parse($out);
339
                    $out = $this->cleanPHx($out);
0 ignored issues
show
Bug introduced by
It seems like $out can also be of type mixed; however, parameter $string of DLTemplate::cleanPHx() does only seem to accept string, 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

339
                    $out = $this->cleanPHx(/** @scrutinizer ignore-type */ $out);
Loading history...
340
                }
341
            }
342
        }
343
        if ($parseDocumentSource) {
344
            $out = $this->parseDocumentSource($out);
345
        }
346
347
        return $out;
348
    }
349
350
    /**
351
     *
352
     * @param string|array $value
353
     * @param string $key
354
     * @param string $path
355
     */
356
    public function setPHxPlaceholders($value = '', $key = '', $path = '')
357
    {
358
        $keypath = !empty($path) ? $path . "." . $key : $key;
359
        $this->phx->curPass = 0;
360
        if (is_array($value)) {
361
            foreach ($value as $subkey => $subval) {
362
                $this->setPHxPlaceholders($subval, $subkey, $keypath);
363
            }
364
        } else {
365
            $this->phx->setPHxVariable($keypath, $value);
366
        }
367
    }
368
369
    /**
370
     * Return clone of twig
371
     *
372
     * @return null
373
     */
374
    protected function getTwig($name, $tpl) {
375
        if (is_null($this->twig) && isset($this->modx->twig)) {
376
            $twig = clone $this->modx->twig;
377
            $this->twig = $twig;
378
        } else {
379
            $twig = $this->twig;
380
        }
381
        if ($twig && class_exists('Twig_Loader_Array')) {
382
            $twig->getLoader()->addLoader(
383
                new Twig_Loader_Array(array(
0 ignored issues
show
Bug introduced by
The type Twig_Loader_Array 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...
384
                    md5($name) => $tpl
385
                ))
386
            );
387
        }
388
        return $twig;
389
    }
390
391
    /**
392
     *
393
     * @param string $string
394
     * @return string
395
     */
396
    public function cleanPHx($string)
397
    {
398
        preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?)(\1|\))\]~s', $string, $matches);
399
        if ($matches[0]) {
400
            $string = str_replace($matches[0], '', $string);
401
        }
402
403
        return $string;
404
    }
405
406
    /**
407
     * @param int $debug
408
     * @param int $maxpass
409
     * @return DLphx
410
     */
411
    public function createPHx($debug = 0, $maxpass = 50)
412
    {
413
        if (!class_exists('DLphx', false)) {
414
            include_once(__DIR__ . '/DLphx.class.php');
415
        }
416
417
        return new DLphx($debug, $maxpass);
418
    }
419
420
    /**
421
     * Переменовывание элементов массива
422
     *
423
     * @param array $data массив с данными
424
     * @param string $prefix префикс ключей
425
     * @param string $suffix суффикс ключей
426
     * @param string $sep разделитель суффиксов, префиксов и ключей массива
427
     * @return array массив с переименованными ключами
428
     */
429
    public function renameKeyArr($data, $prefix = '', $suffix = '', $sep = '.')
430
    {
431
        return APIhelpers::renameKeyArr($data, $prefix, $suffix, $sep);
432
    }
433
434
    /**
435
     * @param $out
436
     * @param DocumentParser|null $modx
437
     * @return mixed|string
438
     */
439
    public function parseDocumentSource($out, $modx = null)
440
    {
441
        if (!is_object($modx)) {
442
            $modx = $this->modx;
443
        }
444
        $minPasses = empty ($modx->minParserPasses) ? 2 : $modx->minParserPasses;
445
        $maxPasses = empty ($modx->maxParserPasses) ? 10 : $modx->maxParserPasses;
446
        $site_status = $modx->getConfig('site_status');
447
        $modx->config['site_status'] = 0;
448
        for ($i = 1; $i <= $maxPasses; $i++) {
449
            $html = $out;
450
            if (preg_match('/\[\!(.*)\!\]/us', $out)) {
451
                $out = str_replace(array('[!', '!]'), array('[[', ']]'), $out);
452
            }
453
            if ($i <= $minPasses || $out != $html) {
454
                $out = $modx->parseDocumentSource($out);
455
            } else {
456
                break;
457
            }
458
        }
459
        $out = $modx->rewriteUrls($out);
460
        $modx->config['site_status'] = $site_status;
461
462
        return $out;
463
    }
464
}
465