1 <?php
2
3 4 5 6 7 8 9 10 11 12
13
14 namespace Slimore\Mvc;
15
16 17 18 19 20 21
22
23 class View extends \Slim\View
24 {
25 26 27
28 public $compileFileSuffix = '.php';
29
30 31 32
33 public $compileFileNameMd5 = true;
34
35 36 37
38 public $compileDirectoryName = '.compiles';
39
40 41 42
43 public $cacheDirectoryName = '.caches';
44
45 46 47
48 protected $templateName;
49
50 51 52
53 protected $templateFile;
54
55 56 57
58 protected $compilePath;
59
60 61 62
63 public $compileCached = true;
64
65 66 67
68 protected $templateCompileFile;
69
70 71 72 73 74
75 protected static $globals = [];
76
77 78 79
80 protected static $properties = [];
81
82 83 84 85 86
87
88 public function setCompileDirectory()
89 {
90 $compilePath = $this->getTemplatesDirectory() . DIRECTORY_SEPARATOR . $this->compileDirectoryName . DIRECTORY_SEPARATOR;
91
92 if (!file_exists($compilePath))
93 {
94 static::mkdir($compilePath);
95 }
96
97 $this->compilePath = $compilePath;
98 }
99
100 101 102 103 104 105
106
107 public function setCompileFile($filename)
108 {
109 $filename = (($this->compileFileNameMd5) ? md5(md5($filename)) : $filename);
110 $this->templateCompileFile = $this->compilePath . $filename . $this->compileFileSuffix;
111 }
112
113 public static function getProperties(array $array)
114 {
115 return static::$properties = $array;
116 }
117
118 119 120 121 122 123 124
125
126 public function render($template, $data = null)
127 {
128 $this->templateName = $template;
129 $this->templateFile = $this->getTemplatePathname($template);
130
131 if (!is_file($this->templateFile))
132 {
133 throw new \RuntimeException("Slimore\\Mvc\\View cannot render `$template` because the template does not exist");
134 }
135
136 $this->setCompileDirectory();
137 $this->setCompileFile($template);
138
139 ob_start();
140
141 $data = array_merge($this->data->all(), (array) $data);
142 $data = array_merge(static::$globals, $data);
143
144 static::getProperties([
145 'data' => $data,
146 'compileCached' => $this->compileCached,
147 'templatePath' => $this->getTemplatesDirectory() . DIRECTORY_SEPARATOR,
148 'compilePath' => $this->compilePath,
149 'compileFileNameMd5' => $this->compileFileNameMd5,
150 'compileFileSuffix' => $this->compileFileSuffix
151 ]);
152
153 extract($data);
154
155
156
157 if (!$this->compileCached)
158 {
159 $tpl = $this->read($this->templateFile);
160 $tpl = static::parser($tpl);
161 $this->write($this->templateCompileFile, $tpl);
162 }
163 else
164 {
165 if (!file_exists($this->templateCompileFile) ||
166 (filemtime($this->templateFile) > filemtime($this->templateCompileFile))
167 ) {
168 $tpl = $this->read($this->templateFile);
169 $tpl = static::parser($tpl);
170 $this->write($this->templateCompileFile, $tpl);
171 }
172 }
173
174 require $this->templateCompileFile;
175
176 echo ob_get_clean();
177 }
178
179 180 181 182 183 184
185
186 public static function mkdir($dir)
187 {
188 if ( file_exists($dir) )
189 {
190 return $dir;
191 }
192
193 mkdir($dir, 0777, true);
194 chmod($dir, 0777);
195
196 return $dir;
197 }
198
199 200 201 202 203 204
205
206 protected function read($filename)
207 {
208 return file_get_contents($filename);
209 }
210
211 212 213 214 215 216
217
218 protected function write($filename, $content)
219 {
220 file_put_contents($filename, $content);
221 }
222
223 224 225 226 227 228
229
230 public static function includeFile($file)
231 {
232 $data = static::$properties['data'];
233 $templatePath = static::$properties['templatePath'];
234 $compilePath = static::$properties['compilePath'];
235 $compileCached = static::$properties['compileCached'];
236 $compileFileNameMd5 = static::$properties['compileFileNameMd5'];
237 $compileFileSuffix = static::$properties['compileFileSuffix'];
238 $templateFile = $templatePath . $file;
239
240 if ( !file_exists($templateFile) )
241 {
242 throw new \InvalidArgumentException('included template file ' . $file . ' not found.');
243 }
244
245 $pathInfo = pathinfo($file);
246 $filename = $pathInfo['filename'];
247
248 if (!$compileFileNameMd5 && !file_exists($compilePath . $pathInfo['dirname']))
249 {
250 static::mkdir($compilePath . $pathInfo['dirname']);
251 }
252
253 $filenameMd5 = (($compileFileNameMd5) ? md5(md5($filename)) : $pathInfo['dirname'] . DIRECTORY_SEPARATOR . $filename);
254 $compileFile = $compilePath . $filenameMd5 . $compileFileSuffix;
255
256 if ($compileCached)
257 {
258 if (!file_exists($compileFile) || (filemtime($templateFile) > filemtime($compileFile)))
259 {
260 $tpl = file_get_contents($templateFile);
261 $tpl = static::parser($tpl);
262 file_put_contents($compileFile, $tpl);
263 }
264 }
265 else
266 {
267 $tpl = file_get_contents($templateFile);
268 $tpl = static::parser($tpl);
269 file_put_contents($compileFile, $tpl);
270 }
271
272 return $compileFile;
273 }
274
275 276 277 278 279 280
281
282 public static function parser($tpl)
283 {
284 $viewClass = '\Slimore\Mvc\View::';
285
286
287 $tpl = preg_replace_callback('/\<\!\-\-\s*\{for\s+(\S+)\s+in\s+(\S+)\}\s*\-\-\>/is', function($matchs) {
288
289 $output = '<?php if (isset(' . $matchs[2] . ') && is_array(' . $matchs[2] . ')) { ?>';
290 $output .= "\r";
291 $output .= '<?php foreach (' . $matchs[2] . ' as $key => ' . $matchs[1] . ') { ?>';
292 $output .= "\r";
293
294 return $output;
295 }, $tpl);
296
297
298 $tpl = preg_replace_callback('/\<\!\-\-\s*\{foreach\s+(\S+)\s+(\S+)\s+(\S+)\}\s*\-\-\>/is', function($matchs) {
299 print_r($matchs);
300 $output = '<?php if (isset(' . $matchs[1] . ') && is_array(' . $matchs[1] . ')) { ?>';
301 $output .= "\r";
302 $output .= '<?php foreach (' . $matchs[1] . ' as ' . $matchs[2] . ' => ' . $matchs[3] . ') { ?>';
303 $output .= "\r";
304
305 return $output;
306 }, $tpl);
307
308 $regexs = [
309 '/\<\!\-\-\s*\{if\s+(\S+)\}\s*\-\-\>/is',
310 '/\<\!\-\-\s*\{elseif\s+(\S+)\}\s*\-\-\>/is',
311 '/\<\!\-\-\s*\{else}\s*\-\-\>/is',
312 '/\<\!\-\-\s*\{\/if}\s*\-\-\>/is',
313 '/\<\!\-\-\s*\{\/for}\s*\-\-\>/is',
314 '/\<\!\-\-\s*\{\/foreach}\s*\-\-\>/is',
315 '/\<\!\-\-\s*\{(.+?)\}\s*\-\-\>/is',
316 '/\{include\s+(.+?)\}/is',
317 '/\{([A-Z][A-Z0-9_]*)\}/s',
318 '/\{(\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\}/is'
319 ];
320
321 $replacements = [
322 '<?php if (\\1) { ?>',
323 '<?php } elseif (\\1) { ?>',
324 '<?php } else { ?>',
325 '<?php } ?>',
326 '<?php } } ?>',
327 '<?php } } ?>',
328 '{\\1}',
329 '<?php include ' . $viewClass . 'includeFile(\\1); ?>',
330 '<?php if ( defined(\'\\1\') ) { echo \\1; } ?>',
331 '<?php if ( isset(\\1) && !is_array(\\1)) { echo \\1; } ?>'
332 ];
333
334 $tpl = preg_replace($regexs, $replacements, $tpl);
335
336
337 $tpl = preg_replace('/\{(([@&\\\$a-zA-Z0-9_]+)\(([^\}]*)\))?\}/is', '<?php echo \\1; ?>', $tpl);
338
339
340 $tpl = preg_replace_callback('/\{(([^\}]*)\s+\?\s+([^\}]*)\s+:\s+([^\}]*))?\}/is', function($matchs) {
341
342 $output = '<?php echo ' . $matchs[1] . '; ?>';
343
344 return str_replace(';; ?>', '; ?>', $output);
345 }, $tpl);
346
347
348 $tpl = preg_replace_callback('/\{(([\$\\\w+]+)([:-\>]*)([^\}]*))?\}/is', function($matchs) {
349
350 $output = '<?php echo ' . $matchs[1] . '; ?>';
351
352 return str_replace(';; ?>', '; ?>', $output);
353 }, $tpl);
354
355
356 $tpl = preg_replace('/\{(\/\/([^\}]*))?\}/is', '<?php \\1; ?>', $tpl);
357
358 return $tpl;
359 }
360
361 362 363 364 365 366
367
368 public static function addGlobals(array $array)
369 {
370 static::$globals = array_merge($array, static::$globals);
371 }
372 }