Test Failed
Push — master ( 860d57...e36708 )
by Alex
02:09
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
            print('Check'.trim($path, '/\\') . '/' . trim($fileSubPath, '/\\')."\r\n");
206
            if (file_exists(trim($path, '/\\') . '/' . trim($fileSubPath, '/\\'))) {
207
                return true;
208
            }
209
        }
210
211
        return false;
212
    }
213
214
    /**
215
     * Getting content of the file
216
     *
217
     * @param string $fileSubPath
218
     *            file sub path
219
     * @return string file content
220
     */
221
    protected function fileGetContents(string $fileSubPath): string
222
    {
223
        foreach ($this->paths as $path) {
224
            $finalPath = trim($path, '/\\') . '/' . trim($fileSubPath, '/\\');
225
            if (file_exists($finalPath)) {
226
                return file_get_contents($finalPath);
227
            }
228
        }
229
// @codeCoverageIgnoreStart
230
        return '';
231
    }// @codeCoverageIgnoreEnd
232
233
    /**
234
     * Method resets layout
235
     *
236
     * @param string $template
237
     *            Template name
238
     */
239
    public function resetLayout(string $template): void
240
    {
241
        $template .= '.html';
242
243
        if ($this->fileExists($template)) {
244
            $this->template = $this->fileGetContents($template);
245
        } elseif ($this->fileExists('res/templates/' . $template)) {
246
            $this->template = $this->fileGetContents('res/templates/' . $template);
247
        } else {
248
            throw (new \Exception(
249
                'Template file ' . $template . ' on the paths ' . implode(', ', $this->paths) . ' was not found',
250
                - 1));
251
        }
252
    }
253
254
    /**
255
     * Method returns compiled page resources
256
     *
257
     * @return string Compiled resources includers
258
     */
259
    private function _getResources(): string
260
    {
261
        $content = '';
262
263
        $cSSFiles = $this->resources->getCssFiles();
264
        foreach ($cSSFiles as $cSSFile) {
0 ignored issues
show
The expression $cSSFiles of type boolean is not traversable.
Loading history...
265
            $content .= '
266
        <link href="' . $cSSFile . '" rel="stylesheet" type="text/css">';
267
        }
268
269
        $jSFiles = $this->resources->getJsFiles();
270
        foreach ($jSFiles as $jSFile) {
0 ignored issues
show
The expression $jSFiles of type boolean is not traversable.
Loading history...
271
            $content .= '
272
        <script src="' . $jSFile . '"></script>';
273
        }
274
275
        return $content;
276
    }
277
278
    /**
279
     * Compile template
280
     *
281
     * @return string Compiled template
282
     */
283
    public function compile(): string
284
    {
285
        $this->setPageVar('resources', $this->_getResources());
286
        $this->setPageVar('mezon-http-path', \Mezon\Conf\Conf::getConfigValue('@mezon-http-path'));
287
        $this->setPageVar('service-http-path', \Mezon\Conf\Conf::getConfigValue('@service-http-path'));
288
        if (isset($_SERVER['HTTP_HOST'])) {
289
            $this->setPageVar('host', $_SERVER['HTTP_HOST']);
290
        }
291
292
        foreach ($this->blocks as $blockName => $block) {
293
            $this->setPageVar($blockName, $block);
294
        }
295
296
        $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

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