Test Failed
Push — master ( 2e3a76...f34778 )
by Agel_Nash
02:27
created

DLTemplate::getTemplateExtension()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
3
include_once(MODX_BASE_PATH . 'assets/lib/APIHelpers.class.php');
4
5
use EvolutionCMS\Core as DocumentParser;
0 ignored issues
show
Bug introduced by
The type EvolutionCMS\Core 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...
6
/**
7
 * Class DLTemplate
8
 */
9
class DLTemplate
10
{
11
    /**
12
     * Объект DocumentParser - основной класс MODX
13
     * @var DocumentParser $modx
14
     * @access protected
15
     */
16
    protected $modx = null;
17
18
    /**
19
     * @var DLTemplate cached reference to singleton instance
20
     */
21
    protected static $instance;
22
23
    protected $templatePath = 'assets/templates/';
24
25
    protected $templateExtension = 'html';
26
27
    /**
28
     * @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...
29
     */
30
    protected $twig = null;
31
32
    protected $twigEnabled = false;
33
34
    protected $bladeEnabled = false;
35
36
    protected $templateData = array();
37
38
    public $phx = null;
39
40
    /**
41
     * gets the instance via lazy initialization (created on first usage)
42
     *
43
     * @return self
44
     */
45
    public static function getInstance(DocumentParser $modx)
46
    {
47
48
        if (null === self::$instance) {
49
            self::$instance = new self($modx);
50
        }
51
52
        return self::$instance;
53
    }
54
55
    /**
56
     * is not allowed to call from outside: private!
57
     *
58
     */
59
    private function __construct(DocumentParser $modx)
60
    {
61
        $this->modx = $modx;
62
    }
63
64
    /**
65
     * prevent the instance from being cloned
66
     *
67
     * @return void
68
     */
69
    private function __clone()
70
    {
71
    }
72
73
    /**
74
     * prevent from being unserialized
75
     *
76
     * @return void
77
     */
78
    private function __wakeup()
79
    {
80
    }
81
82
    /**
83
     * Задает относительный путь к папке с шаблонами
84
     *
85
     * @param $path
86
     * @param bool $supRoot
87
     * @return $this
88
     */
89
    public function setTemplatePath($path, $supRoot = false)
90
    {
91
        $path = trim($path);
92
        if ($supRoot === false) {
93
            $path = preg_replace(array(
94
                '/\.*[\/|\\\]/i',
95
                '/[\/|\\\]+/i'
96
            ), array('/', '/'), $path);
97
        }
98
99
        if (!empty($path)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
100
            $this->templatePath = $path;
101
        }
102
103
        return $this;
104
    }
105
106
    public function getTemplatePath()
107
    {
108
        return $this->templatePath;
109
    }
110
111
    /**
112
     * Задает расширение файла с шаблоном
113
     *
114
     * @param $ext
115
     * @return $this
116
     */
117
    public function setTemplateExtension($ext)
118
    {
119
        $ext = preg_replace(array(
120
            '/\.*[\/|\\\]/i',
121
            '/[\/|\\\]+/i'
122
        ), array('/', '/'), trim($ext, ". \t\n\r\0\x0B"));
123
124
        if (!empty($ext)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
125
            $this->templateExtension = $ext;
126
        }
127
128
        return $this;
129
    }
130
131
    public function getTemplateExtension()
132
    {
133
        return $this->templateExtension;
134
    }
135
136
    /**
137
     * Additional data for external templates
138
     *
139
     * @param array $data
140
     * @return $this
141
     */
142
    public function setTemplateData($data = array())
143
    {
144
        if (is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($data) is always true.
Loading history...
145
            $this->templateData = $data;
146
        }
147
148
        return $this;
149
    }
150
151
    /**
152
     * @param array $data
153
     * @return array
154
     */
155
    public function getTemplateData($data = array())
156
    {
157
        $plh = $this->templateData;
158
        $plh['data'] = $data;
159
        $plh['modx'] = $this->modx;
160
161
        return $plh;
162
    }
163
164
    /**
165
     * Сохранение данных в массив плейсхолдеров
166
     *
167
     * @param mixed $data данные
168
     * @param int $set устанавливать ли глобальнй плейсхолдер MODX
169
     * @param string $key ключ локального плейсхолдера
170
     * @param string $prefix префикс для ключей массива
171
     * @return string
172
     */
173
    public function toPlaceholders($data, $set = 0, $key = 'contentPlaceholder', $prefix = '')
174
    {
175
        $out = '';
176
        if ($set != 0) {
177
            $this->modx->toPlaceholder($key, $data, $prefix);
178
        } else {
179
            $out = $data;
180
        }
181
182
        return $out;
183
    }
184
185
    /**
186
     * refactor $modx->getChunk();
187
     *
188
     * @param string $name Template: chunk name || @CODE: template || @FILE: file with template
189
     * @return string html template with placeholders without data
190
     */
191
    public function getChunk($name)
0 ignored issues
show
Coding Style introduced by
Function's nesting level (5) exceeds 3; consider refactoring the function
Loading history...
192
    {
193
        $tpl = '';
194
        $this->twigEnabled = (0 === strpos($name, '@T_'));
195
        $this->bladeEnabled = (0 === strpos($name, '@B_'));
196
        if ($name != '' && !isset($this->modx->chunkCache[$name])) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
197
            $mode = (preg_match(
198
                '/^((@[A-Z_]+)[:]{0,1})(.*)/Asu',
199
                trim($name),
200
                $tmp
201
            ) && isset($tmp[2], $tmp[3])) ? $tmp[2] : false;
202
            $subTmp = (isset($tmp[3])) ? trim($tmp[3]) : null;
203
            if ($this->twigEnabled) {
204
                $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

204
                $mode = '@' . substr(/** @scrutinizer ignore-type */ $mode, 3);
Loading history...
205
            } elseif ($this->bladeEnabled) {
206
                $mode = '@' . substr($mode, 3);
207
            }
208
            switch ($mode) {
209
                case '@FILE':
210
                    if ($subTmp != '') {
211
                        $real = realpath(MODX_BASE_PATH . $this->templatePath);
212
                        $path = realpath(MODX_BASE_PATH . $this->templatePath . preg_replace(array(
213
                                '/\.*[\/|\\\]/i',
214
                                '/[\/|\\\]+/i'
215
                            ), array('/', '/'), $subTmp) . '.' . $this->templateExtension);
216
                        if (basename($path, '.' . $this->templateExtension) !== '' &&
217
                            0 === strpos($path, $real) &&
218
                            file_exists($path)
219
                        ) {
220
                            $tpl = file_get_contents($path);
221
                        }
222
                    }
223
                    break;
224
                case '@CHUNK':
225
                    if ($subTmp != '') {
226
                        $tpl = $this->modx->getChunk($subTmp);
227
                    }
228
                    break;
229
                case '@INLINE':
230
                case '@TPL':
231
                case '@CODE':
232
                    $tpl = $tmp[3]; //without trim
233
                    break;
234
                case '@DOCUMENT':
235
                case '@DOC':
236
                    switch (true) {
237
                        case ((int)$subTmp > 0):
238
                            $tpl = $this->modx->getPageInfo((int)$subTmp, 0, "content");
239
                            $tpl = isset($tpl['content']) ? $tpl['content'] : '';
240
                            break;
241
                        case ((int)$subTmp == 0):
242
                            $tpl = $this->modx->documentObject['content'];
243
                            break;
244
                    }
245
                    break;
246
                case '@PLH':
247
                case '@PLACEHOLDER':
248
                    if ($subTmp != '') {
249
                        $tpl = $this->modx->getPlaceholder($subTmp);
250
                    }
251
                    break;
252
                case '@CFG':
253
                case '@CONFIG':
254
                case '@OPTIONS':
255
                    if ($subTmp != '') {
256
                        $tpl = $this->modx->getConfig($subTmp);
257
                    }
258
                    break;
259
                case '@SNIPPET':
260
                    if ($subTmp != '') {
261
                        $tpl = $this->modx->runSnippet($subTmp, $this->modx->event->params);
262
                    }
263
                    break;
264
                case '@RENDERPAGE':
265
                    $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

265
                    $tpl = $this->renderDoc(/** @scrutinizer ignore-type */ $subTmp, false);
Loading history...
266
                    break;
267
                case '@LOADPAGE':
268
                    $tpl = $this->renderDoc($subTmp, true);
269
                    break;
270
                case '@TEMPLATE':
271
                    $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

271
                    $tpl = $this->getTemplate(/** @scrutinizer ignore-type */ $subTmp);
Loading history...
272
                    break;
273
                default:
274
                    $tpl = $this->modx->getChunk($name);
275
            }
276
            $this->modx->chunkCache[$name] = $tpl;
277
        } else {
278
            if ($name != '') {
279
                $tpl = $this->modx->getChunk($name);
280
            }
281
        }
282
283
        return $tpl;
284
    }
285
286
    /**
287
     * Рендер документа с подстановкой плейсхолдеров и выполнением сниппетов
288
     *
289
     * @param int $id ID документа
290
     * @param bool $events Во время рендера документа стоит ли вызывать события OnLoadWebDocument и OnLoadDocumentObject (внутри метода getDocumentObject).
291
     * @param mixed $tpl Шаблон с которым необходимо отрендерить документ. Возможные значения:
292
     *                       null - Использовать шаблон который назначен документу
293
     *                       int(0-n) - Получить шаблон из базы данных с указанным ID и применить его к документу
294
     *                       string - Применить шаблон указанный в строке к документу
295
     * @return string
296
     *
297
     * Событие OnLoadWebDocument дополнительно передает параметры:
298
     *       - с источиком от куда произошел вызов события
299
     *       - оригинальный экземпляр класса DocumentParser
300
     */
301
    public function renderDoc($id, $events = false, $tpl = null)
302
    {
303
        $id = (int)$id;
304
        if ($id <= 0) {
305
            return '';
306
        }
307
308
        $m = clone $this->modx; //Чтобы была возможность вызывать события
309
        $m->documentIdentifier = $id;
310
        $m->documentObject = $m->getDocumentObject('id', (int)$id, $events ? 'prepareResponse' : null);
311
        if ($m->documentObject['type'] == "reference") {
312
            if (is_numeric($m->documentObject['content']) && $m->documentObject['content'] > 0) {
313
                $m->documentObject['content'] = $this->renderDoc($m->documentObject['content'], $events);
314
            }
315
        }
316
        switch (true) {
317
            case is_integer($tpl):
318
                $tpl = $this->getTemplate($tpl);
319
                break;
320
            case is_string($tpl):
321
                break;
322
            case is_null($tpl):
323
            default:
324
                $tpl = $this->getTemplate($m->documentObject['template']);
325
        }
326
        $m->documentContent = $tpl;
327
        if ($events) {
328
            $m->invokeEvent("OnLoadWebDocument", array(
329
                'source'   => 'DLTemplate',
330
                'mainModx' => $this->modx,
331
            ));
332
        }
333
334
        return $this->parseDocumentSource($m->documentContent, $m);
335
    }
336
337
    /**
338
     * Получить содержимое шаблона с определенным номером
339
     * @param int $id Номер шаблона
340
     * @return string HTML код шаблона
341
     */
342
    public function getTemplate($id)
343
    {
344
        $tpl = null;
345
        $id = (int)$id;
346
        if ($id > 0) {
347
            $tpl = $this->modx->getDatabase()->getValue("SELECT `content` FROM {$this->modx->getDatabase()->getFullTableName("site_templates")} WHERE `id` = {$id}");
348
        }
349
        if (is_null($tpl)) {
350
            $tpl = '[*content*]';
351
        }
352
353
        return $tpl;
354
    }
355
356
    /**
357
     * refactor $modx->parseChunk();
358
     *
359
     * @param string $name Template: chunk name || @CODE: template || @FILE: file with template
360
     * @param array $data paceholder
361
     * @param bool $parseDocumentSource render html template via DocumentParser::parseDocumentSource()
362
     * @return string html template with data without placeholders
363
     */
364
    public function parseChunk($name, $data = array(), $parseDocumentSource = false, $disablePHx = false)
0 ignored issues
show
Coding Style introduced by
Function's nesting level (4) exceeds 3; consider refactoring the function
Loading history...
365
    {
366
        $out = $this->getChunk($name);
367
        switch (true) {
368
            case $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...
369
                $out = $twig->render(md5($name), $this->getTemplateData($data));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $twig does not seem to be defined for all execution paths leading up to this point.
Loading history...
370
                break;
371
            case $this->bladeEnabled && $out !== '' && ($blade = $this->getBlade($name, $out)):
372
                $out = $blade->with($this->getTemplateData($data))->render();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $blade does not seem to be defined for all execution paths leading up to this point.
Loading history...
373
                break;
374
            case is_array($data) && ($out != ''):
375
                if (preg_match("/\[\+[A-Z0-9\.\_\-]+\+\]/is", $out)) {
376
                    $item = $this->renameKeyArr($data, '[', ']', '+');
377
                    $out = str_replace(array_keys($item), array_values($item), $out);
378
                }
379
                if (!$disablePHx && preg_match("/:([^:=]+)(?:=`(.*?)`(?=:[^:=]+|$))?/is", $out)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
380
                    if (is_null($this->phx) || !($this->phx instanceof DLphx)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
381
                        $this->phx = $this->createPHx(0, 1000);
382
                    }
383
                    $this->phx->placeholders = array();
384
                    $this->setPHxPlaceholders($data);
385
                    $out = $this->phx->Parse($out);
386
                    $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

386
                    $out = $this->cleanPHx(/** @scrutinizer ignore-type */ $out);
Loading history...
387
                }
388
                break;
389
        }
390
        if ($parseDocumentSource) {
391
            $out = $this->parseDocumentSource($out);
392
        }
393
394
        return $out;
395
    }
396
397
    /**
398
     *
399
     * @param string|array $value
400
     * @param string $key
401
     * @param string $path
402
     */
403
    public function setPHxPlaceholders($value = '', $key = '', $path = '')
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

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

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

Loading history...
404
    {
405
        $keypath = !empty($path) ? $path . "." . $key : $key;
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
406
        $this->phx->curPass = 0;
407
        if (is_array($value)) {
408
            foreach ($value as $subkey => $subval) {
409
                $this->setPHxPlaceholders($subval, $subkey, $keypath);
410
            }
411
        } else {
412
            $this->phx->setPHxVariable($keypath, $value);
413
        }
414
    }
415
416
    /**
417
     * Return clone of twig
418
     *
419
     * @param string $name
420
     * @param string $tpl
421
     * @return null
422
     */
423
    protected function getTwig($name, $tpl)
424
    {
425
        if (is_null($this->twig) && isset($this->modx->twig)) {
426
            $twig = clone $this->modx->twig;
427
            $this->twig = $twig;
428
        } else {
429
            $twig = $this->twig;
430
        }
431
        if ($twig && class_exists('Twig_Loader_Array')) {
432
            $twig->getLoader()->addLoader(
433
                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...
434
                    md5($name) => $tpl
435
                ))
436
            );
437
        }
438
439
        return $twig;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $twig also could return the type object|Twig_Environment which is incompatible with the documented return type null.
Loading history...
440
    }
441
442
    /**
443
     * Return clone of blade
444
     *
445
     * @param string $name
446
     * @param string $tpl
447
     * @return Illuminate\View\Factory
0 ignored issues
show
Bug introduced by
The type Illuminate\View\Factory 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...
448
     */
449
    protected function getBlade($name, $tpl)
450
    {
451
        $out = null;
452
        try {
453
            /**
454
             * @var Illuminate\View\Factory $blade
455
             */
456
            $blade = $this->modx->laravel->get('view');
457
            $cache = md5($name). '-'. sha1($tpl);
0 ignored issues
show
Coding Style introduced by
Concat operator must be surrounded by a single space
Loading history...
458
            $path = MODX_BASE_PATH . '/assets/cache/blade/' . $cache . '.blade.php';
459
            if (! file_exists($path)) {
460
                file_put_contents($path, $tpl);
461
            }
462
463
            $out = $blade->make('cache::' . $cache);
464
        } catch(\Exception $exception ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after CATCH keyword; 0 found
Loading history...
Coding Style introduced by
Expected 0 spaces before closing bracket; 1 found
Loading history...
465
            $this->modx->messageQuit($exception->getMessage());
466
        }
467
468
        return $out;
469
    }
470
471
    /**
472
     *
473
     * @param string $string
474
     * @return string
475
     */
476
    public function cleanPHx($string)
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

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

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

Loading history...
477
    {
478
        preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?)(\1|\))\]~s', $string, $matches);
479
        if ($matches[0]) {
480
            $string = str_replace($matches[0], '', $string);
481
        }
482
483
        return $string;
484
    }
485
486
    /**
487
     * @param int $debug
488
     * @param int $maxpass
489
     * @return DLphx
490
     */
491
    public function createPHx($debug = 0, $maxpass = 50)
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

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

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

Loading history...
492
    {
493
        if (!class_exists('DLphx')) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
494
            include_once(__DIR__ . '/DLphx.class.php');
495
        }
496
497
        return new DLphx($this->modx, $debug, $maxpass);
498
    }
499
500
    /**
501
     * Переменовывание элементов массива
502
     *
503
     * @param array $data массив с данными
504
     * @param string $prefix префикс ключей
505
     * @param string $suffix суффикс ключей
506
     * @param string $sep разделитель суффиксов, префиксов и ключей массива
507
     * @return array массив с переименованными ключами
508
     */
509
    public function renameKeyArr($data, $prefix = '', $suffix = '', $sep = '.')
510
    {
511
        return APIhelpers::renameKeyArr($data, $prefix, $suffix, $sep);
512
    }
513
514
    /**
515
     * @param $out
516
     * @param DocumentParser|null $modx
517
     * @return mixed|string
518
     */
519
    public function parseDocumentSource($out, $modx = null)
520
    {
521
        if (!is_object($modx)) {
0 ignored issues
show
Coding Style introduced by
There must be a single space after a NOT operator; 0 found
Loading history...
522
            $modx = $this->modx;
523
        }
524
        $minPasses = empty($modx->minParserPasses) ? 2 : $modx->minParserPasses;
525
        $maxPasses = empty($modx->maxParserPasses) ? 10 : $modx->maxParserPasses;
526
        $site_status = $modx->getConfig('site_status');
527
        $modx->config['site_status'] = 0;
528
        for ($i = 1; $i <= $maxPasses; $i++) {
529
            $html = $out;
530
            if (preg_match('/\[\!(.*)\!\]/us', $out)) {
531
                $out = str_replace(array('[!', '!]'), array('[[', ']]'), $out);
532
            }
533
            if ($i <= $minPasses || $out != $html) {
534
                $out = $modx->parseDocumentSource($out);
535
            } else {
536
                break;
537
            }
538
        }
539
        $out = $modx->rewriteUrls($out);
540
        $out = $this->cleanPHx($out);
541
        $modx->config['site_status'] = $site_status;
542
543
        return $out;
544
    }
545
}
546