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,