* @author Marcus Lunzenauer * @license MIT */ namespace Flexi; class Factory { /** * mapping of file extensions to supported template classes */ protected array $handlers = [ 'php' => [PhpTemplate::class, []], ]; /** * Constructor of TemplateFactory. * * @param string $path the template include path */ public function __construct(protected string $path) { $this->set_path($path); } /** * Sets a new include path for the factory and returns the old one. * * @param string $path the new path * * @return string the old path */ public function set_path(string $path): string { $old_path = $this->get_path(); if (!str_ends_with($path, '/')) { $path .= '/'; } $this->path = $path; return $old_path; } /** * Returns the include path of the factory * * @return string the current include path */ public function get_path(): string { return $this->path; } /** * Open a template of the given name using the factory method pattern. * If a string was given, the path of the factory is searched for a matching * template. * If this string starts with a slash or with /\w+:\/\//, the string is * interpreted as an absolute path. Otherwise the path of the factory will be * prepended. * After that the factory searches for a file extension in this string. If * there is none, the directory where the template is supposed to live is * searched for a file starting with the template string and a supported * file extension. * At last the factory instantiates a template object of the matching template * class. * * Examples: * * $factory->open('/path/to/template') * does not prepend the factory's path but searches for "template.*" in * "/path/to" * * $factory->open('template') * prepends the factory's path and searches there for "template.*" * * $factory->open('template.php') * prepends the factory's path but does not search and instantiates a * PHPTemplate instead * * This method returns it's parameter, if it is not a string. This * functionality is useful for helper methods like #render_partial * * @param Template|string $template A name of a template. * @return Template the factored object * @throws TemplateNotFoundException if the template could not be found */ public function open(Template|string $template): Template { # if it is not a string, this method behaves like identity if ($template instanceof Template) { return $template; } # get file $file = $this->get_template_file($template); # retrieve handler [$class, $options] = $this->get_template_handler($file); return new $class($file, $this, $options); } /** * This method returns the absolute filename of the template * * @param string $template0 a template string * * @return string an absolute filename * * @throws TemplateNotFoundException if the template could not be found */ public function get_template_file(string $template0): string { $template = $this->get_absolute_path($template0); $extension = $this->get_extension($template); # extension defined, is there a matching template class? if ($extension !== null) { if (file_exists($template)) { return $template; } } # no extension defined, find it else { $file = $this->find_template($template); if ($file !== null) { return $file; } } # falling through to throw exception throw new TemplateNotFoundException(sprintf( 'Missing template "%s" in "%s".', $template0, $this->path )); } /** * Matches an extension to a template handler. * * @param string $template the template * * @return array|null an array containing the class name and an array of * options of the matched extension; * or NULL if the extension did not match */ public function get_template_handler(string $template): ?array { $extension = $this->get_extension($template); return $this->handlers[$extension] ?? null; } /** * Registers a handler for templates with a matching extension. * * @param string $extension the extension of the templates to handle * @param class-string