mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-18 13:26:37 +00:00
Wrap dynamic parent expression errors
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
* Fix the `default` filter fallback emitting an undefined variable warning when it uses the null-safe operator
|
* Fix the `default` filter fallback emitting an undefined variable warning when it uses the null-safe operator
|
||||||
* Fix the `matches` operator silently treating PCRE execution errors as non-matches
|
* Fix the `matches` operator silently treating PCRE execution errors as non-matches
|
||||||
* Fix `TemplateWrapper::streamBlock()`, `TemplateWrapper::hasBlock()`, and `TemplateWrapper::getBlockNames()` omitting environment globals
|
* Fix `TemplateWrapper::streamBlock()`, `TemplateWrapper::hasBlock()`, and `TemplateWrapper::getBlockNames()` omitting environment globals
|
||||||
|
* Fix exceptions from dynamic parent expressions escaping without template context
|
||||||
* Add the `HtmlExtension::htmlAttrValue()` method to resolve a single HTML attribute value the way the `html_attr` function renders it
|
* Add the `HtmlExtension::htmlAttrValue()` method to resolve a single HTML attribute value the way the `html_attr` function renders it
|
||||||
* Fix `html_attr` JSON encoding a `Stringable` value in a `data-*` attribute instead of using its string representation
|
* Fix `html_attr` JSON encoding a `Stringable` value in a `data-*` attribute instead of using its string representation
|
||||||
* Add documentation comments to attach metadata to nodes (experimental)
|
* Add documentation comments to attach metadata to nodes (experimental)
|
||||||
|
|||||||
+7
-1
@@ -89,7 +89,13 @@ abstract class Template
|
|||||||
// resolved against a parent, or yieldBlock() into a pre-warmed instance).
|
// resolved against a parent, or yieldBlock() into a pre-warmed instance).
|
||||||
$this->ensureSecurityChecked();
|
$this->ensureSecurityChecked();
|
||||||
|
|
||||||
if (!$parent = $this->doGetParent($context)) {
|
try {
|
||||||
|
$parent = $this->doGetParent($context);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->handleException($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$parent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,13 @@ namespace Twig\Tests;
|
|||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use PHPUnit\Framework\Attributes\DataProvider;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Twig\Environment;
|
use Twig\Environment;
|
||||||
|
use Twig\Error\LoaderError;
|
||||||
|
use Twig\Error\RuntimeError;
|
||||||
use Twig\Loader\ArrayLoader;
|
use Twig\Loader\ArrayLoader;
|
||||||
|
use Twig\TwigFunction;
|
||||||
|
|
||||||
class TemplateWrapperTest extends TestCase
|
class TemplateWrapperTest extends TestCase
|
||||||
{
|
{
|
||||||
@@ -89,6 +93,52 @@ class TemplateWrapperTest extends TestCase
|
|||||||
$this->assertSame('FOOBAR', $streamed);
|
$this->assertSame('FOOBAR', $streamed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideDynamicParentFailures
|
||||||
|
*/
|
||||||
|
#[DataProvider('provideDynamicParentFailures')]
|
||||||
|
public function testDynamicParentFailuresAreWrapped(string $template, ?TwigFunction $function, string $previousException): void
|
||||||
|
{
|
||||||
|
$twig = new Environment(new ArrayLoader(['index' => $template]));
|
||||||
|
if (null !== $function) {
|
||||||
|
$twig->addFunction($function);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ([
|
||||||
|
'block introspection' => static fn () => $twig->load('index')->getBlockNames(),
|
||||||
|
'rendering' => static fn () => $twig->render('index'),
|
||||||
|
] as $entryPoint => $call) {
|
||||||
|
try {
|
||||||
|
$call();
|
||||||
|
$this->fail(\sprintf('Resolving the dynamic parent during %s must fail.', $entryPoint));
|
||||||
|
} catch (RuntimeError $e) {
|
||||||
|
$this->assertSame('index', $e->getSourceContext()->getName());
|
||||||
|
$this->assertSame(1, $e->getTemplateLine());
|
||||||
|
$this->assertInstanceOf($previousException, $e->getPrevious());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDynamicParentTwigErrorsAreNotWrapped(): void
|
||||||
|
{
|
||||||
|
$twig = new Environment(new ArrayLoader(['index' => '{% extends parent %}']));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$twig->load('index')->getBlockNames(['parent' => 'missing']);
|
||||||
|
$this->fail('Loading the dynamic parent must fail.');
|
||||||
|
} catch (LoaderError $e) {
|
||||||
|
$this->assertSame('index', $e->getSourceContext()->getName());
|
||||||
|
$this->assertSame(1, $e->getTemplateLine());
|
||||||
|
$this->assertNull($e->getPrevious());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function provideDynamicParentFailures(): iterable
|
||||||
|
{
|
||||||
|
yield 'missing parent variable' => ['{% extends parent %}', null, \TypeError::class];
|
||||||
|
yield 'exception thrown by parent expression' => ['{% extends boom() %}', new TwigFunction('boom', static function (): never { throw new \DomainException('kaboom'); }), \DomainException::class];
|
||||||
|
}
|
||||||
|
|
||||||
public function testRenderBlock(): void
|
public function testRenderBlock(): void
|
||||||
{
|
{
|
||||||
$twig = new Environment(new ArrayLoader([
|
$twig = new Environment(new ArrayLoader([
|
||||||
|
|||||||
Reference in New Issue
Block a user