- Added an URL extension which allows routes and URLs. - Fixed some bug within ClassTemplate
221 lines
7.2 KiB
PHP
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;
|
|
}
|
|
}
|