Skip to content
Browse files

added traits support for the parent function

  • Loading branch information...
1 parent 56f82db commit d101a059764de6a2279a13f270b263280bcc218e @fabpot committed
View
1 CHANGELOG
@@ -1,6 +1,7 @@
* 1.3.0
* allowed empty templates to be used as traits
+ * added traits support for the "parent" function
* 1.2.0 (2011-09-13)
View
12 doc/templates.rst
@@ -1628,22 +1628,26 @@ is ignored. To avoid name conflicts, you can rename imported blocks:
{% block title %}{% endblock %}
{% block content %}{% endblock %}
-Renaming also allows you to simulate inheritance by calling the "parent" block
-(like what you would have done with ``parent()``):
+The ``parent()`` function automatically determines the correct inheritance
+tree, so it can be used when overriding a block defined in an imported
+template:
.. code-block:: jinja
{% extends "base.html" %}
- {% use "blocks.html" with sidebar as parent_sidebar %}
+ {% use "blocks.html" %}
{% block sidebar %}
- {{ block('parent_sidebar') }}
+ {{ parent() }}
{% endblock %}
{% block title %}{% endblock %}
{% block content %}{% endblock %}
+In this example, ``parent()`` will correctly call the ``sidebar`` block from
+the ``blocks.html`` template.
+
.. note::
You can use as many ``use`` statements as you want in any given template.
View
4 lib/Twig/ExpressionParser.php
@@ -241,8 +241,8 @@ public function getFunctionNode($name, $line)
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line);
}
- if (!$this->parser->getParent()) {
- throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend another one is forbidden', $line);
+ if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
+ throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line);
}
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
View
12 lib/Twig/Node/Module.php
@@ -152,17 +152,25 @@ protected function compileConstructor(Twig_Compiler $compiler)
}
$compiler
- ->write("\$this->blocks = array_merge(\n")
+ ->write("\$this->traits = array_merge(\n")
->indent()
;
for ($i = 0; $i < $countTraits; $i++) {
$compiler
- ->write(sprintf("\$_trait_%s_blocks,\n", $i))
+ ->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i))
;
}
$compiler
+ ->outdent()
+ ->write(");\n\n")
+ ;
+
+ $compiler
+ ->write("\$this->blocks = array_merge(\n")
+ ->indent()
+ ->write("\$this->traits,\n")
->write("array(\n")
;
} else {
View
5 lib/Twig/Parser.php
@@ -234,6 +234,11 @@ public function addTrait($trait)
$this->traits[] = $trait;
}
+ public function hasTraits()
+ {
+ return count($this->traits) > 0;
+ }
+
public function addImportedFunction($alias, $name, Twig_Node_Expression $node)
{
$this->importedFunctions[0][$alias] = array('name' => $name, 'node' => $node);
View
8 lib/Twig/Template.php
@@ -23,6 +23,7 @@
protected $parents;
protected $env;
protected $blocks;
+ protected $traits;
/**
* Constructor.
@@ -33,6 +34,7 @@ public function __construct(Twig_Environment $env)
{
$this->env = $env;
$this->blocks = array();
+ $this->traits = array();
}
/**
@@ -84,10 +86,12 @@ public function getParent(array $context)
*/
public function displayParentBlock($name, array $context, array $blocks = array())
{
- if (false !== $parent = $this->getParent($context)) {
+ if (isset($this->traits[$name])) {
+ $this->traits[$name][0]->displayBlock($name, $context, $blocks);
+ } elseif (false !== $parent = $this->getParent($context)) {
$parent->displayBlock($name, $context, $blocks);
} else {
- throw new Twig_Error_Runtime('This template has no parent', -1, $this->getTemplateName());
+ throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName());
}
}
View
8 test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends.test
@@ -0,0 +1,8 @@
+--TEST--
+"parent" tag
+--TEMPLATE--
+{% block content %}
+ {{ parent() }}
+{% endblock %}
+--EXCEPTION--
+Twig_Error_Syntax: Calling "parent" on a template that does not extend nor "use" another template is forbidden in "index.twig" at line 3
View
14 test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends_but_traits.test
@@ -0,0 +1,14 @@
+--TEST--
+"parent" tag
+--TEMPLATE--
+{% use 'foo.twig' %}
+
+{% block content %}
+ {{ parent() }}
+{% endblock %}
+--TEMPLATE(foo.twig)--
+{% block content %}BAR{% endblock %}
+--DATA--
+return array()
+--EXPECT--
+BAR
View
44 test/Twig/Tests/Fixtures/tags/inheritance/use.test
@@ -0,0 +1,44 @@
+--TEST--
+"parent" function
+--TEMPLATE--
+{% extends "parent.twig" %}
+
+{% use "use1.twig" %}
+{% use "use2.twig" %}
+
+{% block content_parent %}
+ {{ parent() }}
+{% endblock %}
+
+{% block content_use1 %}
+ {{ parent() }}
+{% endblock %}
+
+{% block content_use2 %}
+ {{ parent() }}
+{% endblock %}
+
+{% block content %}
+ {{ block('content_use1_only') }}
+ {{ block('content_use2_only') }}
+{% endblock %}
+--TEMPLATE(parent.twig)--
+{% block content_parent 'content_parent' %}
+{% block content_use1 'content_parent' %}
+{% block content_use2 'content_parent' %}
+{% block content '' %}
+--TEMPLATE(use1.twig)--
+{% block content_use1 'content_use1' %}
+{% block content_use2 'content_use1' %}
+{% block content_use1_only 'content_use1_only' %}
+--TEMPLATE(use2.twig)--
+{% block content_use2 'content_use2' %}
+{% block content_use2_only 'content_use2_only' %}
+--DATA--
+return array()
+--EXPECT--
+ content_parent
+ content_use1
+ content_use2
+ content_use1_only
+ content_use2_only

0 comments on commit d101a05

Please sign in to comment.
Something went wrong with that request. Please try again.