Overview

Packages

  • Onion::Controllers
  • Onion::Core
  • Onion::UI
  • Onion::Utils

Classes

  • Form
  • Grid
  • Html
  • IconsGrid
  • Paginator
  • Template
  • Widget
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * Onion Framework - Spracovanie šablón
  5:  *
  6:  * Copyright (c) 2011 Jano Gašpar (http://webstranky.net)
  7:  *
  8:  * @author    Jano Gašpar
  9:  * @copyright Copyright (c) 2011 Jano Gašpar
 10:  * @package   Onion::UI
 11:  *
 12:  *
 13:  * {include file}, {include #block}
 14:  * {block name}
 15:  * {$variable}, {!$variable}, {$variable['key']}
 16:  * {if $abc === TRUE}{elseif $def === NULL}{else}
 17:  * {loop $array}{else}{/loop}
 18:  * {$variable|filter1:argument1,argument2|filter2:argument1,argument2}
 19:  *
 20:  */
 21: 
 22: class Template
 23: {
 24:     /**
 25:      * @var array úložisko dát pre spracovanie v šablóne
 26:      */
 27:     protected $data;
 28: 
 29: 
 30:     /**
 31:      * @var string adresár kde je uložená aktuálna šablóna
 32:      */
 33:     protected $templates_dir;
 34: 
 35: 
 36:     /**
 37:      * @var string súborova prípona aktuálnej šablóny
 38:      */
 39:     protected $extension;
 40: 
 41: 
 42:     /**
 43:      * @var string cesta k súboru šablóny
 44:      */
 45:     protected $template;
 46: 
 47: 
 48:     /**
 49:      * @var array úložisko blokov, asociatívne pole názov => obsah bloku
 50:      */
 51:     protected $blocks = array();
 52: 
 53: 
 54:     /**
 55:      * @var array úložisko užívateľských makier, asociatívne pole názov => kód (text, php kód, funkcia(pole))
 56:      */
 57:     protected $macros = array();
 58: 
 59: 
 60:     /**
 61:      * @var array úložisko užívateľských filtrov
 62:      */
 63:     protected $filters = array();
 64: 
 65: 
 66:     /**
 67:      * Konštruktor
 68:      *
 69:      * @param  string cesta k súboru šablóny
 70:      * @return object
 71:      */
 72:     function __construct($template)
 73:     {
 74:         $this->data = array();
 75: 
 76:         return $this->set_template($template);
 77:     }
 78: 
 79: 
 80:     /**
 81:      * Nastavenie súboru k šablóne, ak súbor neexistuje použije sa @default
 82:      *
 83:      * @param  string cesta k súboru šablóny
 84:      * @return object
 85:      */
 86:     public function set_template($template)
 87:     {
 88:         $this->template = $template;
 89: 
 90:         $path_parts = pathinfo($template);
 91:         $this->templates_dir = $path_parts['dirname'];
 92:         $this->extension = $path_parts['extension'];
 93: 
 94:         if (file_exists($template) === FALSE) {
 95:             $this->template = $this->templates_dir . '/Default.' . $this->extension;
 96:         }
 97: 
 98:         return $this;
 99:     }
100: 
101: 
102:     /**
103:      * Vymazanie úložiska dát
104:      *
105:      * @return object
106:      */
107:     public function reset_data()
108:     {
109:         $this->data = array();
110: 
111:         return $this;
112:     }
113: 
114: 
115:     /**
116:      * Vloženie dát do úložiska dát
117:      *
118:      * @param  string|array názov premennej, alebo asociatívne pole s dátami
119:      * @param  string|array hodnota premennej
120:      * @return object
121:      */
122:     public function set_data($variable, $value = NULL)
123:     {
124:         if (is_array($variable) === TRUE
125:             OR is_object($variable) === TRUE) {
126: 
127:             $this->data = array_merge($this->data, (array) $variable);
128: 
129:         } else {
130:             $this->data[$variable] = $value;
131:         }
132: 
133:         return $this;
134:     }
135: 
136: 
137:     /**
138:      * Preklad šablóny do PHP kódu
139:      *
140:      * @return string preložený kód
141:      */
142:     public function compile()
143:     {
144:         $template_name = pathinfo($this->template, PATHINFO_FILENAME);
145: 
146:         $cache_file = CACHE_DIR . '/templates/' . $template_name . '.php';
147: 
148:         $template_time = filemtime($this->template);
149: 
150:         $cache_time = 0;
151:         if (file_exists($cache_file) === TRUE) {
152:             $cache_time = filemtime($cache_file);
153:         }
154: 
155:         if ($cache_time !== FALSE
156:             AND $cache_time > $template_time
157:             AND DEBUG === FALSE) {
158: 
159:             return $cache_file;
160:         }
161: 
162:         $template = file_get_contents($this->template);
163: 
164:         $template_len = 0;
165: 
166:         while ($template_len <> strlen($template)) {
167:             $template_len = strlen($template);
168: 
169:             $template = $this->macro_layout($template);
170:             $template = $this->macro_block($template);
171:             $template = $this->macro_include($template);
172:             $template = $this->macro_control_structure($template);
173:             $template = $this->macro_widget($template);
174:             $template = $this->macro_php($template);
175:         }
176: 
177:         $macros_regexp = array(
178:             '{loop +.*?}',
179:             '{/loop}',
180:             '{!?\$.*?}',
181:             );
182: 
183:         $macros_regexp = '#(' . implode(')|(', $macros_regexp) . ')#ms';
184: 
185:         $fragments = preg_split($macros_regexp, $template, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
186: 
187:         $template = '';
188: 
189:         $loop_level = 0;
190: 
191:         foreach ($fragments as $fragment) {
192:             if (preg_match('#{loop +(\$.*?)}#', $fragment, $match) == TRUE) {
193:                 $loop_level++;
194: 
195:                 $counter = '$counter_' . $loop_level;
196:                 $key     = '$key_' . $loop_level;
197:                 $value   = '$value_' . $loop_level;
198:                 $last    = '$last_' . $loop_level;
199: 
200:                 $template .= '<?php ' . $counter . ' = -1;';
201:                 $template .= 'if (empty(' . $match[1] . ') === FALSE)';
202:                 $template .= $last . ' = (count(' . $match[1] . ') - 1);' .chr(10);
203:                 $template .= 'if (empty(' . $match[1] . ') === FALSE)';
204:                 $template .= 'foreach(' . $match[1] . ' as ' . $key . ' => ' . $value . ') {';
205:                 $template .= $counter . '++;';
206:                 $template .= '?>';
207: 
208:             } elseif (preg_match('#{/loop}#', $fragment, $match) == TRUE) {
209:                 $loop_level--;
210: 
211:                 $template .=  '<?php } ?>';
212: 
213:             } elseif (preg_match('#{!?\$.*?}#', $fragment, $match) == TRUE) {
214:                 if ($loop_level > 0) {
215:                     $fragment = preg_replace('#(\$value)([ =<>!\)\[]+)#', '$1_' . $loop_level . '$2', $fragment);
216:                     $fragment = preg_replace('#(\$key)([ =<>!\)\[]+)#', '$1_' . $loop_level . '$2', $fragment);
217:                     $fragment = preg_replace('#(\$counter)([ =<>!\)\[]+)#', '$1_' . $loop_level . '$2', $fragment);
218:                     $fragment = preg_replace('#(\$last)([ =<>!\)\[]+)#', '$1_' . $loop_level . '$2', $fragment);
219:                 }
220: 
221:                 $template .= $this->macro_variable($fragment, $loop_level);
222: 
223:             } else {
224:                 if ($loop_level > 0) {
225:                     $fragment = preg_replace('#(\$value)([ =<>!\)\[]+)#', '$1_' . $loop_level . '$2', $fragment);
226:                     $fragment = preg_replace('#(\$key)([ =<>!\)\[]+)#', '$1_' . $loop_level . '$2', $fragment);
227:                     $fragment = preg_replace('#(\$counter)([ =<>!\)\[]+)#', '$1_' . $loop_level . '$2', $fragment);
228:                     $fragment = preg_replace('#(\$last)([ =<>!\)\[]+)#', '$1_' . $loop_level . '$2', $fragment);
229:                 }
230: 
231:                 $template .= $fragment;
232:             }
233:         }
234: 
235:         foreach ($this->macros as $macro => $callback) {
236:             $template = $this->macro_custom($template, $macro, $callback);
237:         }
238: 
239:         file_put_contents($cache_file, $template);
240: 
241:         return $cache_file;
242:     }
243: 
244: 
245:     /**
246:      * Vykonanie šablóny
247:      *
248:      * @return string html kód
249:      */
250:     public function render() {
251:         extract($this->data);
252:         ob_start();
253:         include($this->compile());
254:         $contents = ob_get_contents();
255:         ob_end_clean();
256:         return $contents;
257:     }
258: 
259: 
260:     /**
261:      * Preklad makra "layout"
262:      *
263:      * @param string  kód šablóny na spracovanie
264:      * @return string spracovaný kód šablóny
265:      */
266:     private function macro_layout($template)
267:     {
268:         preg_match_all('|{extends +(.*?)}|', $template, $extends);
269: 
270:         $extends = array_unique($extends[1]);
271: 
272:         foreach ($extends as $extend) {
273:             $include_file = $this->templates_dir . '/' . $extend . '.' . $this->extension;
274:             $include_content = file_get_contents($include_file);
275: 
276:             $include_content = $this->macro_block($include_content);
277: 
278:             $template = preg_replace('|{extends +'.$extend.'}|', $include_content, $template);
279:         }
280: 
281:         if (empty($extends) === FALSE) {
282:             $template = $this->macro_block($template, FALSE);
283:         }
284: 
285:         return $template;
286:     }
287: 
288: 
289:     /**
290:      * Preklad makra "block"
291:      *
292:      * @param string  kód šablóny na spracovanie
293:      * @return string spracovaný kód šablóny
294:      */
295:     private function macro_block($template, $includes = TRUE)
296:     {
297:         $pattern = '|{block +(.*?)}(.*?){/block}|sm';
298:         preg_match_all($pattern, $template, $blocks);
299: 
300:         if (empty($blocks) === TRUE) {
301:             return $template;
302:         }
303: 
304:         foreach ($blocks[1] as $key => $block_name) {
305:             $this->blocks[$block_name] = $blocks[2][$key];
306: 
307:             if ($includes === TRUE) {
308:                 $template = str_replace($blocks[0][$key], '{include #' . $block_name . '}', $template);
309: 
310:             } else {
311:                 $template = str_replace($blocks[0][$key], '', $template);
312:             }
313:         }
314: 
315:         return $template;
316:     }
317: 
318: 
319:     /**
320:      * Preklad makra "include"
321:      *
322:      * @param string  kód šablóny na spracovanie
323:      * @return string spracovaný kód šablóny
324:      */
325:     private function macro_include($template)
326:     {
327:         preg_match_all('|{include +(.*?)}|', $template, $includes);
328: 
329:         $includes = array_unique($includes[1]);
330: 
331:         foreach ($includes as $include) {
332:             if ($include[0] === '#') {
333:                 $block = substr($include, 1);
334: 
335:                 if (isset($this->blocks[$block]) === TRUE) {
336:                     $include_content = $this->blocks[$block];
337: 
338:                 } else {
339:                     $include_content = $block;
340:                 }
341: 
342:             } else {
343:                 $include_file = $this->templates_dir . '/' . $include . '.' . $this->extension;
344:                 $include_content = file_get_contents($include_file);
345:             }
346: 
347:             $template = preg_replace('|{include +'.$include.'}|', $include_content, $template);
348:         }
349: 
350:         return $template;
351:     }
352: 
353: 
354:     /**
355:      * Preklad makier "if", "elseif", "else!
356:      *
357:      * @param string  kód šablóny na spracovanie
358:      * @return string spracovaný kód šablóny
359:      */
360:     private function macro_control_structure($template)
361:     {
362:         $pattern = '|\{if +(.*?)\}|';
363:         $replace = '<?php if($1) { ?>';
364:         $template = preg_replace($pattern, $replace, $template);
365: 
366:         $pattern = '|\{elseif +(.*?)\}|';
367:         $replace = '<?php } elseif($1) { ?>';
368:         $template = preg_replace($pattern, $replace, $template);
369: 
370:         $template = str_replace('{else}', '<?php } else { ?>', $template);
371: 
372:         $template = str_replace('{/if}', '<?php } ?>', $template);
373: 
374:         return $template;
375:     }
376: 
377: 
378:     /**
379:      * Preklad makra "$"
380:      *
381:      * @param string  kód šablóny na spracovanie
382:      * @return string spracovaný kód šablóny
383:      */
384:     private function macro_variable($variable, $loop_level = NULL)
385:     {
386:         $variable = substr($variable, 1, -1);
387: 
388:         $function = NULL;
389:         $arguments = NULL;
390: 
391:         $filters = array();
392:         if (strpos($variable, '|') !== FALSE) {
393:             $filters = explode('|', $variable);
394: 
395:             $variable = array_shift($filters);
396:         }
397: 
398:         $escape = TRUE;
399:         if ($variable[0] === '!') {
400:             $escape = FALSE;
401:             $variable = substr($variable, 1);
402:         }
403: 
404:         if ($loop_level == FALSE
405:             OR in_array($variable, array('$key', '$counter', '$value', '$last')) === FALSE) {
406: 
407:             $loop_level = '';
408: 
409:         } else {
410:             $loop_level = '_' . $loop_level;
411:         }
412: 
413:         $php_code = '<?php ';
414: 
415:         $php_code .= 'if (isset(' . $variable . $loop_level . ') === FALSE) ' . $variable . $loop_level . ' = NULL;';
416:         $php_code .= '$__tpl_var__' . $loop_level . ' = ' . $variable . $loop_level . ';';
417: 
418:         foreach ($filters as $filter) {
419:             $args = '';
420:             if (strpos($filter, ':') == TRUE) {
421:                 list($filter, $args) = explode(':', $filter);
422:                 $args = ', ' . $args;
423:             }
424: 
425:             if (isset($this->filters[$filter]) === TRUE) {
426:                 $filter = $this->filters[$filter];
427:             }
428: 
429:             if (is_array($filter) === FALSE) {
430:                 if (strpos($args, '###') == TRUE) {
431:                     $args = str_replace('###', '$__tpl_var__' . $loop_level, $args);
432:                     $function = $filter . '(' . trim($args, ',') . ');';
433: 
434:                 } else {
435:                     $function = $filter . '($__tpl_var__' . $loop_level . $args . ');';
436:                 }
437: 
438:             } else {
439:                 $function = 'call_user_func(array(\'' . $filter[0] .'\', \'' . $filter[1] . '\'), $__tpl_var__' . $loop_level . $args . ');';
440:             }
441: 
442:             $php_code .= '$__tpl_var__' . $loop_level . ' = ' . $function;
443:         }
444: 
445:         if ($escape === TRUE) {
446:             $php_code .= 'if (is_object($__tpl_var__' . $loop_level . ') === FALSE) {';
447:             $php_code .= 'echo htmlspecialchars($__tpl_var__' . $loop_level . ', ENT_QUOTES);';
448:             $php_code .= '} else {';
449:             $php_code .= 'echo $__tpl_var__' . $loop_level . ';';
450:             $php_code .= '}';
451: 
452:         } else {
453:             $php_code .= 'echo $__tpl_var__' . $loop_level . ';';
454:         }
455: 
456:         $php_code .=  '?>';
457: 
458:         return $php_code;
459:     }
460: 
461: 
462:     /**
463:      * Preklad makra "widget"
464:      *
465:      * @param string  kód šablóny na spracovanie
466:      * @return string spracovaný kód šablóny
467:      */
468:     private function macro_widget($template)
469:     {
470:         preg_match_all('|{(!?)widget +(.*?)}|', $template, $widgets);
471: 
472:         $flags = $widgets[1];
473:         $widgets = $widgets[2];
474: 
475:         foreach ($widgets as $key => $widget) {
476:             $segments = explode('_', $widget);
477:             $widget_name = '';
478:             foreach ($segments as $segment) {
479:                 $widget_name .= ucfirst($segment);
480:             }
481:             $widget_name .= 'Widget';
482: 
483:             $php_code  = '<?php ';
484:             $php_code .= '$__tpl_object = new ' . $widget_name . '($app);';
485:             $php_code .= '$__tpl_object->render(get_defined_vars());';
486:             $php_code .= 'if (empty($__tpl_object->data) === FALSE) {extract($__tpl_object->data);';
487:             $php_code .= '?>';
488: 
489:             $include = APP_DIR . '/Widgets/' . $widget_name . '.html';
490:             if (file_exists($include) === TRUE) {
491:                 $php_code .= file_get_contents($include);
492: 
493:             } else {
494:                 $var_name = Strings::split_by_upper_chars($widget);
495:                 $var_name = implode('_', $var_name);
496:                 $php_code .= '{' . $flags[$key] . '$' . strtolower($var_name) . '}';
497:             }
498: 
499:             $php_code .= '<?php } ?>';
500: 
501:             $template = preg_replace('|{' . $flags[$key] . 'widget +'.$widget.'}|', $php_code, $template);
502:         }
503: 
504:         return $template;
505:     }
506: 
507: 
508:     private function macro_php($template)
509:     {
510:         $regexp = '|{{(!?\$[a-zA-Z0-9_]+?->[a-zA-Z0-9_]+?\(.*?\))}}|ms';
511: 
512:         preg_match_all($regexp, $template, $matches);
513: 
514:         foreach ($matches[1] as $key => $method) {
515:             $php_code = '<?php ' . $method . ' ?>';
516: 
517:             $template = str_replace($matches[0][$key], $php_code, $template);
518:         }
519: 
520:         return $template;
521:     }
522: 
523: 
524:     /**
525:      * Preklad užívateľských makier
526:      *
527:      * @param  string       kód šablóny na spracovanie
528:      * @param  string       makro
529:      * @param  string|array kód makra, alebo funkcia makra (text, php kód, funkcia(pole))
530:      * @return string       spracovaný kód šablóny
531:      */
532:     private function macro_custom($template, $macro, $callback)
533:     {
534:         $regexp = '|{' . preg_quote($macro) . '(.*?)}|ms';
535: 
536:         preg_match_all($regexp, $template, $matches);
537: 
538:         $matches = array_unique($matches[1]);
539: 
540:         foreach ($matches as $match) {
541:             if (is_array($callback) === TRUE) {
542:                 if (count($callback) === 1) {
543:                     $callback = $callback[0];
544:                 }
545: 
546:                 $replacement = call_user_func($callback, $match);
547: 
548:             } else {
549:                 $replacement = $callback;
550:             }
551: 
552:             $template = str_replace('{' . $macro . $match . '}', $replacement, $template);
553:         }
554: 
555:         return $template;
556:     }
557: 
558: 
559:     /**
560:      * Registrácia užívateľkého makra
561:      *
562:      * @param  string       makro
563:      * @param  string|array kód makra, alebo funkcia makra (text, php kód, funkcia(pole))
564:      * @return void
565:      */
566:     public function register_macro($macro, $callback)
567:     {
568:         $this->macros[$macro] = $callback;
569:     }
570: 
571:     /**
572:      * Registrácia užívateľkého filtra
573:      *
574:      * @param  string       filter
575:      * @param  string|array funkcia filtra (názov funkcie, alebo pole array(Trieda, metóda))
576:      * @return
577:      */
578:     public function register_filter($filter, $callback)
579:     {
580:         $this->filters[$filter] = $callback;
581:     }
582: }
Onion API documentation generated by ApiGen.
Generated using the TokenReflection library.