GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

View::parse()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 5
rs 10
1
<?php
2
/**
3
 * This file is part of the O2System Framework package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author         Steeve Andrian Salim
9
 * @copyright      Copyright (c) Steeve Andrian Salim
10
 */
11
12
// ------------------------------------------------------------------------
13
14
namespace O2System\Framework\Http;
15
16
// ------------------------------------------------------------------------
17
18
use O2System\Framework\Containers\Modules\DataStructures\Module\Theme;
19
use O2System\Framework\Http\Presenter\Meta;
20
use O2System\Gear\Toolbar;
0 ignored issues
show
Bug introduced by
The type O2System\Gear\Toolbar 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...
21
use O2System\Html;
22
use O2System\Spl\Patterns\Structural\Composite\RenderableInterface;
23
use O2System\Spl\DataStructures\SplArrayObject;
24
use O2System\Spl\Exceptions\ErrorException;
25
use O2System\Spl\Traits\Collectors\FileExtensionCollectorTrait;
26
use O2System\Spl\Traits\Collectors\FilePathCollectorTrait;
27
28
/**
29
 * Class View
30
 *
31
 * @package O2System
32
 */
33
class View implements RenderableInterface
34
{
35
    use FilePathCollectorTrait;
36
    use FileExtensionCollectorTrait;
37
38
    /**
39
     * View Config
40
     *
41
     * @var \O2System\Kernel\DataStructures\Config
42
     */
43
    protected $config;
44
45
    /**
46
     * View HTML Document
47
     *
48
     * @var Html\Document
49
     */
50
    protected $document;
51
52
    // ------------------------------------------------------------------------
53
54
    /**
55
     * View::__construct
56
     *
57
     * @return View
58
     */
59
    public function __construct()
60
    {
61
        $this->setFileDirName('views');
62
        $this->addFilePath(PATH_RESOURCES);
63
64
        output()->addFilePath(PATH_RESOURCES);
65
66
        $this->config = config()->loadFile('view', true);
0 ignored issues
show
Documentation Bug introduced by
It seems like config()->loadFile('view', true) can also be of type false. However, the property $config is declared as type O2System\Kernel\DataStructures\Config. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
Bug introduced by
The method loadFile() does not exist on O2System\Kernel\DataStructures\Config. ( Ignorable by Annotation )

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

66
        $this->config = config()->/** @scrutinizer ignore-call */ loadFile('view', true);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
67
68
        $this->setFileExtensions(
69
            [
70
                '.php',
71
                '.phtml',
72
            ]
73
        );
74
75
        if ($this->config->offsetExists('extensions')) {
76
            $this->setFileExtensions($this->config[ 'extensions' ]);
77
        }
78
79
        $this->document = new Html\Document();
80
        $this->document->formatOutput = (bool)$this->config->beautify;
81
    }
82
83
    /**
84
     * View::__get
85
     *
86
     * @param string $property
87
     *
88
     * @return bool Returns FALSE when property is not set.
89
     */
90
    public function &__get($property)
91
    {
92
        $get[ $property ] = false;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$get was never initialized. Although not strictly required by PHP, it is generally a good practice to add $get = array(); before regardless.
Loading history...
93
94
        if (property_exists($this, $property)) {
95
            return $this->{$property};
96
        }
97
98
        return $get[ $property ];
99
    }
100
101
    // ------------------------------------------------------------------------
102
103
    /**
104
     * View::parse
105
     *
106
     * @param string $string
107
     * @param array  $vars
108
     *
109
     * @return bool|string Returns FALSE if failed.
110
     */
111
    public function parse($string, array $vars = [])
112
    {
113
        parser()->loadString($string);
114
115
        return parser()->parse($vars);
116
    }
117
118
    // ------------------------------------------------------------------------
119
120
    /**
121
     * View::with
122
     *
123
     * @param mixed $vars
124
     * @param mixed $value
125
     *
126
     * @return static
127
     */
128
    public function with($vars, $value = null)
129
    {
130
        if (is_string($vars)) {
131
            $vars = [$vars => $value];
132
        }
133
134
        presenter()->merge($vars);
135
136
        return $this;
137
    }
138
139
    // ------------------------------------------------------------------------
140
141
    /**
142
     * View::modal
143
     *
144
     * @param string $filename
145
     * @param array  $vars
146
     */
147
    public function modal($filename, array $vars = [])
148
    {
149
        if (presenter()->theme->hasLayout('modal')) {
150
            if (presenter()->theme->hasLayout('modal')) {
151
                presenter()->theme->setLayout('modal');
152
                echo $this->load($filename, $vars, true);
153
                exit(EXIT_SUCCESS);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
154
            }
155
        }
156
157
        if ($content = $this->load($filename, $vars, true)) {
158
            echo $content;
159
            exit(EXIT_SUCCESS);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
160
        }
161
    }
162
163
    // ------------------------------------------------------------------------
164
165
    /**
166
     * View::load
167
     *
168
     * @param string $filename
169
     * @param array  $vars
170
     * @param bool   $return
171
     *
172
     * @return false|string
173
     */
174
    public function load($filename, array $vars = [], $return = false)
175
    {
176
        if ($filename instanceof \SplFileInfo) {
0 ignored issues
show
introduced by
$filename is never a sub-type of SplFileInfo.
Loading history...
177
            return $this->page($filename->getRealPath(), array_merge($vars, $filename->getVars()));
178
        }
179
180
        if (strpos($filename, 'Pages') !== false) {
181
            return $this->page($filename, $vars, $return);
182
        }
183
184
        presenter()->merge($vars);
185
186
        if (false !== ($filePath = $this->getFilePath($filename))) {
187
188
            // Load Assets
189
            presenter()->assets->addFilePath(dirname($filePath) . DIRECTORY_SEPARATOR);
190
191
            presenter()->assets->loadCss(pathinfo($filePath, PATHINFO_FILENAME));
192
            presenter()->assets->loadJs(pathinfo($filePath, PATHINFO_FILENAME));
193
194
            if ($return === false) {
195
                if (presenter()->partials->hasPartial('content') === false) {
196
                    if (is_ajax()) {
197
                        parser()->loadFile($filePath);
198
                        $content = parser()->parse(presenter()->getArrayCopy());
199
200
                        presenter()->partials->addPartial('content', $content);
201
                    } else {
202
                        presenter()->partials->addPartial('content', $filePath);
203
                    }
204
                } else {
205
                    presenter()->partials->addPartial(pathinfo($filePath, PATHINFO_FILENAME), $filePath);
206
                }
207
            } else {
208
                parser()->loadFile($filePath);
209
210
                return parser()->parse(presenter()->getArrayCopy());
211
            }
212
        } else {
213
            $vars = presenter()->getArrayCopy();
214
            extract($vars);
215
216
            $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
217
218
            $error = new ErrorException(
219
                'E_VIEW_NOT_FOUND',
220
                0,
221
                @$backtrace[ 0 ][ 'file' ],
222
                @$backtrace[ 0 ][ 'line' ],
223
                [trim($filename)]
224
            );
225
226
            unset($backtrace);
227
228
            ob_start();
229
            include output()->getFilePath('error');
0 ignored issues
show
Bug introduced by
The method getFilePath() does not exist on O2System\Kernel\Cli\Output. Did you maybe mean getFilePaths()? ( Ignorable by Annotation )

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

229
            include output()->/** @scrutinizer ignore-call */ getFilePath('error');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
230
            $content = ob_get_contents();
231
            ob_end_clean();
232
233
            if ($return === false) {
234
                if (presenter()->partials->hasPartial('content') === false) {
235
                    presenter()->addPartial('content', $content);
0 ignored issues
show
Bug introduced by
The method addPartial() does not exist on O2System\Framework\Http\Presenter. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

235
                    presenter()->/** @scrutinizer ignore-call */ addPartial('content', $content);
Loading history...
236
                } else {
237
                    presenter()->addPartial(pathinfo($filePath, PATHINFO_FILENAME), $content);
0 ignored issues
show
Bug introduced by
It seems like $filePath can also be of type false; however, parameter $path of pathinfo() 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

237
                    presenter()->addPartial(pathinfo(/** @scrutinizer ignore-type */ $filePath, PATHINFO_FILENAME), $content);
Loading history...
238
                }
239
            } else {
240
                return $content;
241
            }
242
        }
243
    }
244
245
    // ------------------------------------------------------------------------
246
247
    /**
248
     * View::page
249
     *
250
     * @param string $filename
251
     * @param array  $vars
252
     * @param bool   $return
253
     *
254
     * @return bool|string Returns FALSE if failed.
255
     */
256
    public function page($filename, array $vars = [], $return = false)
257
    {
258
        if ( ! is_file($filename)) {
259
            $pageDirectories = modules()->getResourcesDirs('pages');
0 ignored issues
show
Bug introduced by
The method getResourcesDirs() does not exist on O2System\Framework\Conta...s\DataStructures\Module. Did you maybe mean getResourcesDir()? ( Ignorable by Annotation )

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

259
            $pageDirectories = modules()->/** @scrutinizer ignore-call */ getResourcesDirs('pages');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
260
            foreach ($pageDirectories as $pageDirectory) {
261
                if (is_file($pageFilePath = $pageDirectory . $filename . '.phtml')) {
262
                    $filename = $pageFilePath;
263
                    break;
264
                }
265
            }
266
        }
267
268
        if (count($vars)) {
269
            presenter()->merge($vars);
270
        }
271
272
        presenter()->merge(presenter()->page->getVars());
273
274
        if ($return === false) {
275
            if (presenter()->partials->hasPartial('content') === false) {
276
                presenter()->partials->addPartial('content', $filename);
277
            } else {
278
                presenter()->partials->addPartial(pathinfo($filename, PATHINFO_FILENAME), $filename);
279
            }
280
        } elseif (parser()->loadFile($filename)) {
281
            return parser()->parse(presenter()->getArrayCopy());
282
        }
283
    }
284
285
    // ------------------------------------------------------------------------
286
287
    /**
288
     * View::getFilePath
289
     *
290
     * @param string $filename
291
     *
292
     * @return bool|string
293
     */
294
    public function getFilePath($filename)
295
    {
296
        $filename = str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $filename);
297
298
        if (is_file($filename)) {
299
            return realpath($filename);
300
        } else {
301
            $viewsDirectories = array_merge([
302
                PATH_KERNEL . 'Views' . DIRECTORY_SEPARATOR,
303
                PATH_FRAMEWORK . 'Views' . DIRECTORY_SEPARATOR,
304
            ], $this->filePaths);
305
306
            $viewsDirectories = array_unique($viewsDirectories);
307
            $viewsDirectories = array_reverse($viewsDirectories);
308
309
            $controllerSubDir = null;
310
            if($controller = services('controller')) {
0 ignored issues
show
Unused Code introduced by
The assignment to $controller is dead and can be removed.
Loading history...
311
                $controllerSubDir = services('controller')->getParameter() . DIRECTORY_SEPARATOR;
0 ignored issues
show
Bug introduced by
The method getParameter() does not exist on O2System\Kernel\Containers\Services. ( Ignorable by Annotation )

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

311
                $controllerSubDir = services('controller')->/** @scrutinizer ignore-call */ getParameter() . DIRECTORY_SEPARATOR;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
312
            }
313
314
            foreach ($viewsDirectories as $viewsDirectory) {
315
                $filename = str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $filename);
316
317
                // Find specific view file for mobile version
318
                if (services('userAgent')->isMobile()) {
0 ignored issues
show
Bug introduced by
The method isMobile() does not exist on O2System\Kernel\Containers\Services. ( Ignorable by Annotation )

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

318
                if (services('userAgent')->/** @scrutinizer ignore-call */ isMobile()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
319
                    // Find without controller parameter as sub directory
320
                    if (is_file($filePath = $viewsDirectory . $filename . '.mobile.phtml')) {
321
                        return realpath($filePath);
322
                        break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
323
                    }
324
325
                    // Find without controller parameter as sub directory
326
                    if (is_file($filePath = $viewsDirectory . $controllerSubDir . $filename . '.mobile.phtml')) {
327
                        return realpath($filePath);
328
                        break;
329
                    }
330
                }
331
332
                // Find without controller parameter as sub directory
333
                if (is_file($filePath = $viewsDirectory . $filename . '.phtml')) {
334
                    return realpath($filePath);
335
                    break;
336
                }
337
338
                // Find without controller parameter as sub directory
339
                if (is_file($filePath = $viewsDirectory . $controllerSubDir . $filename . '.phtml')) {
340
                    return realpath($filePath);
341
                    break;
342
                }
343
            }
344
        }
345
346
        return false;
347
    }
348
349
    // ------------------------------------------------------------------------
350
351
    /**
352
     * View::render
353
     *
354
     * @param array $options
355
     *
356
     * @return string
357
     */
358
    public function render(array $options = [])
359
    {
360
        if (profiler() !== false) {
361
            profiler()->watch('Starting View Rendering');
362
        }
363
364
        parser()->loadVars(presenter()->getArrayCopy());
365
366
        if (presenter()->page->file instanceof \SplFileInfo) {
0 ignored issues
show
introduced by
presenter()->page->file is always a sub-type of SplFileInfo.
Loading history...
367
368
            if (false === ($pagePresets = presenter()->page->getPresets())) {
0 ignored issues
show
introduced by
The condition false === $pagePresets =...r()->page->getPresets() is always false.
Loading history...
369
                if (presenter()->page->file->getFilename() === 'index') {
370
                    $title = presenter()->page->file->getDirectoryInfo()->getDirName();
371
                } else {
372
                    $titles[] = presenter()->page->file->getDirectoryInfo()->getDirName();
373
                    $titles[] = presenter()->page->file->getFilename();
374
375
                    $title = implode(' - ', array_unique($titles));
376
                }
377
378
                $pagePresets = new SplArrayObject([
379
                    'title'  => readable($title, true),
380
                    'access' => 'public',
381
                ]);
382
            }
383
384
            /**
385
             * Sets Page Theme
386
             */
387
            if ($pagePresets->offsetExists('theme')) {
388
                presenter()->setTheme($pagePresets->theme);
389
            } elseif (false !== ($theme = presenter()->getConfig('theme'))) {
390
                if (modules()->top()->hasTheme($theme)) {
0 ignored issues
show
Bug introduced by
The method top() does not exist on O2System\Framework\Conta...s\DataStructures\Module. ( Ignorable by Annotation )

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

390
                if (modules()->/** @scrutinizer ignore-call */ top()->hasTheme($theme)) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
391
                    presenter()->setTheme($theme);
0 ignored issues
show
Bug introduced by
It seems like $theme can also be of type array; however, parameter $theme of O2System\Framework\Http\Presenter::setTheme() 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

391
                    presenter()->setTheme(/** @scrutinizer ignore-type */ $theme);
Loading history...
392
                }
393
            }
394
395
            /**
396
             * Sets Page Layout
397
             */
398
            if (presenter()->theme !== false) {
399
                if ($pagePresets->offsetExists('layout')) {
400
                    presenter()->theme->setLayout($pagePresets->layout);
401
                }
402
403
                /**
404
                 * Autoload Theme Assets
405
                 */
406
                presenter()->theme->load();
407
408
                if (false !== ($modulePresets = modules()->top()->getPresets())) {
409
410
                    /**
411
                     * Autoload Module Assets
412
                     */
413
                    if ($modulePresets->offsetExists('assets')) {
414
                        presenter()->assets->autoload($modulePresets->assets);
415
                    }
416
417
                    /**
418
                     * Sets Module Meta
419
                     */
420
                    if ($modulePresets->offsetExists('title')) {
421
                        presenter()->meta->title->append(language()->getLine($modulePresets->title));
422
                    }
423
424
                    if ($modulePresets->offsetExists('pageTitle')) {
425
                        presenter()->meta->title->replace(language()->getLine($modulePresets->pageTitle));
426
                    }
427
428
                    if ($modulePresets->offsetExists('browserTitle')) {
429
                        presenter()->meta->title->replace(language()->getLine($modulePresets->browserTitle));
430
                    }
431
432
                    if ($modulePresets->offsetExists('meta')) {
433
                        foreach ($modulePresets->meta as $name => $content) {
434
                            presenter()->meta->store($name, $content);
435
                        }
436
                    }
437
                }
438
439
                $moduleAssets = [
440
                    'app',
441
                    'module',
442
                    modules()->top()->getParameter(),
443
                ];
444
445
                // Autoload Assets
446
                presenter()->assets->loadCss($moduleAssets);
447
                presenter()->assets->loadJs($moduleAssets);
448
449
                /**
450
                 * Autoload Page Assets
451
                 */
452
                if ($pagePresets->offsetExists('assets')) {
453
                    presenter()->assets->autoload($pagePresets->assets);
454
                }
455
456
                if (presenter()->page->file instanceof \SplFileInfo) {
0 ignored issues
show
introduced by
presenter()->page->file is always a sub-type of SplFileInfo.
Loading history...
457
                    $pageDir = presenter()->page->file->getRealPath();
458
                    $pageDir = str_replace('.' . pathinfo($pageDir, PATHINFO_EXTENSION), '', $pageDir);
459
460
                    $pageDirParts = explode('pages' . DIRECTORY_SEPARATOR,
461
                        str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $pageDir));
462
                    $pageDir = end($pageDirParts);
463
464
                    presenter()->assets->addFilePath(reset($pageDirParts) . 'pages' . DIRECTORY_SEPARATOR);
465
466
                    $pageDir = rtrim($pageDir, DIRECTORY_SEPARATOR);
467
                    $pageDirParts = explode(DIRECTORY_SEPARATOR, $pageDir);
468
469
                    $totalParts = count($pageDirParts);
470
471
                    for ($i = 0; $i < $totalParts; $i++) {
472
                        $pageAssets[] = implode(DIRECTORY_SEPARATOR, array_slice($pageDirParts, 0, ($totalParts - $i)));
473
                    }
474
475
                    $pageAssets[] = implode(DIRECTORY_SEPARATOR, [end($pageAssets), end($pageAssets)]);
476
477
                    // Autoload Assets
478
                    presenter()->assets->loadCss($pageAssets);
479
                    presenter()->assets->loadJs($pageAssets);
480
                }
481
482
                /**
483
                 * Sets Page Meta
484
                 */
485
                if ($pagePresets->offsetExists('title')) {
486
                    presenter()->meta->title->append(language()->getLine($pagePresets->title));
487
                }
488
489
                if ($pagePresets->offsetExists('pageTitle')) {
490
                    presenter()->meta->title->replace(language()->getLine($pagePresets->pageTitle));
491
                }
492
493
                if ($pagePresets->offsetExists('browserTitle')) {
494
                    presenter()->meta->title->replace(language()->getLine($pagePresets->browserTitle));
495
                }
496
497
                if ($pagePresets->offsetExists('meta')) {
498
                    foreach ($pagePresets->meta as $name => $content) {
499
                        presenter()->meta->store($name, $content);
500
                    }
501
                }
502
503
                if (false !== ($layout = presenter()->theme->getLayout())) {
0 ignored issues
show
introduced by
The condition false !== $layout = pres...r()->theme->getLayout() is always true.
Loading history...
504
                    parser()->loadFile($layout->getRealPath());
505
506
                    $htmlOutput = parser()->parse();
507
                    $htmlOutput = presenter()->assets->parseSourceCode($htmlOutput);
508
509
                    $this->document->loadHTML($htmlOutput);
510
                }
511
            } else {
512
                output()->sendError(204, language()->getLine('E_THEME_NOT_FOUND', [$theme]));
513
            }
514
        } elseif (presenter()->theme instanceof Theme) {
515
            /**
516
             * Autoload Theme Assets
517
             */
518
            presenter()->theme->load();
519
520
            if (false !== ($modulePresets = modules()->top()->getPresets())) {
521
522
                /**
523
                 * Autoload Module Assets
524
                 */
525
                if ($modulePresets->offsetExists('assets')) {
526
                    presenter()->assets->autoload($modulePresets->assets);
527
                }
528
529
                /**
530
                 * Sets Module Meta
531
                 */
532
                if ($modulePresets->offsetExists('title')) {
533
                    presenter()->meta->title->append(language()->getLine($modulePresets->title));
534
                }
535
536
                if ($modulePresets->offsetExists('pageTitle')) {
537
                    presenter()->meta->title->replace(language()->getLine($modulePresets->pageTitle));
538
                }
539
540
                if ($modulePresets->offsetExists('browserTitle')) {
541
                    presenter()->meta->title->replace(language()->getLine($modulePresets->browserTitle));
542
                }
543
544
                if ($modulePresets->offsetExists('meta')) {
545
                    foreach ($modulePresets->meta as $name => $content) {
546
                        presenter()->meta->store($name, $content);
547
                    }
548
                }
549
            }
550
551
            $moduleAssets = [
552
                'app',
553
                'module',
554
                modules()->top()->getParameter(),
555
            ];
556
557
            // Autoload Assets
558
            presenter()->assets->loadCss($moduleAssets);
559
            presenter()->assets->loadJs($moduleAssets);
560
561
            /**
562
             * Autoload Controller Assets
563
             */
564
            $controllerFilename = str_replace([modules()->top()->getDir('Controllers'), '.php'], '',
565
                controller()->getFileInfo()->getRealPath());
566
            $controllerFilename = dash($controllerFilename);
567
            $controllerAssets[] = $controllerFilename;
568
            $controllerAssets[] = implode('/', [
569
                $controllerFilename,
570
                controller()->getRequestMethod(),
571
            ]);
572
573
            presenter()->assets->loadCss($controllerAssets);
574
            presenter()->assets->loadJs($controllerAssets);
575
576
            if (false !== ($layout = presenter()->theme->getLayout())) {
577
                parser()->loadFile($layout->getRealPath());
578
579
                $htmlOutput = parser()->parse();
580
                $htmlOutput = presenter()->assets->parseSourceCode($htmlOutput);
581
582
                $this->document->loadHTML($htmlOutput);
583
            }
584
        } elseif (false !== ($theme = presenter()->getConfig('theme'))) {
585
            if (modules()->top()->hasTheme($theme)) {
586
                presenter()->setTheme($theme);
587
588
                /**
589
                 * Autoload Theme Assets
590
                 */
591
                presenter()->theme->load();
592
593
                if (false !== ($modulePresets = modules()->top()->getPresets())) {
594
595
                    /**
596
                     * Autoload Module Assets
597
                     */
598
                    if ($modulePresets->offsetExists('assets')) {
599
                        presenter()->assets->autoload($modulePresets->assets);
600
                    }
601
602
                    /**
603
                     * Sets Module Meta
604
                     */
605
                    if ($modulePresets->offsetExists('title')) {
606
                        presenter()->meta->title->append(language()->getLine($modulePresets->title));
607
                    }
608
609
                    if ($modulePresets->offsetExists('pageTitle')) {
610
                        presenter()->meta->title->replace(language()->getLine($modulePresets->pageTitle));
611
                    }
612
613
                    if ($modulePresets->offsetExists('browserTitle')) {
614
                        presenter()->meta->title->replace(language()->getLine($modulePresets->browserTitle));
615
                    }
616
617
                    if ($modulePresets->offsetExists('meta')) {
618
                        foreach ($modulePresets->meta as $name => $content) {
619
                            presenter()->meta->store($name, $content);
620
                        }
621
                    }
622
                }
623
624
                $moduleAssets = [
625
                    'app',
626
                    'module',
627
                    modules()->top()->getParameter(),
628
                ];
629
630
                // Autoload Assets
631
                presenter()->assets->loadCss($moduleAssets);
632
                presenter()->assets->loadJs($moduleAssets);
633
634
                /**
635
                 * Autoload Controller Assets
636
                 */
637
                $controllerFilename = str_replace([modules()->top()->getDir('Controllers'), '.php'], '',
638
                    controller()->getFileInfo()->getRealPath());
639
                $controllerFilename = dash($controllerFilename);
640
                $controllerAssets[] = $controllerFilename;
641
                $controllerAssets[] = implode('/', [
642
                    $controllerFilename,
643
                    controller()->getRequestMethod(),
644
                ]);
645
646
                if (false !== ($layout = presenter()->theme->getLayout())) {
647
                    parser()->loadFile($layout->getRealPath());
648
649
                    $htmlOutput = parser()->parse();
650
                    $htmlOutput = presenter()->assets->parseSourceCode($htmlOutput);
651
652
                    $this->document->loadHTML($htmlOutput);
653
                }
654
            } else {
655
                output()->sendError(204, language()->getLine('E_THEME_NOT_FOUND', [$theme]));
656
            }
657
        } else {
658
            $this->document->find('body')->append(presenter()->partials->__get('content'));
659
        }
660
661
        /**
662
         * Set Document Meta Title
663
         */
664
        if (presenter()->meta->title instanceof Meta\Title) {
0 ignored issues
show
introduced by
presenter()->meta->title is always a sub-type of O2System\Framework\Http\Presenter\Meta\Title.
Loading history...
665
            $this->document->title->text(presenter()->meta->title->__toString());
666
        }
667
668
        /**
669
         * Injecting Meta Opengraph
670
         */
671
        if (presenter()->meta->opengraph instanceof Meta\Opengraph) {
0 ignored issues
show
introduced by
presenter()->meta->opengraph is always a sub-type of O2System\Framework\Http\Presenter\Meta\Opengraph.
Loading history...
672
            // set opengraph title
673
            if (presenter()->meta->title instanceof Meta\Title) {
0 ignored issues
show
introduced by
presenter()->meta->title is always a sub-type of O2System\Framework\Http\Presenter\Meta\Title.
Loading history...
674
                presenter()->meta->opengraph->setTitle(presenter()->meta->title->__toString());
675
            }
676
677
            // set opengraph site name
678
            if (presenter()->exists('siteName')) {
679
                presenter()->meta->opengraph->setSiteName(presenter()->offsetGet('siteName'));
680
            }
681
682
            if (presenter()->meta->opengraph->count()) {
683
                $htmlElement = $this->document->getElementsByTagName('html')->item(0);
684
                $htmlElement->setAttribute('prefix', 'og: ' . presenter()->meta->opengraph->prefix);
685
686
                if (presenter()->meta->opengraph->exists('og:type') === false) {
687
                    presenter()->meta->opengraph->setType('website');
688
                }
689
690
                $opengraph = presenter()->meta->opengraph->getArrayCopy();
691
692
                foreach ($opengraph as $tag) {
693
                    $this->document->metaNodes->createElement($tag->attributes->getArrayCopy());
694
                }
695
            }
696
        }
697
698
        if (presenter()->meta->count()) {
699
            $meta = presenter()->meta->getArrayCopy();
700
701
            foreach ($meta as $tag) {
702
                $this->document->metaNodes->createElement($tag->attributes->getArrayCopy());
703
            }
704
        }
705
706
        /**
707
         * Inject body attributes
708
         */
709
        $body = $this->document->getElementsByTagName('body');
710
        $body->item(0)->setAttribute('module', modules()->top()->getParameter());
711
712
        /**
713
         * Injecting Single Sign-On (SSO) iFrame
714
         */
715
        if (services()->has('user')) {
716
            $iframe = services()->get('user')->getIframeCode();
717
718
            if ( ! empty($iframe)) {
719
                $this->document->find('body')->append($iframe);
720
            }
721
        }
722
723
        if (input()->env('DEBUG_STAGE') === 'DEVELOPER' and
724
            presenter()->getConfig('debugToolBar') === true and
725
            services()->has('profiler')
726
        ) {
727
            $this->document->find('body')->append((new Toolbar())->__toString());
728
        }
729
730
        /**
731
         * Injecting Progressive Web Application (PWA) Manifest
732
         */
733
        $this->document->linkNodes->createElement([
734
            'rel'  => 'manifest',
735
            'href' => '/manifest.json',
736
        ]);
737
738
        $htmlOutput = $this->document->saveHTML();
739
740
        // Uglify Output
741
        if ($this->config->output[ 'uglify' ] === true) {
742
            $htmlOutput = preg_replace(
743
                [
744
                    '/\>[^\S ]+/s',     // strip whitespaces after tags, except space
745
                    '/[^\S ]+\</s',     // strip whitespaces before tags, except space
746
                    '/(\s)+/s',         // shorten multiple whitespace sequences
747
                    '/<!--(.|\s)*?-->/', // Remove HTML comments
748
                    '/<!--(.*)-->/Uis',
749
                    "/[[:blank:]]+/",
750
                ],
751
                [
752
                    '>',
753
                    '<',
754
                    '\\1',
755
                    '',
756
                    '',
757
                    ' ',
758
                ],
759
                str_replace(["\n", "\r", "\t"], '', $htmlOutput));
760
        }
761
762
        // Beautify Output
763
        if ($this->config->output[ 'beautify' ] === true) {
764
            $beautifier = new Html\Dom\Beautifier();
765
            $htmlOutput = $beautifier->format($htmlOutput);
766
        }
767
768
        if (profiler() !== false) {
769
            profiler()->watch('Ending View Rendering');
770
        }
771
772
        return $htmlOutput;
773
    }
774
}