Skip to content

Commit e56cdfd

Browse files
committed
bug #4778 Fix null coalescing operator with imported macros (fabpot)
This PR was merged into the 3.x branch. Discussion ---------- Fix null coalescing operator with imported macros Closes #4776 When using the null coalescing operator with a macro imported via the `from` tag, the `TemplateVariable` node inside `MacroReferenceExpression` was deep-cloned, causing the clone to generate a different `$macros` key than the one assigned by `AssignTemplateVariable`. This resulted in a `Call to a member function hasMacro() on null` error. Commits ------- efa004c Fix null coalescing operator with imported macros
2 parents faa7e87 + efa004c commit e56cdfd

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

src/Node/Expression/MacroReferenceExpression.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ public function __construct(TemplateVariable $template, string $name, AbstractEx
2929
parent::__construct(['template' => $template, 'arguments' => $arguments], ['name' => $name], $lineno);
3030
}
3131

32+
public function __clone()
33+
{
34+
// The template node must not be deep-cloned because its name is
35+
// lazily generated during compilation and must stay in sync with
36+
// the AssignTemplateVariable that populates the $macros array.
37+
$template = $this->nodes['template'];
38+
parent::__clone();
39+
$this->nodes['template'] = $template;
40+
}
41+
3242
public function compile(Compiler $compiler): void
3343
{
3444
if ($this->definedTest) {

tests/TemplateTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,43 @@ public static function getRenderTemplateWithoutOutputData()
150150
];
151151
}
152152

153+
/**
154+
* @dataProvider getNullCoalesceWithImportedMacroData
155+
*/
156+
public function testNullCoalesceWithImportedMacro(array $templates, string $expected)
157+
{
158+
$twig = new Environment(new ArrayLoader($templates));
159+
160+
$this->assertSame($expected, trim($twig->render('index.twig')));
161+
}
162+
163+
public static function getNullCoalesceWithImportedMacroData(): array
164+
{
165+
return [
166+
'from import' => [
167+
[
168+
'index.twig' => '{% from "helper.twig" import foo %}{{ foo("bar") ?? "" }}',
169+
'helper.twig' => '{% macro foo(param) %}{{ param }}{% endmacro %}',
170+
],
171+
'bar',
172+
],
173+
'from import with undefined macro falls back' => [
174+
[
175+
'index.twig' => '{% from "helper.twig" import foo, nonexistent %}{{ nonexistent("bar") ?? "fallback" }}',
176+
'helper.twig' => '{% macro foo(param) %}{{ param }}{% endmacro %}',
177+
],
178+
'fallback',
179+
],
180+
'from import used multiple times' => [
181+
[
182+
'index.twig' => '{% from "helper.twig" import foo %}{{ foo("a") ?? "" }}-{{ foo("b") ?? "" }}',
183+
'helper.twig' => '{% macro foo(param) %}{{ param }}{% endmacro %}',
184+
],
185+
'a-b',
186+
],
187+
];
188+
}
189+
153190
public function testRenderBlockWithUndefinedBlock()
154191
{
155192
$twig = new Environment(new ArrayLoader());

0 commit comments

Comments
 (0)