added a way to ignore a missing template when using the "include" tag
authorFabien Potencier <fabien.potencier@gmail.com>
Sat, 27 Aug 2011 11:54:33 +0000 (13:54 +0200)
committerFabien Potencier <fabien.potencier@gmail.com>
Sat, 27 Aug 2011 12:02:05 +0000 (14:02 +0200)
CHANGELOG
doc/templates.rst
lib/Twig/Node/Include.php
lib/Twig/TokenParser/Include.php
test/Twig/Tests/Fixtures/tags/include/ignore_missing.test [new file with mode: 0644]
test/Twig/Tests/Node/IncludeTest.php

index a533074..f931328 100644 (file)
--- 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
index 9117dcd..b882e4b 100644 (file)
@@ -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
 ~~~~~~
 
index d740665..467749b 100644 (file)
@@ -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")
+            ;
+        }
     }
 }
index b939ed6..5415455 100644 (file)
@@ -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 (file)
index 0000000..24aed06
--- /dev/null
@@ -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--
index fd483f9..9d25ff2 100644 (file)
@@ -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, <<<EOF
 \$template = \$this->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, <<<EOF
+try {
+    \$this->env->loadTemplate("foo.twig")->display(array("foo" => true));
+} catch (Twig_Error_Loader \$e) {
+    // ignore missing template
+}
+EOF
+        );
+
         return $tests;
     }
 }