mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-18 13:26:37 +00:00
Merge branch '3.x' into 4.x
* 3.x: Clarify the exception message for nested block chains from another environment Report a clear error when using macros imported in a template body that was not rendered # Conflicts: # CHANGELOG # src/Template.php # tests/CallMacroTest.php
This commit is contained in:
+1
-1
@@ -44,7 +44,7 @@ final class BlockChain
|
||||
foreach ($templates as $template) {
|
||||
if ($template instanceof self) {
|
||||
if ($env !== $template->env) {
|
||||
throw new \LogicException('A block chain cannot contain templates from different Twig environments.');
|
||||
throw new \LogicException('A block chain cannot contain a block chain from a different Twig environment.');
|
||||
}
|
||||
|
||||
$this->templates[] = $template;
|
||||
|
||||
@@ -52,9 +52,11 @@ class MacroVariable extends AbstractExpression
|
||||
$compiler->raw('$this->getMacroNamespace()');
|
||||
} else {
|
||||
$compiler
|
||||
->raw('$macros[')
|
||||
->raw('($macros[')
|
||||
->string($name)
|
||||
->raw(']')
|
||||
->raw('] ?? $this->throwUninitializedMacroNamespace(')
|
||||
->repr($this->getTemplateLine())
|
||||
->raw('))')
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,6 +486,14 @@ abstract class Template
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected function throwUninitializedMacroNamespace(int $line): never
|
||||
{
|
||||
throw new RuntimeError(\sprintf('Macros imported in the body of template "%s" are not available because the body was not rendered; move the "import" or "from" tag inside the block or the macro that uses it.', $this->getTemplateName()), $line, $this->getSourceContext());
|
||||
}
|
||||
|
||||
private function handleException(\Throwable $error): never
|
||||
{
|
||||
if ($error instanceof Error) {
|
||||
|
||||
@@ -296,7 +296,7 @@ class BlockChainTest extends TestCase
|
||||
$other = new Environment(new ArrayLoader(['theme' => '']));
|
||||
|
||||
$this->expectException(\LogicException::class);
|
||||
$this->expectExceptionMessage('A block chain cannot contain templates from different Twig environments.');
|
||||
$this->expectExceptionMessage('A block chain cannot contain a block chain from a different Twig environment.');
|
||||
|
||||
new BlockChain($twig, [new BlockChain($other, ['theme'])]);
|
||||
}
|
||||
@@ -519,7 +519,8 @@ class BlockChainTest extends TestCase
|
||||
try {
|
||||
$chain->renderBlock('field', ['helper' => 'macros1']);
|
||||
$this->fail('Rendering an uninitialized import must fail.');
|
||||
} catch (RuntimeError) {
|
||||
} catch (RuntimeError $e) {
|
||||
$this->assertStringContainsString('Macros imported in the body of template "theme" are not available because the body was not rendered', $e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertSame('one', $twig->render('theme', ['helper' => 'macros1']));
|
||||
|
||||
@@ -134,6 +134,42 @@ class CallMacroTest extends TestCase
|
||||
$template->getMacroNamespace()->call('missing', [], [], 1, new Source('', 'index'));
|
||||
}
|
||||
|
||||
public function testRenderingABlockOnItsOwnReportsMacrosImportedInTheTemplateBody(): void
|
||||
{
|
||||
$template = $this->load([
|
||||
'index' => '{% import "macros" as helpers %}{% block field %}{{ helpers.label() }}{% endblock %}',
|
||||
'macros' => '{% macro label() %}label{% endmacro %}',
|
||||
]);
|
||||
|
||||
$this->expectException(RuntimeError::class);
|
||||
$this->expectExceptionMessage('Macros imported in the body of template "index" are not available because the body was not rendered; move the "import" or "from" tag inside the block or the macro that uses it in "index" at line 1.');
|
||||
|
||||
$template->renderBlock('field', []);
|
||||
}
|
||||
|
||||
public function testRenderingABlockOnItsOwnUsesMacrosImportedInTheBlock(): void
|
||||
{
|
||||
$template = $this->load([
|
||||
'index' => '{% block field %}{% import "macros" as helpers %}{{ helpers.label() }}{% endblock %}',
|
||||
'macros' => '{% macro label() %}label{% endmacro %}',
|
||||
]);
|
||||
|
||||
$this->assertSame('label', $template->renderBlock('field', []));
|
||||
}
|
||||
|
||||
public function testCallingAMacroOnItsOwnReportsMacrosImportedInTheTemplateBody(): void
|
||||
{
|
||||
$template = $this->load([
|
||||
'index' => '{% from "macros" import label %}{% macro row() %}{{ label() }}{% endmacro %}',
|
||||
'macros' => '{% macro label() %}label{% endmacro %}',
|
||||
]);
|
||||
|
||||
$this->expectException(RuntimeError::class);
|
||||
$this->expectExceptionMessage('Macros imported in the body of template "index" are not available because the body was not rendered');
|
||||
|
||||
$this->callMacro($template, 'row', []);
|
||||
}
|
||||
|
||||
private function callMacro(Template $template, string $name, array $arguments): mixed
|
||||
{
|
||||
return $template->getMacroNamespace()->call($name, $arguments, [], 1, new Source('', 'index'));
|
||||
|
||||
Reference in New Issue
Block a user