Test Failed
Push — master ( 5a27da...c8b5ae )
by Alex
02:06
created

HtmlTemplate.php (5 issues)

1
<?php
2
namespace Mezon\HtmlTemplate;
3
4
/**
5
 * Class HtmlTemplate
6
 *
7
 * @package Mezon
8
 * @subpackage HtmlTemplate
9
 * @author Dodonov A.A.
10
 * @version v.1.0 (2019/08/07)
11
 * @copyright Copyright (c) 2019, aeon.org
12
 */
13
14
/**
15
 * Template class
16
 *
17
 * @author Dodonov A.A.
18
 */
19
class HtmlTemplate
20
{
21
22
    /**
23
     * Loaded template content
24
     */
25
    private $template = false;
26
27
    /**
28
     * Loaded resources
29
     */
30
    private $resources = false;
31
32
    /**
33
     * Path to the template folder
34
     *
35
     * @var array
36
     */
37
    private $paths = false;
38
39
    /**
40
     * Page blocks
41
     *
42
     * @var array
43
     */
44
    private $blocks = [];
45
46
    /**
47
     * Page variables
48
     *
49
     * @var array
50
     */
51
    private $pageVars = [];
52
53
    /**
54
     * Template сonstructor
55
     *
56
     * @param string|array $path
57
     *            Path to template
58
     * @param string $template
59
     *            Page layout
60
     * @param array $blocks
61
     *            Page blocks
62
     */
63
    public function __construct($path, string $template = 'index', array $blocks = [])
64
    {
65
        if (is_string($path)) {
66
            $this->paths = [
67
                $path
68
            ];
69
        } elseif (is_array($path)) {
0 ignored issues
show
The condition is_array($path) is always true.
Loading history...
70
            $this->paths = $path;
71
        } else {
72
            throw (new \Exception('Invalid type for $path parameter'));
73
        }
74
75
        $this->resetLayout($template);
76
77
        $this->resources = new \Mezon\HtmlTemplate\TemplateResources();
78
79
        $this->blocks = [];
80
81
        foreach ($blocks as $blockName) {
82
            $this->addBlock($blockName);
83
        }
84
85
        // output all blocks in one place
86
        // but each block can be inserted in {$blockName} places
87
        $this->setPageVar('content-blocks', implode('', $this->blocks));
88
    }
89
90
    /**
91
     * Method adds paths to the setup ones
92
     *
93
     * @param array $paths
94
     *            paths to directories with the template's static content
95
     */
96
    public function addPaths(array $paths): void
97
    {
98
        $this->paths = array_merge($paths, $this->paths);
99
    }
100
101
    /**
102
     * Resetting paths
103
     *
104
     * @param array $paths
105
     */
106
    public function setPaths(array $paths): void
107
    {
108
        $this->paths = $paths;
109
    }
110
111
    /**
112
     * Method returns all setup puths of the template
113
     *
114
     * @return array
115
     */
116
    public function getPaths(): array
117
    {
118
        return $this->paths;
119
    }
120
121
    /**
122
     * Setting page variables
123
     *
124
     * @param string $var
125
     *            Variable name
126
     * @param mixed $value
127
     *            Variable value
128
     */
129
    public function setPageVar(string $var, $value): void
130
    {
131
        $this->pageVars[$var] = $value;
132
    }
133
134
    /**
135
     * Method sets multiple variables
136
     *
137
     * @param array $vars
138
     */
139
    public function setPageVars(array $vars): void
140
    {
141
        foreach ($vars as $var => $value) {
142
            $this->setPageVar($var, $value);
143
        }
144
    }
145
146
    /**
147
     * Getting page var
148
     *
149
     * @param string $var
150
     *            variable name
151
     * @return mixed variable value, or exception if the variable was not found
152
     */
153
    public function getPageVar(string $var)
154
    {
155
        if (isset($this->pageVars[$var]) === false) {
156
            throw (new \Exception('Template variable ' . $var . ' was not set'));
157
        }
158
159
        return $this->pageVars[$var];
160
    }
161
162
    /**
163
     * Setting page variables from file's content
164
     *
165
     * @param string $var
166
     *            Variable name
167
     * @param mixed $path
168
     *            Path to file
169
     */
170
    public function setPageVarFromFile(string $var, string $path): void
171
    {
172
        $this->setPageVar($var, file_get_contents($path));
173
    }
174
175
    /**
176
     * Compiling the page with it's variables
177
     *
178
     * @param string $content
179
     *            Compiling content
180
     */
181
    public function compilePageVars(string &$content): void
182
    {
183
        foreach ($this->pageVars as $key => $value) {
184
            if (is_array($value) === false && is_object($value) === false) {
185
                // only scalars can be substituted in this way
186
                $content = str_replace('{' . $key . '}', $value, $content);
0 ignored issues
show
$value of type object is incompatible with the type string|string[] expected by parameter $replace of str_replace(). ( Ignorable by Annotation )

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

186
                $content = str_replace('{' . $key . '}', /** @scrutinizer ignore-type */ $value, $content);
Loading history...
187
            }
188
        }
189
190
        $content = \Mezon\TemplateEngine\TemplateEngine::unwrapBlocks($content, $this->pageVars);
191
192
        $content = \Mezon\TemplateEngine\TemplateEngine::compileSwitch($content);
193
    }
194
195
    /**
196
     * Checking if the file exists
197
     *
198
     * @param string $fileSubPath
199
     *            file sub path
200
     * @return bool true if the file exists, false otherwise
201
     */
202
    protected function fileExists(string $fileSubPath): bool
203
    {
204
        foreach ($this->paths as $path) {
205
            if (file_exists(trim($path, '/\\') . '/' . trim($fileSubPath, '/\\'))) {
206
                return true;
207
            }
208
        }
209
210
        return false;
211
    }
212
213
    /**
214
     * Getting content of the file
215
     *
216
     * @param string $fileSubPath
217
     *            file sub path
218
     * @return string file content
219
     */
220
    protected function fileGetContents(string $fileSubPath): string
221
    {
222
        foreach ($this->paths as $path) {
223
            $finalPath = rtrim($path, '/\\') . '/' . trim($fileSubPath, '/\\');
224
            if (file_exists($finalPath)) {
225
                return file_get_contents($finalPath);
226
            }
227
        }
228
        // @codeCoverageIgnoreStart
229
        return '';
230
    }
231
232
    // @codeCoverageIgnoreEnd
233
234
    /**
235
     * Method resets layout
236
     *
237
     * @param string $template
238
     *            Template name
239
     */
240
    public function resetLayout(string $template): void
241
    {
242
        $template .= '.html';
243
244
        if ($this->fileExists($template)) {
245
            $this->template = $this->fileGetContents($template);
246
        } elseif ($this->fileExists('res/templates/' . $template)) {
247
            $this->template = $this->fileGetContents('res/templates/' . $template);
248
        } else {
249
            throw (new \Exception(
250
                'Template file ' . $template . ' on the paths ' . implode(', ', $this->paths) . ' was not found',
251
                - 1));
252
        }
253
    }
254
255
    /**
256
     * Method returns compiled page resources
257
     *
258
     * @return string Compiled resources includers
259
     */
260
    private function _getResources(): string
261
    {
262
        $content = '';
263
264
        $cSSFiles = $this->resources->getCssFiles();
265
        foreach ($cSSFiles as $cSSFile) {
0 ignored issues
show
The expression $cSSFiles of type boolean is not traversable.
Loading history...
266
            $content .= '
267
        <link href="' . $cSSFile . '" rel="stylesheet" type="text/css">';
268
        }
269
270
        $jSFiles = $this->resources->getJsFiles();
271
        foreach ($jSFiles as $jSFile) {
0 ignored issues
show
The expression $jSFiles of type boolean is not traversable.
Loading history...
272
            $content .= '
273
        <script src="' . $jSFile . '"></script>';
274
        }
275
276
        return $content;
277
    }
278
279
    /**
280
     * Compile template
281
     *
282
     * @return string Compiled template
283
     */
284
    public function compile(): string
285
    {
286
        $this->setPageVar('resources', $this->_getResources());
287
        $this->setPageVar('mezon-http-path', \Mezon\Conf\Conf::getConfigValue('@mezon-http-path'));
288
        $this->setPageVar('service-http-path', \Mezon\Conf\Conf::getConfigValue('@service-http-path'));
289
        if (isset($_SERVER['HTTP_HOST'])) {
290
            $this->setPageVar('host', $_SERVER['HTTP_HOST']);
291
        }
292
293
        foreach ($this->blocks as $blockName => $block) {
294
            $this->setPageVar($blockName, $block);
295
        }
296
297
        $this->compilePageVars($this->template);
0 ignored issues
show
$this->template of type boolean is incompatible with the type string expected by parameter $content of Mezon\HtmlTemplate\HtmlTemplate::compilePageVars(). ( Ignorable by Annotation )

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

297
        $this->compilePageVars(/** @scrutinizer ignore-type */ $this->template);
Loading history...
298
299
        $this->template = preg_replace('/\{[a-zA-z0-9\-]*\}/', '', $this->template);
300
301
        return $this->template;
302
    }
303
304
    /**
305
     * Method returns block's content
306
     *
307
     * @param string $blockName
308
     * @return string block's content
309
     */
310
    protected function readBlock(string $blockName): string
311
    {
312
        if ($this->fileExists('res/blocks/' . $blockName . '.tpl')) {
313
            $blockContent = $this->fileGetContents('res/blocks/' . $blockName . '.tpl');
314
        } elseif ($this->fileExists('blocks/' . $blockName . '.tpl')) {
315
            $blockContent = $this->fileGetContents('blocks/' . $blockName . '.tpl');
316
        } else {
317
            throw (new \Exception('Block ' . $blockName . ' was not found', - 1));
318
        }
319
320
        return $blockContent;
321
    }
322
323
    /**
324
     * Method adds block to page
325
     *
326
     * @param string $blockName
327
     *            Name of the additing block
328
     */
329
    public function addBlock(string $blockName): void
330
    {
331
        $this->blocks[$blockName] = $this->readBlock($blockName);
332
    }
333
334
    /**
335
     * Method returns block's content
336
     *
337
     * @param string $blockName
338
     * @return string block's content
339
     */
340
    public function getBlock(string $blockName): string
341
    {
342
        return $this->readBlock($blockName);
343
    }
344
}
345