added traits support for the parent function

This commit is contained in:
Fabien Potencier
2011-09-22 12:03:40 +02:00
parent 56f82db1a1
commit d101a05976
9 changed files with 98 additions and 10 deletions
+1
View File
@@ -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)
+8 -4
View File
@@ -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.
+2 -2
View File
@@ -241,8 +241,8 @@ class Twig_ExpressionParser
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);
+10 -2
View File
@@ -152,17 +152,25 @@ class Twig_Node_Module extends Twig_Node
}
$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 {
+5
View File
@@ -234,6 +234,11 @@ class Twig_Parser implements Twig_ParserInterface
$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);
+6 -2
View File
@@ -23,6 +23,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
protected $parents;
protected $env;
protected $blocks;
protected $traits;
/**
* Constructor.
@@ -33,6 +34,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
{
$this->env = $env;
$this->blocks = array();
$this->traits = array();
}
/**
@@ -84,10 +86,12 @@ abstract class Twig_Template implements Twig_TemplateInterface
*/
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());
}
}
@@ -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
@@ -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
@@ -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