- A lot of bugfixes made for this release.
This commit is contained in:
parent
4e909b2840
commit
8df38b568c
|
@ -20,6 +20,10 @@ if (! class_exists("%NAMESPACE%\%CLASSNAME%", false) ) {
|
|||
|
||||
public static $context;
|
||||
|
||||
public bool $rendering = false;
|
||||
|
||||
public bool $renderingInsideSection = false;
|
||||
|
||||
public function __construct(\Picea\Picea $picea, array $variablesList = [], ?object $thisProxy = null) {
|
||||
$this->picea = $picea;
|
||||
$this->variableList = $variablesList;
|
||||
|
@ -33,32 +37,49 @@ if (! class_exists("%NAMESPACE%\%CLASSNAME%", false) ) {
|
|||
|
||||
public function output(array $variablesList = []) : void
|
||||
{
|
||||
$this->rendering = true;
|
||||
|
||||
( function($___class__template, $___global_variables, $___variables, $picea) {
|
||||
extract($___global_variables);
|
||||
extract($___variables, \EXTR_OVERWRITE);
|
||||
?>%CONTENT%<?php
|
||||
} )->call($this->thisProxy ?? new class(){}, $this, $this->variableList, $variablesList, $this->picea);
|
||||
%PARENT_OUTPUT%
|
||||
|
||||
$this->rendering = false;
|
||||
}
|
||||
|
||||
public function renderSection($name) : void
|
||||
public function renderSection(string $name, bool $return = false) /*: string|void*/
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach([ 'prepend', 'default', 'append' ] as $item) {
|
||||
if ( ! is_array($this->sectionList[$name][$item]) ) continue;
|
||||
|
||||
usort($this->sectionList[$name][$item], fn($a, $b) => $a['order'] <=> $b['order']);
|
||||
|
||||
foreach($this->sectionList[$name][$item] as $section) {
|
||||
if ($return) {
|
||||
ob_start();
|
||||
}
|
||||
|
||||
$section['callback']();
|
||||
|
||||
if ($return) {
|
||||
$result[] = ob_get_clean();
|
||||
}
|
||||
|
||||
if ( $item === 'default' ) {
|
||||
break 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return ? implode("", $result) : "";
|
||||
}
|
||||
|
||||
public function exportFunctions() : void
|
||||
{
|
||||
static $caching = [];
|
||||
%FUNCTIONS%
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Picea;
|
||||
|
||||
use Picea\Extension\FunctionExtension;
|
||||
use Picea\Language\LanguageRegistration;
|
||||
|
||||
class Compiler
|
||||
|
@ -94,13 +95,35 @@ class Compiler
|
|||
|
||||
public function registerExtension(Extension\Extension $extension) : self
|
||||
{
|
||||
foreach($extension->tokens ?? (array) ( $extension->token ?? [] ) as $token) {
|
||||
$tokens = $extension->tokens ?? (array) ( $extension->token ?? [] );
|
||||
|
||||
foreach($tokens as $token) {
|
||||
$this->extensionList[$token] = $extension;
|
||||
}
|
||||
|
||||
if (! $tokens ) {
|
||||
$this->extensionList[] = $extension;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function registerExtensionsFunctions(Compiler\Context $context) : void
|
||||
{
|
||||
foreach($this->extensionList as $ext) {
|
||||
if ($ext instanceof FunctionExtension) {
|
||||
foreach ($ext->exportFunctions() as $name => $value) {
|
||||
if ( is_string($value) ) {
|
||||
$callable = fn(...$args) => call_user_func_array([ $ext, $value ], $args);
|
||||
}
|
||||
|
||||
$context->pushFunction(is_numeric($name) ? $value : $name, $callable ?? $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getExtensionFromToken(string $name) : Extension\Extension
|
||||
{
|
||||
if ( false === $this->extensionList[$name] ?? false ) {
|
||||
|
|
|
@ -54,11 +54,17 @@ abstract class Context {
|
|||
|
||||
public function renderFunctions() : string
|
||||
{
|
||||
$cls = $this->compiledClassPath();
|
||||
$ns = $this->namespace ? "\\{$this->namespace}\\" : "";
|
||||
if ($this->extendFrom) {
|
||||
return "parent::exportFunctions();";
|
||||
}
|
||||
else {
|
||||
$cls = $this->compiledClassPath();
|
||||
$ns = $this->namespace ? "\\{$this->namespace}\\" : "";
|
||||
|
||||
foreach($this->functionStack as $name => $function) {
|
||||
$list[] = <<<FUNC
|
||||
$list = ['static $caching = [];'];
|
||||
|
||||
foreach ($this->functionStack as $name => $function) {
|
||||
$list[] = <<<FUNC
|
||||
if ( false === ( ( \$caching['$ns$name'] ?? false) || function_exists( '$ns$name' ) ) ) {
|
||||
\$caching['$ns$name'] = true;
|
||||
|
||||
|
@ -67,9 +73,10 @@ abstract class Context {
|
|||
}
|
||||
}
|
||||
FUNC;
|
||||
}
|
||||
}
|
||||
|
||||
return implode(PHP_EOL, $list);
|
||||
return implode(PHP_EOL, $list);
|
||||
}
|
||||
}
|
||||
|
||||
public function exportFunctions() : void
|
||||
|
|
|
@ -29,7 +29,10 @@ class BlockToken implements ControlStructure {
|
|||
unset(\$inlineVariables);
|
||||
}
|
||||
catch(\TypeError \$ex) {
|
||||
throw new \Exception('A block awaiting arguments `$arguments` instead received `' . implode(', ', array_map('gettype', \$inlineVariables)) . '`');
|
||||
|
||||
throw new \Exception(
|
||||
sprintf('A block awaiting arguments `%s` instead received `%s` with values `%s`', '$arguments', implode(', ', array_map('gettype', \$inlineVariables)), json_encode(\$inlineVariables))
|
||||
);
|
||||
}
|
||||
?>
|
||||
PHP;
|
||||
|
|
|
@ -20,6 +20,10 @@ class ForToken implements ControlStructure {
|
|||
return "<?php for ($arguments): {$uid} = 1; ?>";
|
||||
|
||||
case "endfor":
|
||||
if ( $context->iterationStack === null ){
|
||||
|
||||
}
|
||||
|
||||
if ( end($context->iterationStack)['or'] === false ) {
|
||||
$output = "<?php endfor; ?>";
|
||||
}
|
||||
|
@ -30,6 +34,9 @@ class ForToken implements ControlStructure {
|
|||
array_pop($context->iterationStack);
|
||||
|
||||
return $output;
|
||||
|
||||
case "continue":
|
||||
return "<?php continue; ?>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,13 @@ namespace Picea\ControlStructure;
|
|||
|
||||
class ForeachToken implements ControlStructure {
|
||||
|
||||
public array $token = [ "foreach", "endforeach" ];
|
||||
public array $token = [ "foreach", "endforeach", "continue" ];
|
||||
|
||||
public function parse(/*\Picae\Compiler\Context*/ &$context, ?string $arguments, string $token) {
|
||||
switch($token) {
|
||||
case "continue":
|
||||
return "<?php continue; ?>";
|
||||
|
||||
case "foreach":
|
||||
$name = "$".uniqid("foreach_");
|
||||
|
||||
|
@ -27,7 +30,7 @@ class ForeachToken implements ControlStructure {
|
|||
'token' => 'endforeach',
|
||||
];
|
||||
|
||||
return "<?php foreach ($arguments): $name = ( $name ?? 0 ) + 1; ; ?>";
|
||||
return "<?php foreach ($arguments): $name = ( $name ?? 0 ) + 1; ?>";
|
||||
|
||||
case "endforeach":
|
||||
if ( end($context->iterationStack)['or'] === false ) {
|
||||
|
|
|
@ -47,13 +47,13 @@ class SectionToken implements ControlStructure {
|
|||
|
||||
return "<?php \$___class__template->sectionList[$name] ??= [ 'prepend' => [], 'append' => [], 'default' => [] ];".
|
||||
"\$___class__template->sectionList[$name]['$action'][] = [ 'order' => $order, 'callback' => function() use (\$picea, \$___class__template, \$___global_variables, \$___variables) {".
|
||||
"extract(\$___global_variables); extract(\$___variables, \EXTR_OVERWRITE); ?>";
|
||||
"extract(\$___global_variables); extract(\$___variables, \EXTR_OVERWRITE); \$___class__template->sectionStack[] = '$name'; ?>";
|
||||
}
|
||||
|
||||
protected function printEndSection($context) : string
|
||||
{
|
||||
$section = array_pop($context->sections);
|
||||
$build = $context->extendFrom ? "" : "\$___class__template->renderSection({$section['name']});";
|
||||
return "<?php }]; $build?>";
|
||||
$build = $context->extendFrom ? "\$___class__template->sectionStack && \$___class__template->renderSection({$section['name']});" : "\$___class__template->renderSection({$section['name']});";
|
||||
return "<?php array_pop(\$___class__template->sectionStack); }]; $build?>";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Picea\Extension;
|
||||
|
||||
use Picea\Compiler\Context;
|
||||
|
||||
interface FunctionExtension
|
||||
{
|
||||
public function exportFunctions() : array;
|
||||
}
|
|
@ -4,38 +4,35 @@ namespace Picea\Extension;
|
|||
|
||||
use Picea\Compiler\Context;
|
||||
|
||||
class JsonExtension implements Extension {
|
||||
class JsonExtension implements Extension, FunctionExtension {
|
||||
|
||||
public array $token = [ "json", "json.pretty" ];
|
||||
|
||||
public int $flags = JSON_HEX_TAG | \JSON_HEX_APOS | \JSON_HEX_QUOT | \JSON_THROW_ON_ERROR;
|
||||
|
||||
public function __construct(? Context $context = null) {
|
||||
if ($context) {
|
||||
$this->register($context);
|
||||
}
|
||||
}
|
||||
|
||||
public function parse(/*\Picae\Compiler\Context*/ &$context, ?string $arguments, string $token)
|
||||
|
||||
public function parse(/*\Picae\Compiler\Context*/ &$context, ?string $arguments, string $token)
|
||||
{
|
||||
$flag = $this->flags;
|
||||
|
||||
|
||||
switch ($token) {
|
||||
case "json.pretty":
|
||||
$flag |= \JSON_PRETTY_PRINT;
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case "json.html":
|
||||
return "<?php echo htmlentities(json_encode($arguments, {$this->flags}), ENT_QUOTES, 'UTF-8') ?>";
|
||||
}
|
||||
|
||||
return "<?php echo json_encode($arguments, $flag) ?>";
|
||||
}
|
||||
|
||||
public function register(Context $context) : void
|
||||
|
||||
public function exportFunctions(): array
|
||||
{
|
||||
$context->pushFunction("json", function($arguments, ? int $flags = null) {
|
||||
return json_encode($arguments, \JSON_FORCE_OBJECT);
|
||||
});
|
||||
return [
|
||||
'json' => function($arguments, ? int $flags = null) {
|
||||
return json_encode($arguments, \JSON_FORCE_OBJECT);
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace Picea\Extension;
|
|||
|
||||
use Picea\Compiler\Context;
|
||||
|
||||
class LanguageExtension implements Extension {
|
||||
class LanguageExtension implements Extension, FunctionExtension {
|
||||
|
||||
public array $tokens = [ "lang", "_", "language.set" ];
|
||||
|
||||
|
@ -12,11 +12,18 @@ class LanguageExtension implements Extension {
|
|||
|
||||
protected LanguageHandler $languageHandler;
|
||||
|
||||
public function __construct(Context $context, LanguageHandler $handler) {
|
||||
$this->register($context);
|
||||
public function __construct(LanguageHandler $handler) {
|
||||
$this->languageHandler = $handler;
|
||||
}
|
||||
|
||||
public function exportFunctions(): array
|
||||
{
|
||||
return [
|
||||
'_' => 'relativeLang',
|
||||
'lang' => 'absoluteLang',
|
||||
];
|
||||
}
|
||||
|
||||
public function parse(/*\Picae\Compiler\Context*/ &$context, ?string $arguments, string $token) : string
|
||||
{
|
||||
switch($token) {
|
||||
|
@ -35,8 +42,6 @@ class LanguageExtension implements Extension {
|
|||
|
||||
public function register(Context $context) : void
|
||||
{
|
||||
$context->pushFunction("_", [ $this, 'relativeLang' ]);
|
||||
$context->pushFunction("lang", [ $this, 'absoluteLang' ]);
|
||||
}
|
||||
|
||||
public function relativeLang(string $key, array $variables = []) #: array|string
|
||||
|
|
|
@ -14,7 +14,7 @@ class UrlExtension implements Extension {
|
|||
|
||||
protected array $routesTarget;
|
||||
|
||||
public array $tokens = [ "url" , "route", "asset", "url.parameters" ];
|
||||
public array $tokens = [ "url" , "route", "asset", "url.current", "url.parameters" ];
|
||||
|
||||
public function __construct(Context $context, string $urlBase = "", string $assetToken = "") {
|
||||
$this->urlBase = trim($urlBase, "/");
|
||||
|
@ -33,7 +33,10 @@ class UrlExtension implements Extension {
|
|||
|
||||
case "url":
|
||||
return "<?php echo \$picea->compiler->getExtensionFromToken('$token')->buildUrl($arguments) ?>";
|
||||
|
||||
|
||||
case "url.current":
|
||||
return "<?php echo \$picea->compiler->getExtensionFromToken('$token')->currentUrl($arguments) ?>";
|
||||
|
||||
case "url.parameters":
|
||||
return "<?php echo \$picea->compiler->getExtensionFromToken('$token')->setUrlParameters($arguments) ?>";
|
||||
}
|
||||
|
@ -44,6 +47,7 @@ class UrlExtension implements Extension {
|
|||
public function register(Context $context) : void
|
||||
{
|
||||
$context->pushFunction("url", [ $this, 'buildUrl' ]);
|
||||
$context->pushFunction("current_url", [ $this, 'currentUrl' ]);
|
||||
$context->pushFunction("asset", [ $this, 'buildAssetUrl' ]);
|
||||
$context->pushFunction("route", [ $this, 'buildRouteUrl' ]);
|
||||
}
|
||||
|
@ -58,6 +62,11 @@ class UrlExtension implements Extension {
|
|||
return $url . ( $parameters ? "?" . http_build_query($parameters) : "" );
|
||||
}
|
||||
|
||||
public function currentUrl(array $parameters = []) : string
|
||||
{
|
||||
return $this->buildUrl($this->uri(), $parameters);
|
||||
}
|
||||
|
||||
public function buildUrl(string $uri = "", array $parameters = []) : string
|
||||
{
|
||||
return $this->setUrlParameters($this->url() . "/" . ltrim($uri, "/"), $parameters);
|
||||
|
@ -108,11 +117,7 @@ class UrlExtension implements Extension {
|
|||
$uri = explode('?', $uri, 2)[0];
|
||||
}
|
||||
|
||||
if ( ($base = $this->config['base'] ?? false) && ( stripos($uri, $base) === 0 ) ) {
|
||||
$uri = substr($uri, strlen($base));
|
||||
}
|
||||
|
||||
return '/' . ltrim($uri, '/');
|
||||
return '/' . ltrim(substr($uri, strlen($this->base())), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -177,23 +182,23 @@ class UrlExtension implements Extension {
|
|||
if (strpos($item[1], "=") !== false) {
|
||||
list($variable, $default) = explode('=', $item[1]);
|
||||
}
|
||||
elseif (strpos($item[1], ":") !== false) {
|
||||
list($variable, ) = explode(':', $item[1]);
|
||||
}
|
||||
else {
|
||||
$variable = $item[1];
|
||||
}
|
||||
|
||||
|
||||
if ( array_key_exists($variable, $arguments) ) {
|
||||
$value = $arguments[ $item[1] ];
|
||||
}
|
||||
else if ( isset($default) ) {
|
||||
$value = ""; # $default;
|
||||
$value = $arguments[ $variable ];
|
||||
unset($arguments[ $variable ]);
|
||||
}
|
||||
else {
|
||||
$variable = $item[1];
|
||||
$value = $default ?? "";
|
||||
}
|
||||
|
||||
$search[ $item[0] ] = $value;
|
||||
|
||||
unset($arguments[ $item[1] ]);
|
||||
}
|
||||
|
||||
$route = str_replace(array_keys($search), array_values($search), $route);
|
||||
|
|
|
@ -4,8 +4,6 @@ namespace Picea\Language;
|
|||
|
||||
use Picea\Compiler;
|
||||
|
||||
use Picea\Compiler\Context;
|
||||
|
||||
class DefaultRegistrations implements LanguageRegistration
|
||||
{
|
||||
protected array $extensions;
|
||||
|
@ -13,12 +11,9 @@ class DefaultRegistrations implements LanguageRegistration
|
|||
protected array $syntaxes;
|
||||
|
||||
protected array $controlStructures;
|
||||
|
||||
protected ? Context $context;
|
||||
|
||||
public function __construct(? Context $context = null, array $extensions = [], array $syntaxes = [], array $controlStructure = [])
|
||||
|
||||
public function __construct(array $extensions = [], array $syntaxes = [], array $controlStructure = [])
|
||||
{
|
||||
$this->context = $context;
|
||||
$this->extensions = $extensions;
|
||||
$this->syntaxes = $syntaxes;
|
||||
$this->controlStructures = $controlStructure;
|
||||
|
@ -69,8 +64,8 @@ class DefaultRegistrations implements LanguageRegistration
|
|||
{
|
||||
$compiler->registerExtension(new \Picea\Extension\PhpExtension());
|
||||
$compiler->registerExtension(new \Picea\Extension\PrintExtension());
|
||||
$compiler->registerExtension(new \Picea\Extension\JsonExtension($this->context));
|
||||
|
||||
$compiler->registerExtension(new \Picea\Extension\JsonExtension());
|
||||
|
||||
foreach($this->extensions ?? [] as $extension) {
|
||||
$compiler->registerExtension($extension);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,10 @@ class Picea implements LanguageRegistration
|
|||
|
||||
public array $loadedTemplateFile = [];
|
||||
|
||||
public array $globalVariables = [];
|
||||
|
||||
public array $compiled = [];
|
||||
|
||||
public function __construct(
|
||||
? Closure $responseHtml = null,
|
||||
? Compiler\Context $context = null,
|
||||
|
@ -48,19 +52,25 @@ class Picea implements LanguageRegistration
|
|||
$this->compiler = $compiler ?? $this->instanciateCompiler();
|
||||
$this->fileFetcher = $fileFetcher ?? $this->instanciateFileFetcher();
|
||||
$this->debug = $debug;
|
||||
|
||||
#$this->context->exportFunctions();
|
||||
|
||||
$this->compiler->registerExtensionsFunctions($this->context);
|
||||
|
||||
$this->renderContext($this->context);
|
||||
}
|
||||
|
||||
public function gatherTemplateObject(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
|
||||
{
|
||||
if ( null === $object = $this->fetchFromCache($viewPath, $variables, $proxy) ) {
|
||||
throw new \RuntimeException("An error occured while trying to save a compiled template.");
|
||||
}
|
||||
|
||||
try {
|
||||
return $object();
|
||||
return call_user_func($this->gatherTemplateObject($viewPath, $variables, $proxy));
|
||||
}
|
||||
catch(\Throwable $ex) {
|
||||
# Temporary class for an experiment
|
||||
|
@ -120,11 +130,11 @@ class Picea implements LanguageRegistration
|
|||
* @return type
|
||||
*/
|
||||
public function inlineHtml(? object $proxy, string $viewPath, array $variables) {
|
||||
return $this->renderHtml($viewPath, $variables, $proxy);
|
||||
return $this->renderHtml($viewPath, $this->globalVariables + $variables, $proxy);
|
||||
}
|
||||
|
||||
public function inlineBlock(? object $proxy, string $viewPath, ... $variables) {
|
||||
return $this->renderHtml($viewPath, [ 'inlineVariables' => $variables ], $proxy);
|
||||
return $this->renderHtml($viewPath, [ 'inlineVariables' => $this->globalVariables + $variables ], $proxy);
|
||||
}
|
||||
|
||||
public function inlineContent(string $viewPath) {
|
||||
|
@ -187,13 +197,15 @@ class Picea implements LanguageRegistration
|
|||
|
||||
public function fetchFromCache(string $viewPath, array $variables = [], ?object $proxy = null) : ?object
|
||||
{
|
||||
if ( ( true === $this->debug ) || (! $this->cache->compiled($viewPath))) {
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue