'/\{([^#\/][^}\n]+?)\}/i', 'each'=>'/\{#each ([^}]*)\}([\S\s]*)\{\/each\}/i', 'exist'=>'/\{#exist ([^}]*)\}([\S\s]*)\{\/exist\}/i', 'existelse'=>'/\{#exist ([^}]*)\}([\S\s]*)\{#else\}([\S\s]*)\{\/exist\}/i', 'ignore'=>'/\{#ignore\}([\S\s]*)\{\/ignore\}/i', 'ignored'=>'/\{#ignored (\d+?)\}/i', 'gettext'=>"/{_([^,}]+)(?:, ?([^},]+))*\}/i", 'gettext_string'=>'/^([\'"])(.+)\1$/i' ]; private $template; private $name; public function __construct(string $name, string $template, bool $is_file = false){ if(isset(static::$templates[$name])){ throw new Exception("Template {$name} already exists"); } if($is_file){ $path = realpath($template); if(!file_exists($path)){ throw new Exception("Template file {$template} doesn't exist"); } $template = file_get_contents($path); } $this->template = $template; $this->name = $name; static::$templates[$name] = $this; } public function run(array $data) : string{ $data = EArray::from($data); if($this->fire('before', $data) === false){ throw new Exception("Render on template {$this->name} cancelled. Before."); } $output = static::parse($this->template, $data); if($this->fire('after', $output) === false){ throw new Exception("Render on template {$this->name} cancelled. After"); } return (string)$output; } public static function from(string $name, array $data = []) : string{ $template = static::$templates[$name] ?? null; if(is_null($template)){ throw new Exception("Template {$name} does not exist"); } return $template->run($data); } public static function parse(string $template, $data){ $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) use($data){ $output = ''; if(isset($data[$matches[1]])){ foreach($data[$matches[1]] as $item){ $output = static::parse($matches[2], $item); } } return $output; }, $output); // Handle {#exist name}{#else}{/exist} $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); // Handle {#exist name}{/exist} $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); // Handle {gettext} $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); // Handle {name} $output = preg_replace_callback(static::$regex['match'], function($matches) use($data){ return $data[$matches[1]] ?? ''; }, $output); return preg_replace_callback(static::$regex['ignored'], function($matches) use(&$ignored){ return $ignored[(int)$matches[1]] ?? ''; }, $output); } } ?>