Passed
Push — master ( 48e2e4...58f05f )
by Marwan
08:52
created

Compiler::parse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
c 1
b 0
f 0
dl 0
loc 23
ccs 14
cts 14
cp 1
crap 3
rs 9.8333
eloc 13
nc 3
nop 1
1
<?php
2
3
/**
4
 * @author Marwan Al-Soltany <[email protected]>
5
 * @copyright Marwan Al-Soltany 2021
6
 * For the full copyright and license information, please view
7
 * the LICENSE file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace MAKS\Velox\Frontend\View;
13
14
use MAKS\Velox\Backend\Config;
15
use MAKS\Velox\Frontend\Path;
16
use MAKS\Velox\Frontend\View\Engine;
17
18
/**
19
 * A class that offers some utility functions to require, parse, and compile view files.
20
 *
21
 * @package Velox\Frontend\View
22
 * @since 1.5.4
23
 */
24
class Compiler
25
{
26
    /**
27
     * Compiles a PHP file with the passed variables.
28
     *
29
     * @param string $file An absolute path to the file that should be compiled.
30
     * @param string $type The type of the file (just a name to make for friendly exceptions).
31
     * @param array|null [optional] An associative array of the variables to pass.
32
     *
33
     * @return string
34
     *
35
     * @throws \Exception If failed to compile the file.
36
     */
37 10
    public static function compile(string $file, string $type, ?array $variables = null): string
38
    {
39 10
        ob_start();
40
41
        try {
42 10
            self::require($file, $variables);
43 4
        } catch (\Exception $error) {
44
            // clean started buffer before throwing the exception
45 4
            ob_end_clean();
46
47 4
            throw $error;
48
        }
49
50 9
        $buffer = ob_get_contents();
51 9
        ob_end_clean();
52
53 9
        if ($buffer === false) {
54
            $name = basename($file, Config::get('view.fileExtension'));
0 ignored issues
show
Bug introduced by
It seems like MAKS\Velox\Backend\Confi...t('view.fileExtension') can also be of type null; however, parameter $suffix of basename() 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

54
            $name = basename($file, /** @scrutinizer ignore-type */ Config::get('view.fileExtension'));
Loading history...
55
            throw new \Exception("Something went wrong when trying to compile the {$type} with the name '{$name}' in {$file}");
56
        }
57
58 9
        return trim($buffer);
59
    }
60
61
    /**
62
     * Requires a PHP file and pass it the passed variables.
63
     *
64
     * @param string $file An absolute path to the file that should be compiled.
65
     * @param array|null $variables [optional] An associative array of the variables to pass.
66
     *
67
     * @return void
68
     *
69
     * @throws \Exception If the file could not be loaded.
70
     */
71 11
    public static function require(string $file, ?array $variables = null): void
72
    {
73 11
        $file = self::resolve($file);
74
75 11
        if (!file_exists($file)) {
76 5
            throw new \Exception(
77 5
                "Could not load the file with the path '{$file}' nor fall back to a parent. Check if the file exists"
78
            );
79
        }
80
81 10
        $_file = static::parse($file);
82
83 10
        unset($file);
84
85 10
        if ($variables !== null) {
86 9
            extract($variables, EXTR_OVERWRITE);
87 9
            unset($variables);
88
        }
89
90 10
        require($_file);
91
92 10
        unset($_file);
93 10
    }
94
95
    /**
96
     * Parses a file through the templating engine and returns a path to the compiled file.
97
     *
98
     * @param string $file The file to parse.
99
     *
100
     * @return string
101
     */
102 10
    public static function parse(string $file): string
103
    {
104 10
        if (!Config::get('view.engine.enabled', true)) {
105 1
            return $file;
106
        }
107
108 9
        static $engine = null;
109
110 9
        if ($engine === null) {
111 1
            $engine = new Engine(
112 1
                (string)Config::get('global.paths.themes') . '/',
113 1
                (string)Config::get('view.fileExtension', '.phtml'),
114 1
                (string)Config::get('global.paths.storage') . '/temp/views/',
115 1
                (bool)Config::get('view.engine.cache', true),
116 1
                (bool)Config::get('view.engine.debug', false)
117
            );
118
        }
119
120 9
        $file = $engine->getCompiledFile(strtr($file, [
121 9
            Path::normalize(Config::get('global.paths.themes'), '') => ''
0 ignored issues
show
Bug introduced by
It seems like MAKS\Velox\Backend\Confi...('global.paths.themes') can also be of type null; however, parameter $directory of MAKS\Velox\Frontend\Path::normalize() 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

121
            Path::normalize(/** @scrutinizer ignore-type */ Config::get('global.paths.themes'), '') => ''
Loading history...
122
        ]));
123
124 9
        return $file;
125
    }
126
127
    /**
128
     * Resolves a file from the active theme or inherits it from a parent theme.
129
     *
130
     * @param string $file
131
     *
132
     * @return string
133
     */
134 11
    public static function resolve(string $file): string
135
    {
136 11
        if (file_exists($file)) {
137 4
            return $file;
138
        }
139
140 8
        if (Config::get('view.inherit')) {
141 8
            $active = Config::get('theme.active');
142 8
            $parent = Config::get('theme.parent');
143 8
            $themes = Config::get('global.paths.themes');
144 8
            $nameWrapper = basename($themes) . DIRECTORY_SEPARATOR . '%s';
0 ignored issues
show
Bug introduced by
It seems like $themes can also be of type null; however, parameter $path of basename() 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

144
            $nameWrapper = basename(/** @scrutinizer ignore-type */ $themes) . DIRECTORY_SEPARATOR . '%s';
Loading history...
145
146 8
            foreach ((array)$parent as $substitute) {
147 8
                $fallbackFile = strtr($file, [
148 8
                    sprintf($nameWrapper, $active) => sprintf($nameWrapper, $substitute)
149
                ]);
150
151 8
                if (file_exists($fallbackFile)) {
152 7
                    $file = $fallbackFile;
153 7
                    break;
154
                }
155
            }
156
        }
157
158 8
        return $file;
159
    }
160
}
161