Skip to content

Commit

Permalink
dynamic render tag
Browse files Browse the repository at this point in the history
  • Loading branch information
cappuc committed Dec 30, 2024
1 parent df0aa80 commit abbe1d9
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 7 deletions.
15 changes: 13 additions & 2 deletions src/Render/RenderContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,13 +312,24 @@ public function getTemplateName(): ?string
return $this->templateName;
}

public function loadPartial(string $templateName): Template
public function loadPartial(string $templateName, bool $parseIfMissing = false): Template
{
if ($partial = $this->sharedState->partialsCache->get($templateName)) {
return $partial;
}

throw new StandardException(sprintf("The partial '%s' has not be loaded during parsing", $templateName));
if (! $parseIfMissing) {
throw new StandardException(sprintf("The partial '%s' has not be loaded during parsing", $templateName));
}

$parseContext = $this->environment->newParseContext();

$template = $parseContext->loadPartial($templateName);

$this->sharedState->partialsCache->merge($parseContext->getPartialsCache());
$this->sharedState->outputs->merge($parseContext->getOutputs());

return $template;
}

public function mergePartialsCache(PartialsCache $partialsCache): RenderContext
Expand Down
17 changes: 17 additions & 0 deletions src/Tags/Custom/DynamicRenderTag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Keepsuit\Liquid\Tags\Custom;

use Keepsuit\Liquid\Parse\ExpressionParser;
use Keepsuit\Liquid\Tags\RenderTag;

/**
* @phpstan-import-type Expression from ExpressionParser
*/
class DynamicRenderTag extends RenderTag
{
protected function allowDynamicPartials(): bool
{
return true;
}
}
33 changes: 28 additions & 5 deletions src/Tags/RenderTag.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
*/
class RenderTag extends Tag implements CanBeStreamed, HasParseTreeVisitorChildren
{
protected string $templateNameExpression;
protected string|VariableLookup $templateNameExpression;

protected mixed $variableNameExpression;

Expand All @@ -48,6 +48,7 @@ public function parse(TagParseContext $context): static
$templateNameExpression = $context->params->expression();
$this->templateNameExpression = match (true) {
is_string($templateNameExpression) => $templateNameExpression,
$this->allowDynamicPartials() && $templateNameExpression instanceof VariableLookup => $templateNameExpression,
default => throw new SyntaxException('Template name must be a string'),
};

Expand Down Expand Up @@ -80,7 +81,9 @@ public function parse(TagParseContext $context): static

$context->params->assertEnd();

$context->getParseContext()->loadPartial($this->templateNameExpression);
if (is_string($this->templateNameExpression)) {
$context->getParseContext()->loadPartial($this->templateNameExpression);
}
});

return $this;
Expand All @@ -99,9 +102,10 @@ public function render(RenderContext $context): string

public function stream(RenderContext $context): \Generator
{
$partial = $context->loadPartial($this->templateNameExpression);
$partial = $this->loadPartial($context);
$templateName = $partial->name ?? '';

$contextVariableName = $this->aliasName ?? Arr::last(explode('/', $this->templateNameExpression));
$contextVariableName = $this->aliasName ?? Arr::last(explode('/', $templateName));
assert(is_string($contextVariableName));

$variable = $this->variableNameExpression ? $context->evaluate($this->variableNameExpression) : null;
Expand All @@ -110,7 +114,7 @@ public function stream(RenderContext $context): \Generator
$variable = $variable instanceof Traversable ? iterator_to_array($variable) : $variable;
assert(is_array($variable));

$forLoop = new ForLoopDrop($this->templateNameExpression, count($variable));
$forLoop = new ForLoopDrop($templateName, count($variable));

foreach ($variable as $value) {
$partialContext = $this->buildPartialContext($partial, $context, [
Expand Down Expand Up @@ -142,6 +146,20 @@ public function parseTreeVisitorChildren(): array
];
}

protected function loadPartial(RenderContext $context): Template
{
$templateName = $this->templateNameExpression;
if ($this->allowDynamicPartials() && $this->templateNameExpression instanceof VariableLookup) {
$templateName = $this->templateNameExpression->evaluate($context);
}

if (! is_string($templateName)) {
throw new SyntaxException('Template name must be a string');
}

return $context->loadPartial($templateName, parseIfMissing: $this->allowDynamicPartials());
}

protected function buildPartialContext(Template $partial, RenderContext $context, array $variables = []): RenderContext
{
$innerContext = $context->newIsolatedSubContext($partial->name);
Expand All @@ -156,4 +174,9 @@ protected function buildPartialContext(Template $partial, RenderContext $context

return $innerContext;
}

protected function allowDynamicPartials(): bool
{
return false;
}
}
20 changes: 20 additions & 0 deletions tests/Integration/Tags/Custom/DynamicRenderTag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

use Keepsuit\Liquid\EnvironmentFactory;
use Keepsuit\Liquid\Tests\Stubs\StubFileSystem;

test('dynamically template name', function () {
$environment = EnvironmentFactory::new()
->setFilesystem(new StubFileSystem(partials: ['snippet' => 'echo']))
->setRethrowErrors(true)
->build();

$environment->tagRegistry->register(\Keepsuit\Liquid\Tags\Custom\DynamicRenderTag::class);

expect($environment->tagRegistry->get('render'))
->toBe(\Keepsuit\Liquid\Tags\Custom\DynamicRenderTag::class);

$template = $environment->parseString("{% assign name = 'snippet' %}{% render name %}");

expect($template->render($environment->newRenderContext()))->toBe('echo');
});

0 comments on commit abbe1d9

Please sign in to comment.