|
@@ -12,6 +12,7 @@
|
|
|
public static $basedir = __DIR__;
|
|
|
private static $regex = [
|
|
|
'match'=>'/\{([^#\/?_][^}\n]*?)\}/i',
|
|
|
+ 'parentmatch'=>'/\{\.\.\/([^#\/?_][^}\n]*?)\}/i',
|
|
|
'each'=>'/\{#each ([^}]*)\}([\S\s]*)\{\/each \1\}/i',
|
|
|
'exist'=>'/\{#exist ([^}]*)\}([\S\s]*)\{\/exist \1\}/i',
|
|
|
'existelse'=>'/\{#exist ([^}]*)\}([\S\s]*)\{#else \1\}([\S\s]*)\{\/exist \1\}/i',
|
|
@@ -23,6 +24,7 @@
|
|
|
'eval'=>'/\{\?([\W\w\S\s]+)\?\}/i',
|
|
|
'include'=>'/{#include ([^}]+)}/i'
|
|
|
];
|
|
|
+ protected static $parsers;
|
|
|
private $template;
|
|
|
private $name;
|
|
|
private $path;
|
|
@@ -41,6 +43,176 @@
|
|
|
$this->name = $name;
|
|
|
$this->path = static::$cachedir."/{$this->name}.".md5($this->template).'.php';
|
|
|
static::$templates[$name] = $this;
|
|
|
+ if(is_null(static::$parsers)){
|
|
|
+ static::$parsers = [
|
|
|
+ 'ignore'=>function(&$output, &$ignored){
|
|
|
+ $output = preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
|
|
|
+ $ignored[] = $matches[1];
|
|
|
+ return '{#ignored '.(count($ignored) - 1).'}';
|
|
|
+ }, $output);
|
|
|
+ },
|
|
|
+ 'include'=>function(&$output, &$ignored){
|
|
|
+ $output = preg_replace_callback(static::$regex['include'], function($matches) use(&$ignored){
|
|
|
+ $path = static::$basedir.'/'.$matches[1];
|
|
|
+ if(file_exists($path)){
|
|
|
+ $output = file_get_contents($path);
|
|
|
+ static::$parsers['ignore']($output, $ignored);
|
|
|
+ return $output;
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ }, $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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $output;
|
|
|
+ }, $output);
|
|
|
+ },
|
|
|
+ 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; ?>";
|
|
|
+ $output .= static::compile($matches[2]);
|
|
|
+ $output .= "<?php \$data = array_pop(\$parent);";
|
|
|
+ $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; ?>";
|
|
|
+ }, $output);
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ 'gettext'=>[
|
|
|
+ function(&$output, $data){
|
|
|
+ $output = preg_replace_callback(static::$regex['gettext'], function($matches) use($data){
|
|
|
+ $args = array_map(function($item) use($data){
|
|
|
+ if(preg_match(static::$regex['gettext_string'], $item)){
|
|
|
+ return preg_replace(static::$regex['gettext_string'], '\2', $item);
|
|
|
+ }else{
|
|
|
+ return $data[$item] ?? '';
|
|
|
+ }
|
|
|
+ }, array_slice($matches, 1));
|
|
|
+ return _(sprintf(...$args));
|
|
|
+ }, $output);
|
|
|
+ },
|
|
|
+ function(&$output){
|
|
|
+ $output = preg_replace_callback(static::$regex['gettext'], function($matches){
|
|
|
+ if(count($matches) > 2){
|
|
|
+ $output = "<?= 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 = "<?= _({$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 $data[$matches[1]] ?? '';
|
|
|
+ }, $output);
|
|
|
+ },
|
|
|
+ function(&$output){
|
|
|
+ $output = preg_replace_callback(static::$regex['match'], function($matches){
|
|
|
+ return "<?=(\$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 "<?=(\$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]] ?? '');
|
|
|
+ }, $output);
|
|
|
+ }
|
|
|
+ ];
|
|
|
+ }
|
|
|
}
|
|
|
public function run(array $data) : string{
|
|
|
$data = EArray::from($data);
|
|
@@ -70,155 +242,57 @@
|
|
|
}
|
|
|
public static function compile(string $template) : string{
|
|
|
$ignored = [];
|
|
|
+ $output = $template;
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
|
|
|
- $ignored[] = $matches[1];
|
|
|
- return '{#ignored '.(count($ignored) - 1).'}';
|
|
|
- }, $template);
|
|
|
+ static::$parsers['ignore']($output, $ignored);
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['include'], function($matches) use(&$ignored){
|
|
|
- $path = static::$basedir.'/'.$matches[1];
|
|
|
- if(file_exists($path)){
|
|
|
- return preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
|
|
|
- $ignored[] = $matches[1];
|
|
|
- return '{#ignored '.(count($ignored) - 1).'}';
|
|
|
- }, file_get_contents($path));
|
|
|
- }
|
|
|
- return '';
|
|
|
- }, $output);
|
|
|
+ static::$parsers['include']($output, $ignored);
|
|
|
|
|
|
- $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; ?>";
|
|
|
- $output .= static::compile($matches[2]);
|
|
|
- $output .= "<?php \$data = array_pop(\$parent);";
|
|
|
- $output .= "endforeach;endif; ?>";
|
|
|
- return $output;
|
|
|
- }, $output);
|
|
|
+ static::$parsers['each'][1]($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);
|
|
|
+ static::$parsers['existelse'][1]($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; ?>";
|
|
|
- }, $output);
|
|
|
+ static::$parsers['exist'][1]($output);
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['gettext'], function($matches){
|
|
|
- if(count($matches) > 2){
|
|
|
- $output = "<?= 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 = "<?= _({$matches[1]}";
|
|
|
- }
|
|
|
- return "{$output}); ?>";
|
|
|
- }, $output);
|
|
|
+ static::$parsers['gettext'][1]($output);
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['echo'], function($matches){
|
|
|
- return "<?= {$matches[1]}; ?>";
|
|
|
- }, $output);
|
|
|
+ static::$parsers['echo'][1]($output);
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['eval'], function($matches){
|
|
|
- return "<?php {$matches[1]}; ?>";
|
|
|
- }, $output);
|
|
|
+ static::$parsers['eval'][1]($output);
|
|
|
+
|
|
|
+ static::$parsers['parentmatch'][1]($output);
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['match'], function($matches){
|
|
|
- return "<?=(\$data[".var_export($matches[1], true)."] ?? ''); ?>";
|
|
|
- }, $output);
|
|
|
+ static::$parsers['match'][1]($output);
|
|
|
|
|
|
- return preg_replace_callback(static::$regex['ignored'], function($matches) use(&$ignored){
|
|
|
- return htmlentities($ignored[(int)$matches[1]] ?? '');
|
|
|
- }, $output);
|
|
|
+ static::$parsers['ignored']($output, $ignored);
|
|
|
+ return $output;
|
|
|
}
|
|
|
public static function parse(string $template, $data) : string{
|
|
|
$ignored = [];
|
|
|
+ $output = $template;
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
|
|
|
- $ignored[] = $matches[1];
|
|
|
- return '{#ignored '.(count($ignored) - 1).'}';
|
|
|
- }, $template);
|
|
|
+ static::$parsers['ignore']($output, $ignored);
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['include'], function($matches) use(&$ignored){
|
|
|
- $path = static::$basedir.'/'.$matches[1];
|
|
|
- if(file_exists($path)){
|
|
|
- return preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
|
|
|
- $ignored[] = $matches[1];
|
|
|
- return '{#ignored '.(count($ignored) - 1).'}';
|
|
|
- }, file_get_contents($path));
|
|
|
- }
|
|
|
- return '';
|
|
|
- }, $output);
|
|
|
+ static::$parsers['include']($output, $ignored);
|
|
|
|
|
|
- $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);
|
|
|
- }
|
|
|
- }
|
|
|
- return $output;
|
|
|
- }, $output);
|
|
|
+ static::$parsers['each'][0]($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);
|
|
|
+ static::$parsers['existelse'][0]($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);
|
|
|
+ static::$parsers['exist'][0]($output, $data);
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['gettext'], function($matches) use($data){
|
|
|
- $args = array_map(function($item) use($data){
|
|
|
- if(preg_match(static::$regex['gettext_string'], $item)){
|
|
|
- return preg_replace(static::$regex['gettext_string'], '\2', $item);
|
|
|
- }else{
|
|
|
- return $data[$item] ?? '';
|
|
|
- }
|
|
|
- }, array_slice($matches, 1));
|
|
|
- return _(sprintf(...$args));
|
|
|
- }, $output);
|
|
|
+ static::$parsers['gettext'][0]($output, $data);
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['echo'], function($matches) use($data){
|
|
|
- return eval("return {$matches[1]};");
|
|
|
- }, $output);
|
|
|
+ static::$parsers['echo'][0]($output);
|
|
|
|
|
|
- $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);
|
|
|
+ static::$parsers['eval'][0]($output);
|
|
|
+
|
|
|
+ static::$parsers['parentmatch'][1]($output, $data);
|
|
|
|
|
|
- $output = preg_replace_callback(static::$regex['match'], function($matches) use($data){
|
|
|
- return $data[$matches[1]] ?? '';
|
|
|
- }, $output);
|
|
|
+ static::$parsers['match'][0]($output, $data);
|
|
|
|
|
|
- return preg_replace_callback(static::$regex['ignored'], function($matches) use(&$ignored){
|
|
|
- return $ignored[(int)$matches[1]] ?? '';
|
|
|
- }, $output);
|
|
|
+ static::$parsers['ignored']($output, $ignored);
|
|
|
+ return $output;
|
|
|
}
|
|
|
public static function execute(string $path, $data) : string{
|
|
|
ob_start();
|