cache = $cache ?? new Caching\Memory(""); $this->context = $context ?? new Compiler\BaseContext(); $this->languageRegistration = $languageRegistration ?? new Language\DefaultRegistrations([], [], []); $this->builderTemplatePath = $builderTemplatePath ?? dirname(__FILE__) . static::DEFAULT_BUILDER_TEMPLATE; $this->compiler = $compiler ?? $this->instanciateCompiler(); $this->fileFetcher = $fileFetcher ?? $this->instanciateFileFetcher(); $this->debug = $debug; $this->compiler->registerExtensionsFunctions($this->context); $this->renderContext($this->context); } public function gatherCompiledObject(string $viewPath, array $variables = [], ? object $proxy = null) : ? object { if ( null === $object = $this->fetchFromCache($viewPath, $this->globalVariables + $variables, $proxy) ) { throw new \RuntimeException("An error occured while trying to save a compiled template."); } return $object; } public function renderHtml(string $viewPath, array $variables = [], ?object $proxy = null) : ? string { $object = $this->gatherCompiledObject($viewPath, $variables, $proxy); try { return call_user_func($object); } catch(\Throwable $ex) { #if (! $ex instanceof Exception\RenderHtmlException ) { # throw new Exception\RenderHtmlException($object, $this, "An error occurred trying to render HTML view `$viewPath` : " . $ex->getMessage(), 911, $ex); #} #else { throw $ex; #} } return null; } /** * Method used by Block and View tokens */ public function inlineHtml(? object $proxy, string $viewPath, array $variables) { return $this->renderHtml($viewPath, $this->globalVariables + $variables, $proxy); } /** * Allows block to be called from templates */ public function inlineBlock(? object $proxy, string $viewPath, ... $variables) { return $this->renderHtml($viewPath, [ 'inlineVariables' => $variables, 'globalVariables' => $this->globalVariables ], $proxy); } /** * Push view content inline */ public function inlineContent(string $viewPath) { return $this->fileFetcher->getFileContent($viewPath); } /** * Renders a compile context */ public function renderContext(Compiler\Context $context) : object { if ( null === $object = $this->contextFromCache($context) ) { throw new \RuntimeException("An error occured while trying to save a compiled template."); } return $object; } public function compileSource(string $source) : array { $this->compiler->loadSourceCode($source); return [ 'context' => $context = clone $this->context, 'source' => $this->compiler->compile($context), ]; } public function compileFile(string $viewPath) : array { if (! file_exists($viewPath) ) { throw new \InvalidArgumentException("File `$viewPath` cannot be found or there is a permission problem."); } if ( false === $fileContent = file_get_contents($viewPath) ) { throw new \ErrorException("Given file could not be opened `$viewPath`. This could indicate a permission misconfiguration on your file or folder."); } $this->compiler->loadSourceCode($fileContent); $context = clone $this->context; $context->viewPath = $viewPath; $context->source = $this->compiler->compile($context); return $context; } public function buildFromSource(string $source) : array { $tmpFolder = sys_get_temp_dir(); $builder = $this->instanciateBuilder(); $compiledSource = $this->compileSource($source); list($namespace, $className) = $builder->build($compiledSource['context'], $compiledSource['source']) ; $path = "$tmpFolder/$className.php"; file_put_contents($path, $compiledSource); return [ 'path' => $path, 'namespace' => $namespace, 'className' => $className, ]; } public function fetchFromCache(string $viewPath, array $variables = [], ?object $proxy = null) : ?object { if ( ! isset($this->compiled[$viewPath]) && ( true === $this->debug ) || (! $this->cache->compiled($viewPath))) { $context = $this->compileView($viewPath); $this->cache->save($context); if ( $context->extendFrom ) { $this->fetchFromCache($context->extendFrom, $variables, $proxy); } $this->compiled[$viewPath] = true; } return $this->cache->load($viewPath, $this, $variables, $proxy); } public function contextFromCache(Compiler\Context $context) : ?object { if ( $this->debug || ! $this->cache->compiled( $context->cacheFilename() ) ) { $context = $this->compileContext($context); $this->cache->save($context); } return $this->cache->load($context->cacheFilename(), $this); } public function instanciateCompiler() : Compiler { return new Compiler($this->languageRegistration); } public function instanciateBuilder() : Builder { return new Builder($this->builderTemplatePath); } public function instanciateFileFetcher() : FileFetcher { return new FileFetcher(); } public function registerAll(Compiler $compiler) : void { $this->registerSyntax($compiler); $this->registerControlStructure($compiler); $this->registerExtension($compiler); } public function registerSyntax(Compiler $compiler) : void { $this->languageRegistration->registerSyntax($compiler); } public function registerControlStructure(Compiler $compiler) : void { $this->languageRegistration->registerControlStructure($compiler); } public function registerExtension(Compiler $compiler) : void { $this->languageRegistration->registerExtension($compiler); } public function declareLoadedTemplate(string $className, string $filePath) : void { $this->loadedTemplateFile[$className] = $filePath; } protected function compileView(string $viewPath) : Compiler\Context { $tmpFolder = sys_get_temp_dir(); $builder = $this->instanciateBuilder(); $compiled = $this->compileSource($this->fileFetcher->getFileContent($viewPath)); $context = $compiled['context']; $context->viewPath = $viewPath; $context->filePath = $this->fileFetcher->getFilePath($viewPath); $context = $builder->build($compiled['context'], $compiled['source']) ; $context->classPath = $tmpFolder . DIRECTORY_SEPARATOR . $context->className . ".php"; if ( $context->extendFrom ) { $this->compileView($context->extendFrom); } return $context; } protected function compileContext(Compiler\Context $context) : Compiler\Context { $tmpFolder = sys_get_temp_dir(); $builder = $this->instanciateBuilder(); $compiled = $this->compileSource(""); $context->viewPath = $context->cacheFilename(); $builder->build($context, ""); $context->classPath = $tmpFolder . DIRECTORY_SEPARATOR . $context->cacheFilename() . ".php"; return $context; } }