HtmlTemplate::setPageVarFromFile()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

203
                    $content = str_replace('{' . $key . '}', /** @scrutinizer ignore-type */ $value, $content);
Loading history...
204
                }
205
            }
206
207
            // trying to substitute recursive
208
            $matches = [];
209
            preg_match('/\{[a-zA-Z0-9\-]{1,1000}\}/m', $content, $matches);
210
            if ($prevVarsHash !== md5(implode('', $matches))) {
211
                $prevVarsHash = md5(implode('', $matches));
212
            } else {
213
                break;
214
            }
215
        } while (true);
216
217
        $content = TemplateEngine::unwrapBlocks($content, $this->pageVars);
218
219
        $content = TemplateEngine::compileSwitch($content);
220
    }
221
222
    /**
223
     * Checking if the file exists
224
     *
225
     * @param string $fileSubPath
226
     *            file sub path
227
     * @return bool true if the file exists, false otherwise
228
     */
229
    public function fileExists(string $fileSubPath): bool
230
    {
231
        foreach ($this->paths as $path) {
232
            if (file_exists(rtrim($path, '/\\') . '/' . trim($fileSubPath, '/\\'))) {
233
                return true;
234
            }
235
        }
236
237
        return false;
238
    }
239
240
    /**
241
     * Getting content of the file
242
     *
243
     * @param string $fileSubPath
244
     *            file sub path
245
     * @return string file content
246
     */
247
    protected function fileGetContents(string $fileSubPath): string
248
    {
249
        foreach ($this->paths as $path) {
250
            $finalPath = rtrim($path, '/\\') . '/' . trim($fileSubPath, '/\\');
251
            if (file_exists($finalPath)) {
252
                return file_get_contents($finalPath);
253
            }
254
        }
255
        // @codeCoverageIgnoreStart
256
        return '';
257
    }
258
259
    // @codeCoverageIgnoreEnd
260
261
    /**
262
     * Method resets layout
263
     *
264
     * @param string $template
265
     *            Template name
266
     */
267
    public function resetLayout(string $template): void
268
    {
269
        $template .= '.html';
270
271
        if ($this->fileExists($template)) {
272
            $this->template = $this->fileGetContents($template);
273
        } elseif ($this->fileExists('Res/Templates/' . $template)) {
274
            $this->template = $this->fileGetContents('Res/Templates/' . $template);
275
        } else {
276
            throw (new \Exception(
277
                'Template file ' . $template . ' on the paths [' . implode(', ', $this->paths) . '] was not found',
278
                - 1));
279
        }
280
    }
281
282
    /**
283
     * Compile template
284
     *
285
     * @return string Compiled template
286
     */
287
    public function compile(): string
288
    {
289
        $this->setPageVar('resources', $this->resources === null ? '' : $this->resources->compileResources());
290
        $this->setPageVar('mezon-http-path', Conf::getConfigValue('@mezon-http-path'));
291
        $this->setPageVar('service-http-path', Conf::getConfigValue('@service-http-path'));
292
        if (isset($_SERVER['HTTP_HOST'])) {
293
            $this->setPageVar('host', $_SERVER['HTTP_HOST']);
294
        }
295
296
        foreach ($this->blocks as $blockName => $block) {
297
            $this->setPageVar($blockName, $block);
298
        }
299
300
        $this->compilePageVars($this->template);
0 ignored issues
show
Bug introduced by
$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

300
        $this->compilePageVars(/** @scrutinizer ignore-type */ $this->template);
Loading history...
301
302
        $this->template = preg_replace('/\{[a-zA-z0-9\-]*\}/', '', $this->template);
303
304
        return $this->template;
305
    }
306
307
    /**
308
     * Does block exist
309
     *
310
     * @param string $blockName
311
     *            block name
312
     * @return bool does block exist?
313
     */
314
    public function blockExists(string $blockName): bool
315
    {
316
        if ($this->fileExists('Res/Blocks/' . $blockName . '.tpl')) {
317
            return true;
318
        } elseif ($this->fileExists('Blocks/' . $blockName . '.tpl')) {
319
            return true;
320
        } else {
321
            return false;
322
        }
323
    }
324
325
    /**
326
     * Method returns block's content
327
     *
328
     * @param string $blockName
329
     * @return string block's content
330
     */
331
    protected function readBlock(string $blockName): string
332
    {
333
        if ($this->fileExists('Res/Blocks/' . $blockName . '.tpl')) {
334
            $blockContent = $this->fileGetContents('Res/Blocks/' . $blockName . '.tpl');
335
        } elseif ($this->fileExists('Blocks/' . $blockName . '.tpl')) {
336
            $blockContent = $this->fileGetContents('Blocks/' . $blockName . '.tpl');
337
        } else {
338
            throw (new \Exception('Block ' . $blockName . ' was not found', - 1));
339
        }
340
341
        return $blockContent;
342
    }
343
344
    /**
345
     * Method adds block to page
346
     *
347
     * @param string $blockName
348
     *            Name of the additing block
349
     */
350
    public function addBlock(string $blockName): void
351
    {
352
        $this->blocks[$blockName] = $this->readBlock($blockName);
353
    }
354
355
    /**
356
     * Method returns block's content
357
     *
358
     * @param string $blockName
359
     * @return string block's content
360
     */
361
    public function getBlock(string $blockName): string
362
    {
363
        return $this->readBlock($blockName);
364
    }
365
366
    /**
367
     * Method returns file data
368
     *
369
     * @param string $filePath
370
     *            path to file
371
     * @return string file content
372
     */
373
    public function getFile(string $filePath): string
374
    {
375
        foreach ($this->paths as $path) {
376
            $fullPath = rtrim($path, '\\/') . '/' . ltrim($filePath, '\\/');
377
378
            if (file_exists($fullPath)) {
379
                return file_get_contents($fullPath);
380
            }
381
        }
382
383
        throw (new \Exception('File "' . $filePath . '" was not found in paths : ' . implode($this->paths)));
384
    }
385
386
    /**
387
     * Method sets template resources
388
     *
389
     * @param TemplateResources $resources
390
     *            resources
391
     */
392
    public function setResources(TemplateResources $resources): void
393
    {
394
        $this->resources = $resources;
395
    }
396
}
397