picea/src/Picea.php
Dave Mc Nicoll ddc3ae704a - Work on Language Handler and extension.
- Added an URL extension which allows routes and URLs.
- Fixed some bug within ClassTemplate
2020-01-23 15:28:05 -05:00

221 lines
7.2 KiB
PHP

<?php declare(strict_types=1);
namespace Picea;
use Closure;
use Picea\Language\LanguageRegistration;
use Psr\Http\Message\ResponseInterface;
class Picea implements LanguageRegistration
{
const DEFAULT_BUILDER_TEMPLATE = "/Builder/ClassTemplate.php";
public Compiler\Context $context;
public Compiler $compiler;
public LanguageRegistration $languageRegistration;
public string $builderTemplatePath;
public Closure $responseHtml;
public Caching\Cache $cache;
public FileFetcher $fileFetcher;
public bool $debug;
public function __construct(
? Closure $responseHtml = null,
? Compiler\Context $context = null,
? Caching\Cache $cache = null,
? Compiler $compiler = null,
? LanguageRegistration $languageRegistration = null,
? FileFetcher $fileFetcher = null,
? string $builderTemplatePath = null,
bool $debug = false
){
$this->response = $responseHtml;
$this->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->context->exportFunctions();
$this->renderContext($this->context);
}
public function renderHtml(string $viewPath, array $variables = [], ?object $proxy = null) : string
{
if ( null === $object = $this->fetchFromCache($viewPath, $variables, $proxy) ) {
throw new \RuntimeException("An error occured while trying to save a compiled template.");
}
return $object();
}
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 outputHtml(string $viewPath, array $variables) : ResponseInterface
#{
# if ( $this->response ?? false ) {
# if ( false === $content = $this->cache->handle($viewPath) ) {
#
# }
# $source = $this->compileSource($source ?? "test");
# $response = $this->response;
# return $response("abc");
# }
# throw new \InvalidArgumentException("No \Psr\Http\Message\ResponseInterface closure provided. Please provide one using the constructor or assigning it to the class variable `responseHtml`.");
#}
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, $compiledSource) = $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 ( $this->debug || ! $this->cache->compiled($viewPath) ) {
$context = $this->compileView($viewPath);
$this->cache->save($context);
if ( $context->extendFrom ) {
$this->fetchFromCache($context->extendFrom, $variables, $proxy);
}
}
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);
}
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 = $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;
}
}