Browse Source

* Add define
* Add widget
* Simplify parsers
* Make parse cache templates so it doesn't have to build them each time if you are repeating using Template::parse(string, data)

Nathaniel van Diepen 7 years ago
parent
commit
09b7495250
1 changed files with 93 additions and 168 deletions
  1. 93 168
      Data/template.class.php

+ 93 - 168
Data/template.class.php

@@ -41,7 +41,9 @@
 			'gettext_string'=>'/^([\'"])(.+)\1$/i',
 			'echo'=>'/\{=([^}]+)\}/i',
 			'eval'=>'/\{\?([\W\w\S\s]+)\?\}/i',
-			'include'=>'/{#include ([^}]+)}/i'
+			'include'=>'/{#include ([^}]+)}/i',
+			'define'=>'/\{#define ([^}]*)\}([\S\s]*)\{\/define \1\}/i',
+			'widget'=>'/{#widget ([^}]+)}/i'
 		];
 		protected static $parsers;
 		private $template;
@@ -71,20 +73,31 @@
 							}, $output);
 						}
 					},
-					'each'=>[
-						function(&$output, $data){
-							$output = preg_replace_callback(static::$regex['each'], function($matches) use($data){
-								$output = '';
-								if(isset($data[$matches[1]])){
-									foreach($data[$matches[1]] as $item){
-										$output = static::parse($matches[2], $item);
-									}
+					'define'=>function(&$output, &$widgets){
+						while(preg_match(static::$regex['define'], $output)){
+							$output = preg_replace_callback(static::$regex['define'], function($matches) use(&$widgets){
+								$name = $matches[1];
+								if(isset($widgets[$name])){
+									throw new \Exception("Widget {$name} is already defined");
 								}
-								return $output;
+								$widgets[$name] = $matches[2];
+								return '';
 							}, $output);
-						},
-						function(&$output){
-							$output = preg_replace_callback(static::$regex['each'], function($matches){
+						}
+					},
+					'widget'=>function(&$output, $widgets){
+						while(preg_match(static::$regex['widget'], $output)){
+							$output = preg_replace_callback(static::$regex['widget'], function($matches) use(&$widgets){
+								$name = $matches[1];
+								if(!isset($widgets[$name])){
+									throw new \Exception("Widget {$name} is not defined");
+								}
+								return $widgets[$name];
+							}, $output);
+						}
+					},
+					'each'=>function(&$output){
+						$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; \$data = \$item; ?>";
@@ -93,129 +106,62 @@
 							$output .= "endforeach;endif; ?>";
 							return $output;
 						}, $output);
-						}
-					],
-					'existelse'=>[
-						function(&$output, $data){
-							$output = preg_replace_callback(static::$regex['existelse'], function($matches) use($data){
-								if(isset($data[$matches[1]])){
-									$output = static::parse($matches[2], $data);
-								}else{
-									$output = static::parse($matches[3], $data);
-								}
-								return $output;
-							}, $output);
-						},
-						function(&$output){
-							$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);
-						}
-					],
-					'exist'=>[
-						function(&$output, $data){
-							$output = preg_replace_callback(static::$regex['exist'], function($matches) use($data){
-								if(isset($data[$matches[1]])){
-									return static::parse($data[$matches[2]], $data);
-								}
-								return '';
-							}, $output);
-						},
-						function(&$output){
-							$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; ?>";
-								return $output;
-							}, $output);
-						}
-					],
-					'gettext'=>[
-						function(&$output, $data){
-							$output = preg_replace_callback(static::$regex['gettext'], function($matches) use($data){
-								$args = array_map(function($item) use($data){
+					},
+					'existelse'=>function(&$output){
+						$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);
+					},
+					'exist'=>function(&$output){
+						$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; ?>";
+							return $output;
+						}, $output);
+					},
+					'gettext'=>function(&$output){
+						$output = preg_replace_callback(static::$regex['gettext'], function($matches){
+							if(count($matches) > 2){
+								$output = "<?=htmlentities(sprintf(_({$matches[1]})";
+								foreach(array_slice($matches, 2) as $item){
 									if(preg_match(static::$regex['gettext_string'], $item)){
-										return preg_replace(static::$regex['gettext_string'], '\2', $item);
+										$output .= ", $item";
 									}else{
-										return $data[$item] ?? '';
+										$output .= ", (\$data['{$item}'] ?? '')";
 									}
-								}, array_slice($matches, 1));
-								return htmlentities(_(sprintf(...$args)));
-							}, $output);
-						},
-						function(&$output){
-							$output = preg_replace_callback(static::$regex['gettext'], function($matches){
-								if(count($matches) > 2){
-									$output = "<?=htmlentities(sprintf(_({$matches[1]})";
-									foreach(array_slice($matches, 2) as $item){
-										if(preg_match(static::$regex['gettext_string'], $item)){
-											$output .= ", $item";
-										}else{
-											$output .= ", (\$data['{$item}'] ?? '')";
-										}
-									}
-								}else{
-									$output = "<?=htmlentities(_({$matches[1]}";
 								}
-								return "{$output})); ?>";
-							}, $output);
-						}
-					],
-					'echo'=>[
-						function(&$output){
-							$output = preg_replace_callback(static::$regex['echo'], function($matches){
-								return eval("return {$matches[1]};");
-							}, $output);
-						},
-						function(&$output){
-							$output = preg_replace_callback(static::$regex['echo'], function($matches){
-								return "<?= {$matches[1]}; ?>";
-							}, $output);
-						}
-					],
-					'eval'=>[
-						function(&$output){
-							$output = preg_replace_callback(static::$regex['eval'], function($matches){
-								ob_start();
-								eval($matches[1]);
-								$output = ob_get_contents();
-								ob_end_clean();
-								return $output;
-							}, $output);
-						},
-						function(&$output){
-							$output = preg_replace_callback(static::$regex['eval'], function($matches){
-								return "<?php {$matches[1]}; ?>";
-							}, $output);
-						}
-					],
-					'match'=>[
-						function(&$output, $data){
-							$output = preg_replace_callback(static::$regex['match'], function($matches) use($data){
-								return htmlentities($data[$matches[1]] ?? '');
-							}, $output);
-						},
-						function(&$output){
-							$output = preg_replace_callback(static::$regex['match'], function($matches){
-								return "<?=htmlentities(\$data[".var_export($matches[1], true)."] ?? ''); ?>";
-							}, $output);
-						}
-					],
-					'parentmatch'=>[
-						function(&$output, $data){
-							throw new \Exception("Not supported in non-compiled templates");
-						},
-						function(&$output){
-							$output = preg_replace_callback(static::$regex['parentmatch'], function($matches){
-								return "<?=htmlentities(\$parent[count(\$parent)-1][".var_export($matches[1], true)."] ?? ''); ?>";
-							}, $output);
-						}
-					],
+							}else{
+								$output = "<?=htmlentities(_({$matches[1]}";
+							}
+							return "{$output})); ?>";
+						}, $output);
+					},
+					'echo'=>function(&$output){
+						$output = preg_replace_callback(static::$regex['echo'], function($matches){
+							return "<?= {$matches[1]}; ?>";
+						}, $output);
+					},
+					'eval'=>function(&$output){
+						$output = preg_replace_callback(static::$regex['eval'], function($matches){
+							return "<?php {$matches[1]}; ?>";
+						}, $output);
+					},
+					'match'=>function(&$output){
+						$output = preg_replace_callback(static::$regex['match'], function($matches){
+							return "<?=htmlentities(\$data[".var_export($matches[1], true)."] ?? ''); ?>";
+						}, $output);
+					},
+					'parentmatch'=>function(&$output){
+						$output = preg_replace_callback(static::$regex['parentmatch'], function($matches){
+							return "<?=htmlentities(\$parent[count(\$parent)-1][".var_export($matches[1], true)."] ?? ''); ?>";
+						}, $output);
+					},
 					'ignored'=>function(&$output, $ignored){
 						$output = preg_replace_callback(static::$regex['ignored'], function($matches) use($ignored){
 							return htmlentities($ignored[(int)$matches[1]] ?? '');
@@ -234,6 +180,9 @@
 				$template = file_get_contents($path);
 			}
 			static::$parsers['include']($template);
+			$widgets = [];
+			static::$parsers['define']($template, $widgets);
+			static::$parsers['widget']($template, $widgets);
 			$this->template = $template;
 			$this->name = $name;
 			$this->path = static::$cachedir."/{$this->name}.".md5($this->template).'.php';
@@ -284,55 +233,31 @@
 			// Handle {#include path/to/file}
 			static::$parsers['include']($output, $ignored);
 			// Handle {#each name}{/each}
-			static::$parsers['each'][1]($output);
+			static::$parsers['each']($output);
 			// Handle {#exist name}{#else}{/exist}
-			static::$parsers['existelse'][1]($output);
+			static::$parsers['existelse']($output);
 			// Handle {#exist name}{/exist}
-			static::$parsers['exist'][1]($output);
+			static::$parsers['exist']($output);
 			// Handle {gettext}
-			static::$parsers['gettext'][1]($output);
+			static::$parsers['gettext']($output);
 			// Handle {=expression}
-			static::$parsers['echo'][1]($output);
+			static::$parsers['echo']($output);
 			// Handle {? expression ?}
-			static::$parsers['eval'][1]($output);
+			static::$parsers['eval']($output);
 			// Handle {../name}
-			static::$parsers['parentmatch'][1]($output);
+			static::$parsers['parentmatch']($output);
 			// Handle {name}
-			static::$parsers['match'][1]($output);
+			static::$parsers['match']($output);
 			// Handle {#ignored i}
 			static::$parsers['ignored']($output, $ignored);
 			return $output;
 		}
 		public static function parse(string $template, $data) : string{
-			if(is_null(static::$parsers)){
-				// Force parsers to be added
-				new Template(uuid(), $template);
+			$id = md5($template);
+			if(!isset(static::$templates[$id])){
+				new Template($id, $template);
 			}
-			$ignored = [];
-			$output = $template;
-			// Handle {#ignore code}
-			static::$parsers['ignore']($output, $ignored);
-			// Handle {#include path/to/file}
-			static::$parsers['include']($output, $ignored);
-			// Handle {#each name}{/each}
-			static::$parsers['each'][0]($output, $data);
-			// Handle {#exist name}{#else}{/exist}
-			static::$parsers['existelse'][0]($output, $data);
-			// Handle {#exist name}{/exist}
-			static::$parsers['exist'][0]($output, $data);
-			// Handle {gettext}
-			static::$parsers['gettext'][0]($output, $data);
-			// Handle {=expression}
-			static::$parsers['echo'][0]($output);
-			// Handle {? expression ?}
-			static::$parsers['eval'][0]($output);
-			// Handle {../name}
-			static::$parsers['parentmatch'][1]($output, $data);
-			// Handle {name}
-			static::$parsers['match'][0]($output, $data);
-			// Handle {#ignored i}
-			static::$parsers['ignored']($output, $ignored);
-			return $output;
+			return static::$templates[$id]->run($data);
 		}
 		public static function execute(string $path, $data) : string{
 			ob_start();