slotDefinitions(); return ""; case "endblock": return "render(\$___class__template); unset(\$___block); ?>"; case "arguments": $class = static::class; return <<using ?? [], \EXTR_OVERWRITE); extract( \\$class::parseArguments(function($arguments) {}, \$inlineVariables), \EXTR_OVERWRITE); unset(\$inlineVariables); } catch(\TypeError \$ex) { throw new \Exception( sprintf('A block awaiting arguments `%s` instead received `%s` with values `%s`', '$arguments', implode(', ', array_map('gettype', \$inlineVariables ?? [])), json_encode(\$inlineVariables)) ); } /*%EXCEPTION_LINE_BASE%*/?> PHP; case "define": list($name, $definition) = array_pad(explode(',', $arguments, 2), 2, ""); end($slotDefinitions)->setDefinition(eval("return $name;"), $definition); return <<defineSlot($name, function($definition) {}); ?> PHP; case "slot": $def = end($slotDefinitions); list($name, $definition) = array_pad(explode(',', $arguments, 2), 2, ""); $loops = count($context->iterationStack ?? []) ? ",". implode(', ', array_filter(array_column($context->iterationStack, 'uid'), fn($e) => strpos($e, '[') === false)) : null; if ($def->hasDefinitions() ) { $slotName = eval("return $name;"); $def->currentSlot = $slotName; $def->setDefinitionVars($slotName, $definition); $definition = $def->printDefinition($slotName); if ($definition) { $definition .= ","; } return <<printSlot($name, function($definition array \$___using = []) use (\$picea $loops) { extract(\$___using, \EXTR_SKIP); ?> PHP; } else { if ($definition) { $definition .= ","; } return <<slotIsSet($name) || \$___block->setSlot($name, function($definition array \$___using = []) use (\$picea $loops) { extract(\$___using, \EXTR_SKIP); ?> PHP; } case "endslot": $def =end($slotDefinitions); if ($def->hasDefinitions() ) { $definition = $def->getCurrentSlotDefinitionVars(); if ($definition) { $definition .= ","; } return <<call(\$this, $definition array_merge(get_defined_vars(), \$this->using)); ?> PHP; } else { return ""; } case "using": return "setUsing($arguments); ?>"; } } public function inlineHtml(? object $proxy, string $viewPath, ... $variables) { return $this->renderHtml($viewPath, [ 'inlineVariables' => $variables ], $proxy); } public static function parseSlotArguments(Callable $method) : array { #return } public static function parseArguments(Callable $method, array $arguments) : array { try{ call_user_func_array($method, $arguments); } catch(\TypeError $ex) { throw $ex; } $parameters = []; foreach((new \ReflectionFunction($method))->getParameters() as $key => $value) { if ( isset($arguments[$key]) ) { $parameters[ $value->getName() ] = $arguments[$key]; } elseif ( $value->isDefaultValueAvailable() ) { $parameters[ $value->getName() ] = $value->getDefaultValue(); } elseif ( $value->isVariadic() ) { $parameters[ $value->getName() ] = []; } else { $parameters[ $value->getName() ] = null; } } return $parameters; } public static function slotDefinitions() { return new class() { public array $definitions = []; public array $variables = []; public bool $rendering = false; public string $currentSlot; public function setDefinition(string $name, string $definition) : self { $this->definitions[$name] = $definition; return $this; } public function setDefinitionVars(string $name, string $variables) : self { $this->variables[$name] = $variables; return $this; } public function getDefinitionVars(string $name) : string { return $this->variables[$name] ?? ""; } public function getCurrentSlotDefinitionVars() : string { return $this->getDefinitionVars($this->currentSlot); } public function hasDefinitions() : bool { return count($this->definitions) > 0; } public function printDefinition(string $name) : string { if ( ! isset($this->definitions[$name]) ) { throw new \Exception("Slot definition for `$name` was not found. Have you defined it in your block header ?"); } return $this->definitions[$name]; } public function render() : void { $this->rendering = true; } }; } public static function instanciateBlock(string $viewPath, ... $arguments) { return new class($viewPath, ...$arguments) { public bool $rendering = false; public string $viewPath; public array $using = []; public array $arguments = []; public array $slots = []; public array $definition = []; public function __construct(string $viewPath, ...$arguments) { $this->viewPath = $viewPath; $this->arguments = $arguments; } public function render(object $classTemplate) : string { $this->rendering = true; return $classTemplate->picea->inlineBlock($this, $this->viewPath, ...$this->arguments); } public function setSlot(string $name, Callable $method) : void { $this->slots[$name] = $method; } public function defineSlot(string $name, Callable $method) : void { $this->definition[$name] = $method; } public function slotIsSet(string $name) : bool { return ! empty($this->slots[$name]); } public function printSlot(string $name, Callable $default) { return $this->slotIsSet($name) ? $this->slots[$name] : $default; } public function setUsing(array $variables) { $this->using = $variables; } }; } }