diff --git a/src/Latte/Essential/Blueprint.php b/src/Latte/Essential/Blueprint.php index 97d65c41d..acc0068d5 100644 --- a/src/Latte/Essential/Blueprint.php +++ b/src/Latte/Essential/Blueprint.php @@ -9,8 +9,6 @@ namespace Latte\Essential; -use Latte; -use Latte\Runtime\Template; use Nette\PhpGenerator as Php; @@ -20,24 +18,35 @@ */ final class Blueprint { - public function printClass(Template $template, ?string $name = null): void + public function generateTemplateClass( + array $params, + ?string $name = 'Template', + ?string $extends = null, + ): Php\ClassType { if (!class_exists(Php\ClassType::class)) { - throw new \LogicException('Nette PhpGenerator is required to print template, install package `nette/php-generator`.'); + throw new \LogicException('Nette PhpGenerator is required to generate blueprint, install package `nette/php-generator`.'); } - $name = $name ?: 'Template'; $namespace = new Php\PhpNamespace(Php\Helpers::extractNamespace($name)); $class = $namespace->addClass(Php\Helpers::extractShortName($name)); + if ($extends) { + if (!class_exists($extends)) { + throw new \LogicException("Blueprint error: Class '$extends' doesn't exist."); + } elseif ((new \ReflectionClass($extends))->isFinal()) { + throw new \LogicException("Blueprint error: Unable to extend final class $extends"); + } + $class->setExtends($extends); + $params = array_diff_key($params, get_class_vars($extends)); + } + $this->addProperties($class, $params); + return $class; + } - $this->addProperties($class, $template->getParameters()); - $functions = array_diff_key($template->global->fn->getAll(), (new Latte\Essential\CoreExtension)->getFunctions()); - $this->addFunctions($class, $functions); - $end = $this->printCanvas(); - $this->printHeader('Native types'); - $this->printCode((string) $namespace); - echo $end; + public function printClass(Php\ClassType $class): void + { + $this->printCode((string) $class->getNamespace()); } @@ -46,24 +55,16 @@ public function printClass(Template $template, ?string $name = null): void */ public function printVars(array $vars): void { - if (!class_exists(Php\Type::class)) { - throw new \LogicException('Nette PhpGenerator is required to print template, install package `nette/php-generator`.'); - } - $res = ''; foreach ($vars as $name => $value) { - if (str_starts_with($name, 'ʟ_')) { - continue; + if (!str_starts_with($name, 'ʟ_')) { + $type = $this->getType($value); + $res .= "{varType $type $$name}\n"; } - - $type = $this->getType($value); - $res .= "{varType $type $$name}\n"; } - $end = $this->printCanvas(); $this->printHeader('varPrint'); $this->printCode($res ?: 'No variables', 'latte'); - echo $end; } @@ -134,12 +135,17 @@ public function printParameters( } - public function printCanvas(): string + public function openCanvas(): void { echo ''; echo ''; echo "
\n"; - return "
\n"; + } + + + public function closeCanvas(): void + { + echo "\n"; } diff --git a/src/Latte/Essential/Nodes/TemplatePrintNode.php b/src/Latte/Essential/Nodes/TemplatePrintNode.php index be720a59b..2e0ba79b7 100644 --- a/src/Latte/Essential/Nodes/TemplatePrintNode.php +++ b/src/Latte/Essential/Nodes/TemplatePrintNode.php @@ -13,14 +13,13 @@ use Latte\Compiler\Nodes; use Latte\Compiler\Nodes\StatementNode; use Latte\Compiler\NodeTraverser; -use Latte\Compiler\PhpHelpers; use Latte\Compiler\PrintContext; use Latte\Compiler\Tag; use Latte\Compiler\Token; /** - * {templatePrint [ClassName]} + * {templatePrint [ParentClass]} */ class TemplatePrintNode extends StatementNode { @@ -37,7 +36,13 @@ public static function create(Tag $tag): static public function print(PrintContext $context): string { - return '(new Latte\Essential\Blueprint)->printClass($this, ' . PhpHelpers::dump($this->template) . '); exit;'; + return $context->format(<<<'XX' + $ʟ_bp = new Latte\Essential\Blueprint; + $ʟ_bp->openCanvas(); + $ʟ_bp->printClass($ʟ_bp->generateTemplateClass($this->getParameters(), extends: %dump)); + $ʟ_bp->endCanvas(); + exit; + XX, $this->template); } diff --git a/src/Latte/Essential/Nodes/VarPrintNode.php b/src/Latte/Essential/Nodes/VarPrintNode.php index 8efa80586..76ee38512 100644 --- a/src/Latte/Essential/Nodes/VarPrintNode.php +++ b/src/Latte/Essential/Nodes/VarPrintNode.php @@ -33,9 +33,16 @@ public static function create(Tag $tag): static public function print(PrintContext $context): string { - $vars = $this->all ? 'get_defined_vars()' + $vars = $this->all + ? 'get_defined_vars()' : 'array_diff_key(get_defined_vars(), $this->getParameters())'; - return "(new Latte\\Essential\\Blueprint)->printVars($vars); exit;"; + return <<openCanvas(); + \$ʟ_bp->printVars($vars); + \$ʟ_bp->endCanvas(); + exit; + XX; } diff --git a/tests/common/Blueprint.printClass.phpt b/tests/common/Blueprint.printClass.phpt new file mode 100644 index 000000000..878b3e7c0 --- /dev/null +++ b/tests/common/Blueprint.printClass.phpt @@ -0,0 +1,55 @@ +setLoader(new Latte\Loaders\StringLoader); +$latte->addFunction('Abc', function (stdClass $a, $b = 132) {}); + + +class ParentTemplate +{ + public $int; +} + +$params = ['int' => 123, 'unknown' => null]; + +$blueprint = new Latte\Essential\Blueprint; +ob_start(); +$blueprint->printClass($blueprint->generateTemplateClass($params)); +$res = ob_get_clean(); + +Assert::match( + <<<'XX' + %A%class Template + { + public int $int; + public mixed $unknown; + } + %A% + XX, + $res, +); + + +ob_start(); +$blueprint->printClass($blueprint->generateTemplateClass($params, name: Foo\Template::class, extends: ParentTemplate::class)); +$res = ob_get_clean(); + +Assert::match( + <<<'XX' + %A%namespace Foo; + + class Template extends \ParentTemplate + { + public mixed $unknown; + } + %A% + XX, + $res, +); diff --git a/tests/tags/printVars.phpt b/tests/common/Blueprint.printVars.phpt similarity index 68% rename from tests/tags/printVars.phpt rename to tests/common/Blueprint.printVars.phpt index 1a9214bf2..bd8316771 100644 --- a/tests/tags/printVars.phpt +++ b/tests/common/Blueprint.printVars.phpt @@ -7,9 +7,9 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -$printer = new Latte\Essential\Blueprint; +$blueprint = new Latte\Essential\Blueprint; ob_start(); -$printer->printVars(['int' => 123, 'unknown' => null]); +$blueprint->printVars(['int' => 123, 'unknown' => null]); $res = ob_get_clean(); Assert::match( diff --git a/tests/tags/printClass.phpt b/tests/tags/printClass.phpt deleted file mode 100644 index 65d739320..000000000 --- a/tests/tags/printClass.phpt +++ /dev/null @@ -1,35 +0,0 @@ -setLoader(new Latte\Loaders\StringLoader); -$latte->addFunction('Abc', function (stdClass $a, $b = 132) {}); - - -$template = $latte->createTemplate('', ['int' => 123, 'unknown' => null]); - -$printer = new Latte\Essential\Blueprint; -ob_start(); -$printer->printClass($template); -$res = ob_get_clean(); - -Assert::match( - <<<'XX' - %A%/** - * @method mixed Abc(stdClass $a, $b = 132) - */ - class Template - { - public int $int; - public mixed $unknown; - } - %A% - XX, - $res, -); diff --git a/tests/tags/templatePrint.phpt b/tests/tags/templatePrint.phpt index 6ce4fc722..7db667bda 100644 --- a/tests/tags/templatePrint.phpt +++ b/tests/tags/templatePrint.phpt @@ -22,7 +22,10 @@ Assert::match( { extract($this->params); - (new Latte\Essential\Blueprint)->printClass($this, null); + $ʟ_bp = new Latte\Essential\Blueprint; + $ʟ_bp->openCanvas(); + $ʟ_bp->printClass($ʟ_bp->generateTemplateClass($this->getParameters(), extends: null)); + $ʟ_bp->endCanvas(); exit; %A% XX, @@ -37,7 +40,10 @@ Assert::match( { extract($this->params); - (new Latte\Essential\Blueprint)->printClass($this, 'Foo'); + $ʟ_bp = new Latte\Essential\Blueprint; + $ʟ_bp->openCanvas(); + $ʟ_bp->printClass($ʟ_bp->generateTemplateClass($this->getParameters(), extends: 'Foo')); + $ʟ_bp->endCanvas(); exit; %A% XX,