Skip to content

Commit a3d339c

Browse files
committed
Fix runtime partial handling
1 parent 8e4f799 commit a3d339c

5 files changed

Lines changed: 63 additions & 36 deletions

File tree

src/Compiler.php

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -422,17 +422,14 @@ private function PartialStatement(PartialStatement $statement): string
422422
// appendContent opcode) and invoke the partial with an empty indent so its lines are
423423
// not additionally indented.
424424
if ($this->context->options->preventIndent && $statement->indent !== '') {
425-
return "$indent." . self::getRuntimeFunc('p', "\$cx, $p, $vars, 0, ''");
425+
return "$indent." . self::getRuntimeFunc('p', "\$cx, $p, $vars, null, ''");
426426
}
427427

428-
return self::getRuntimeFunc('p', "\$cx, $p, $vars, 0, $indent");
428+
return self::getRuntimeFunc('p', "\$cx, $p, $vars, null, $indent");
429429
}
430430

431431
private function PartialBlockStatement(PartialBlockStatement $statement): string
432432
{
433-
$this->context->partialBlockId++;
434-
$pid = $this->context->partialBlockId;
435-
436433
// Hoist inline partial registrations so they run before the partial is called.
437434
// Without this, inline partials defined in the block would only be registered when
438435
// {{> @partial-block}} is invoked, too late for partials that call them directly.
@@ -485,8 +482,7 @@ private function PartialBlockStatement(PartialBlockStatement $statement): string
485482
? [self::getRuntimeFunc('inFallback', "\$cx, " . self::quote($partialName) . ', ' . $bodyClosure)]
486483
: [];
487484
$parts = [...$hoistedParts, ...$fallbackParts,
488-
self::getRuntimeFunc('in', "\$cx, '@partial-block$pid', " . $bodyClosure),
489-
self::getRuntimeFunc('p', "\$cx, $p, $vars, $pid, ''"),
485+
self::getRuntimeFunc('p', "\$cx, $p, $vars, $bodyClosure, ''"),
490486
];
491487
return implode('.', $parts);
492488
}
@@ -617,7 +613,7 @@ private function PathExpression(PathExpression $expression): string
617613

618614
// @partial-block as variable: truthy when an active partial block exists
619615
if ($data && $depth === 0 && count($stringParts) === 1 && $stringParts[0] === 'partial-block') {
620-
return "isset(\$cx->partials['@partial-block' . \$cx->partialId]) ? true : null";
616+
return "isset(\$cx->partials['@partial-block']) ? true : null";
621617
}
622618

623619
// Check block params (depth-0, non-data, non-scoped paths only, not SubExpression-headed)

src/Context.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ public function __construct(
2020
public array $partialCode = [],
2121
public int $usedDynPartial = 0,
2222
public int $usedPBlock = 0,
23-
public int $partialBlockId = 0,
2423
public array $partials = [],
2524
public array $partialBlock = [],
2625
public array $inlinePartial = [],
@@ -37,7 +36,6 @@ public function merge(self $context): void
3736
$this->partialCode = $context->partialCode;
3837
$this->usedDynPartial = $context->usedDynPartial;
3938
$this->usedPBlock = $context->usedPBlock;
40-
$this->partialBlockId = $context->partialBlockId;
4139
$this->usedPartial = $context->usedPartial;
4240
}
4341
}

src/Runtime.php

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@ public static function createContext(mixed $context, array $options, array $comp
166166
partials: $parentCx->partials,
167167
depths: $parentCx->depths,
168168
data: $root,
169-
partialId: $parentCx->partialId,
170169
frame: $parentCx->frame,
171170
);
172171
}
@@ -366,17 +365,33 @@ public static function merge(mixed $a, mixed $b): mixed
366365
* @param array<string, mixed> $hash named hash overrides merged into the context
367366
* @param string $indent whitespace to prepend to each line of the partial's output
368367
*/
369-
public static function p(RuntimeContext $cx, string $name, mixed $context, array $hash, int $pid, string $indent): string
368+
public static function p(RuntimeContext $cx, string $name, mixed $context, array $hash, ?\Closure $partialBlock, string $indent): string
370369
{
371-
$pp = ($name === '@partial-block') ? $name . ($pid > 0 ? $pid : $cx->partialId) : $name;
372-
373-
$fn = $cx->partials[$pp] ?? null;
370+
$fn = $cx->partials[$name] ?? null;
374371
if ($fn === null) {
375372
throw new \Exception("The partial $name could not be found");
376373
}
377374

378-
$savedPartialId = $cx->partialId;
379-
$cx->partialId = ($name === '@partial-block') ? ($pid > 0 ? $pid : ($cx->partialId > 0 ? $cx->partialId - 1 : 0)) : $pid;
375+
if ($partialBlock !== null) {
376+
$currentBlock = $cx->partials['@partial-block'] ?? null;
377+
$cx->partials['@partial-block'] = static function (mixed $blockContext = null) use ($partialBlock, $currentBlock): string {
378+
$callingCx = self::$partialContext;
379+
assert($callingCx !== null);
380+
$saved = $callingCx->partials['@partial-block'] ?? null;
381+
if ($currentBlock !== null) {
382+
$callingCx->partials['@partial-block'] = $currentBlock;
383+
} else {
384+
unset($callingCx->partials['@partial-block']);
385+
}
386+
$result = $partialBlock($blockContext);
387+
if ($saved !== null) {
388+
$callingCx->partials['@partial-block'] = $saved;
389+
} else {
390+
unset($callingCx->partials['@partial-block']);
391+
}
392+
return $result;
393+
};
394+
}
380395

381396
$context = $hash ? static::merge($context, $hash) : $context;
382397
$prev = self::$partialContext;
@@ -385,8 +400,14 @@ public static function p(RuntimeContext $cx, string $name, mixed $context, array
385400
$result = $fn($context);
386401
} finally {
387402
self::$partialContext = $prev;
403+
if ($partialBlock !== null) {
404+
if ($currentBlock !== null) {
405+
$cx->partials['@partial-block'] = $currentBlock;
406+
} else {
407+
unset($cx->partials['@partial-block']);
408+
}
409+
}
388410
}
389-
$cx->partialId = $savedPartialId;
390411

391412
if ($indent !== '') {
392413
$lines = explode("\n", $result);
@@ -425,23 +446,7 @@ public static function inFallback(RuntimeContext $cx, string $name, \Closure $pa
425446
*/
426447
public static function in(RuntimeContext $cx, string $name, \Closure $partial): string
427448
{
428-
if (str_starts_with($name, '@partial-block')) {
429-
// Capture the outer partialId at registration time so that when this
430-
// block closure runs, any {{>@partial-block}} inside it resolves to
431-
// the correct outer partial block rather than following the pid-decrement chain.
432-
$outerPartialId = $cx->partialId;
433-
$cx->partials[$name] = function (mixed $context = null, array $options = []) use ($partial, $outerPartialId): string {
434-
$callingCx = self::$partialContext;
435-
assert($callingCx !== null);
436-
$savedId = $callingCx->partialId;
437-
$callingCx->partialId = $outerPartialId;
438-
$result = $partial($context, $options);
439-
$callingCx->partialId = $savedId;
440-
return $result;
441-
};
442-
} else {
443-
$cx->partials[$name] = $partial;
444-
}
449+
$cx->partials[$name] = $partial;
445450
return '';
446451
}
447452

src/RuntimeContext.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public function __construct(
1919
public array $partials = [],
2020
public array $depths = [],
2121
public array $data = [],
22-
public int $partialId = 0,
2322
public array $frame = [],
2423
) {}
2524
}

test.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
use DevTheorem\Handlebars\{Handlebars, Options};
4+
5+
require 'vendor/autoload.php';
6+
7+
$templateString = '{ {{#>outer}} {{#>innerBlock}} Hello {{/innerBlock}} {{>simple}} {{/outer}} }';
8+
$outerPartialTemplateString = '( {{#>nested}} « {{>@partial-block}} » {{/nested}} )';
9+
$nestedPartialTemplateString = '[ {{>@partial-block}} ]';
10+
$innerBlockPartialTemplateString = '< {{>@partial-block}} >';
11+
$simplePartialTemplateString = 'World!';
12+
13+
$template = Handlebars::compile($templateString, new Options(
14+
/*partials: [
15+
'outer' => $outerPartialTemplateString,
16+
'nested' => $nestedPartialTemplateString,
17+
'innerBlock' => $innerBlockPartialTemplateString,
18+
'simple' => $simplePartialTemplateString,
19+
],*/
20+
));
21+
22+
$outer = Handlebars::compile($outerPartialTemplateString);
23+
$nested = Handlebars::compile($nestedPartialTemplateString);
24+
$innerBlock = Handlebars::compile($innerBlockPartialTemplateString);
25+
$simple = Handlebars::compile($simplePartialTemplateString);
26+
27+
echo $template(null, [
28+
'partials' => ['outer' => $outer, 'nested' => $nested, 'innerBlock' => $innerBlock, 'simple' => $simple],
29+
]);

0 commit comments

Comments
 (0)