From c56dd32f571339bde32aab817548673fbe404add Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 27 Aug 2011 13:54:33 +0200 Subject: [PATCH] added a way to ignore a missing template when using the "include" tag --- CHANGELOG | 1 + doc/templates.rst | 18 ++++++++++++++++ lib/Twig/Node/Include.php | 22 ++++++++++++++++++- lib/Twig/TokenParser/Include.php | 10 ++++++++- .../Fixtures/tags/include/ignore_missing.test | 10 +++++++++ test/Twig/Tests/Node/IncludeTest.php | 22 ++++++++++++++----- 6 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 test/Twig/Tests/Fixtures/tags/include/ignore_missing.test diff --git a/CHANGELOG b/CHANGELOG index a533074..f931328 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 1.2.0 + * added a way to ignore a missing template when using the "include" tag ({% include "foo" ignore missing %}) * added support for an array of templates to the "include" tag ({% include ['foo', 'bar'] %}) * added support for bitwise operators in expressions * added the "attribute" function to allow getting dynamic attributes on variables diff --git a/doc/templates.rst b/doc/templates.rst index 9117dcd..b882e4b 100644 --- a/doc/templates.rst +++ b/doc/templates.rst @@ -878,13 +878,31 @@ directly:: $twig->loadTemplate('template.twig')->display(array('template' => $template)); .. versionadded:: 1.2 + The ``ignore missing`` feature has been added in Twig 1.2. + +You can mark an include with ``ignore missing`` in which case Twig will ignore +the statement if the template to be ignored does not exist. It has to be +placed just after the template name. Here some valid examples:: + +.. code-block:: jinja + + {% include "sidebar.html" ignore missing %} + {% include "sidebar.html" ignore missing with {'foo': 'bar} %} + {% include "sidebar.html" ignore missing only %} + +.. versionadded:: 1.2 The possibility to pass an array of templates has been added in Twig 1.2. You can also provide a list of templates that are checked for existence before inclusion. The first template that exists will be included:: +.. code-block:: jinja + {% include ['page_detailed.html', 'page.html'] %} +If ``ignore missing`` is given, it will fall back to rendering nothing if none +of the templates exist, otherwise it will throw an exception. + Import ~~~~~~ diff --git a/lib/Twig/Node/Include.php b/lib/Twig/Node/Include.php index d740665..467749b 100644 --- a/lib/Twig/Node/Include.php +++ b/lib/Twig/Node/Include.php @@ -18,9 +18,9 @@ */ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface { - public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $lineno, $tag = null) + public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) { - parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (Boolean) $only), $lineno, $tag); + parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (Boolean) $only, 'ignore_missing' => (Boolean) $ignoreMissing), $lineno, $tag); } /** @@ -32,6 +32,13 @@ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface { $compiler->addDebugInfo($this); + if ($this->getAttribute('ignore_missing')) { + $compiler + ->write("try {\n") + ->indent() + ; + } + if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) { $compiler ->write("\$this->env->loadTemplate(") @@ -66,5 +73,16 @@ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface } $compiler->raw(");\n"); + + if ($this->getAttribute('ignore_missing')) { + $compiler + ->outdent() + ->write("} catch (Twig_Error_Loader \$e) {\n") + ->indent() + ->write("// ignore missing template\n") + ->outdent() + ->write("}\n\n") + ; + } } } diff --git a/lib/Twig/TokenParser/Include.php b/lib/Twig/TokenParser/Include.php index b939ed6..5415455 100644 --- a/lib/Twig/TokenParser/Include.php +++ b/lib/Twig/TokenParser/Include.php @@ -32,6 +32,14 @@ class Twig_TokenParser_Include extends Twig_TokenParser { $expr = $this->parser->getExpressionParser()->parseExpression(); + $ignoreMissing = false; + if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'ignore')) { + $this->parser->getStream()->next(); + $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, 'missing'); + + $ignoreMissing = true; + } + $variables = null; if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'with')) { $this->parser->getStream()->next(); @@ -48,7 +56,7 @@ class Twig_TokenParser_Include extends Twig_TokenParser $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); - return new Twig_Node_Include($expr, $variables, $only, $token->getLine(), $this->getTag()); + return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); } /** diff --git a/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test b/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test new file mode 100644 index 0000000..24aed06 --- /dev/null +++ b/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test @@ -0,0 +1,10 @@ +--TEST-- +"include" tag +--TEMPLATE-- +{% include ["foo.twig", "bar.twig"] ignore missing %} +{% include "foo.twig" ignore missing %} +{% include "foo.twig" ignore missing with {} %} +{% include "foo.twig" ignore missing with {} only %} +--DATA-- +return array() +--EXPECT-- diff --git a/test/Twig/Tests/Node/IncludeTest.php b/test/Twig/Tests/Node/IncludeTest.php index fd483f9..9d25ff2 100644 --- a/test/Twig/Tests/Node/IncludeTest.php +++ b/test/Twig/Tests/Node/IncludeTest.php @@ -19,14 +19,14 @@ class Twig_Tests_Node_IncludeTest extends Twig_Tests_Node_TestCase public function testConstructor() { $expr = new Twig_Node_Expression_Constant('foo.twig', 0); - $node = new Twig_Node_Include($expr, null, false, 0); + $node = new Twig_Node_Include($expr, null, false, false, 0); $this->assertEquals(null, $node->getNode('variables')); $this->assertEquals($expr, $node->getNode('expr')); $this->assertFalse($node->getAttribute('only')); $vars = new Twig_Node_Expression_Array(array('foo' => new Twig_Node_Expression_Constant(true, 0)), 0); - $node = new Twig_Node_Include($expr, $vars, true, 0); + $node = new Twig_Node_Include($expr, $vars, true, false, 0); $this->assertEquals($vars, $node->getNode('variables')); $this->assertTrue($node->getAttribute('only')); } @@ -45,7 +45,7 @@ class Twig_Tests_Node_IncludeTest extends Twig_Tests_Node_TestCase $tests = array(); $expr = new Twig_Node_Expression_Constant('foo.twig', 0); - $node = new Twig_Node_Include($expr, null, false, 0); + $node = new Twig_Node_Include($expr, null, false, false, 0); $tests[] = array($node, '$this->env->loadTemplate("foo.twig")->display($context);'); $expr = new Twig_Node_Expression_Conditional( @@ -54,7 +54,7 @@ class Twig_Tests_Node_IncludeTest extends Twig_Tests_Node_TestCase new Twig_Node_Expression_Constant('foo', 0), 0 ); - $node = new Twig_Node_Include($expr, null, false, 0); + $node = new Twig_Node_Include($expr, null, false, false, 0); $tests[] = array($node, <<env->resolveTemplate(((true) ? ("foo") : ("foo"))); \$template->display(\$context); @@ -63,12 +63,22 @@ EOF $expr = new Twig_Node_Expression_Constant('foo.twig', 0); $vars = new Twig_Node_Expression_Array(array('foo' => new Twig_Node_Expression_Constant(true, 0)), 0); - $node = new Twig_Node_Include($expr, $vars, false, 0); + $node = new Twig_Node_Include($expr, $vars, false, false, 0); $tests[] = array($node, '$this->env->loadTemplate("foo.twig")->display(array_merge($context, array("foo" => true)));'); - $node = new Twig_Node_Include($expr, $vars, true, 0); + $node = new Twig_Node_Include($expr, $vars, true, false, 0); $tests[] = array($node, '$this->env->loadTemplate("foo.twig")->display(array("foo" => true));'); + $node = new Twig_Node_Include($expr, $vars, true, true, 0); + $tests[] = array($node, <<env->loadTemplate("foo.twig")->display(array("foo" => true)); +} catch (Twig_Error_Loader \$e) { + // ignore missing template +} +EOF + ); + return $tests; } } -- 1.7.2.5