mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-18 13:26:37 +00:00
Report a clear error when using macros imported in a template body that was not rendered
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# 3.29.0 (2026-XX-XX)
|
||||
|
||||
* Fix the PHP warning and cryptic error when a block or a macro rendered on its own uses macros imported in the template body
|
||||
* Fix `{% cache %}` always missing in the Symfony bundle when `framework.cache.app` uses a natively tag aware adapter
|
||||
* Fix the sandbox resolving `use` trait templates before checking that the `use` tag is allowed
|
||||
* Fix `html_attr` dropping `style` declarations whose value is `0`, `0.0` or `'0'`
|
||||
|
||||
@@ -33,9 +33,11 @@ class MacroVariable extends TempNameExpression
|
||||
$compiler->raw('$this->getMacroNamespace()');
|
||||
} else {
|
||||
$compiler
|
||||
->raw('$macros[')
|
||||
->raw('($macros[')
|
||||
->string($name)
|
||||
->raw(']')
|
||||
->raw('] ?? $this->throwUninitializedMacroNamespace(')
|
||||
->repr($this->getTemplateLine())
|
||||
->raw('))')
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,6 +559,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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-generated method to display the template with the given context.
|
||||
*
|
||||
|
||||
@@ -480,7 +480,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']));
|
||||
|
||||
@@ -197,6 +197,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', []);
|
||||
}
|
||||
|
||||
public function testDeprecatedCoreExtensionCallMacroAcceptsMacroNamespace(): void
|
||||
{
|
||||
$template = $this->load(['index' => '{% macro greet(name) %}Hi {{ name }}{% endmacro %}']);
|
||||
|
||||
Reference in New Issue
Block a user