Browse Source

* Add template compiling and caching

Nathaniel van Diepen 7 years ago
parent
commit
45173ec518
1 changed files with 92 additions and 3 deletions
  1. 92 3
      Data/template.class.php

+ 92 - 3
Data/template.class.php

@@ -8,6 +8,7 @@
 	class Template {
 		use Events;
 		private static $templates = [];
+		public static $cachedir;
 		private static $regex = [
 			'match'=>'/\{([^#\/][^}\n]+?)\}/i',
 			'each'=>'/\{#each ([^}]*)\}([\S\s]*)\{\/each\}/i',
@@ -16,10 +17,13 @@
 			'ignore'=>'/\{#ignore\}([\S\s]*)\{\/ignore\}/i',
 			'ignored'=>'/\{#ignored (\d+?)\}/i',
 			'gettext'=>"/{_([^,}]+)(?:, ?([^},]+))*\}/i",
-			'gettext_string'=>'/^([\'"])(.+)\1$/i'
+			'gettext_string'=>'/^([\'"])(.+)\1$/i',
+			'echo'=>'/\{=([^}]+)\}/i',
+			'eval'=>'/\{\?([\W\w\S\s]+)\?\}/i'
 		];
 		private $template;
 		private $name;
+		private $path;
 		public function __construct(string $name, string $template, bool $is_file = false){
 			if(isset(static::$templates[$name])){
 				throw new Exception("Template {$name} already exists");
@@ -33,6 +37,7 @@
 			}
 			$this->template = $template;
 			$this->name = $name;
+			$this->path = static::$cachedir."/{$this->name}.".md5($this->template).'.php';
 			static::$templates[$name] = $this;
 		}
 		public function run(array $data) : string{
@@ -40,7 +45,10 @@
 			if($this->fire('before', $data) === false){
 				throw new Exception("Render on template {$this->name} cancelled. Before.");
 			}
-			$output = static::parse($this->template, $data);
+			if(!file_exists($this->path)){
+				file_put_contents($this->path, static::compile($this->template));
+			}
+			$output = static::execute($this->path, $data);
 			if($this->fire('after', $output) === false){
 				throw new Exception("Render on template {$this->name} cancelled. After");
 			}
@@ -53,7 +61,68 @@
 			}
 			return $template->run($data);
 		}
-		public static function parse(string $template, $data){
+		public static function compile(string $template) : string{
+			$ignored = [];
+			// Handle {#ignore code}
+			$output = preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
+				$ignored[] = $matches[1];
+				return '{#ignored '.(count($ignored) - 1).'}';
+			}, $template);
+			// Handle {#each name}{/each}
+			$output = preg_replace_callback(static::$regex['each'], function($matches){
+				$output = "<?php if(isset(\$data[".var_export($matches[1], true)."])): ";
+				$output .= "foreach(\$data[".var_export($matches[1], true)."] as \$item): ";
+				$output .= "\$parent = \$data; ?>";
+				$output .= static::compile($matches[2]);
+				$output .= "<?php \$data = \$parent;";
+				$output .= "endforeach;endif; ?>";
+				return $output;
+			}, $output);
+			// Handle {#exist name}{#else}{/exist}
+			$output = preg_replace_callback(static::$regex['existelse'], function($matches){
+				$output = "<?php if(isset(\$data[".var_export($matches[1], true)."])): ?>";
+				$output .= static::compile($matches[2]);
+				$output .= "<php else: ?>";
+				$output .= static::compile($matches[3]);
+				$output .= "<?php endif; ?>";
+				return $output;
+			}, $output);
+			// Handle {#exist name}{/exist}
+			$output = preg_replace_callback(static::$regex['exist'], function($matches){
+				$output = "<?php if(isset(\$data[".var_export($matches[1], true)."])): ?>";
+				$output .= static::compile($matches[2]);
+				$output .= "<?php endif; ?>";
+			}, $output);
+			// Handle {gettext}
+			$output = preg_replace_callback(static::$regex['gettext'], function($matches){
+				$output = "<?= _(sprintf(";
+				foreach(array_slice($matches, 1) as $item){
+					if(preg_match(static::$regex['gettext_string'], $item)){
+						$output .= $item;
+					}else{
+						$output .= "(\$data['{$item}'] ?? '')";
+					}
+				}
+				return "{$output})); ?>";
+			}, $output);
+			// Handle {=expression}
+			$output = preg_replace_callback(static::$regex['echo'], function($matches){
+				return "<?= {$matches[1]}; ?>";
+			}, $output);
+			// Handle {? expression ?}
+			$output = preg_replace_callback(static::$regex['eval'], function($matches){
+				return "<?php {$matches[1]}; ?>";
+			}, $output);
+			// Handle {name}
+			$output = preg_replace_callback(static::$regex['match'], function($matches){
+				return "<?=(\$data[".var_export($matches[1], true)."] ?? ''); ?>";
+			}, $output);
+			// Handle {#ignored i}
+			return preg_replace_callback(static::$regex['ignored'], function($matches) use(&$ignored){
+				return htmlentities($ignored[(int)$matches[1]] ?? '');
+			}, $output);
+		}
+		public static function parse(string $template, $data) : string{
 			$ignored = [];
 			// Handle {#ignore code}
 			$output = preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
@@ -97,13 +166,33 @@
 				}, array_slice($matches, 1));
 				return _(sprintf(...$args));
 			}, $output);
+			// Handle {=expression}
+			$output = preg_replace_callback(static::$regex['echo'], function($matches) use($data){
+				return eval("return {$matches[1]};");
+			}, $output);
+			// Handle {? expression ?}
+			$output = preg_replace_callback(static::$regex['eval'], function($matches) use($data){
+				ob_start();
+				eval($matches[1]);
+				$output = ob_get_contents();
+				ob_end_clean();
+				return $output;
+			}, $output);
 			// Handle {name}
 			$output = preg_replace_callback(static::$regex['match'], function($matches) use($data){
 				return $data[$matches[1]] ?? '';
 			}, $output);
+			// Handle {#ignored i}
 			return preg_replace_callback(static::$regex['ignored'], function($matches) use(&$ignored){
 				return $ignored[(int)$matches[1]] ?? '';
 			}, $output);
 		}
+		public static function execute(string $path, $data) : string{
+			ob_start();
+			include($path);
+			$output = ob_get_contents();
+			ob_end_clean();
+			return $output;
+		}
 	}
 ?>