Merge branch '1.x' into 2.x

* 1.x:
  exposed a way to access template data and methods in a portable way
  removed optimization as it's not compatible with Symfony cache system
This commit is contained in:
Fabien Potencier
2016-11-15 16:57:15 -05:00
10 changed files with 270 additions and 23 deletions
+1
View File
@@ -19,6 +19,7 @@
* 1.28.0 (2016-XX-XX)
* exposed a way to access template data and methods in a portable way
* changed context access to use the PHP 7 null coalescing operator when available
* added the "with" tag
* added support for a custom template on the block() function
+19 -3
View File
@@ -42,10 +42,18 @@ templates from a database or other resources.
the evaluated templates. For such a need, you can use any available PHP
cache library.
To load a template from this environment you just have to call the
``loadTemplate()`` method which then returns a ``Twig_Template`` instance::
Rendering Templates
-------------------
$template = $twig->loadTemplate('index.html');
To load a template from a Twig environment, call the ``load()`` method which
returns a ``Twig_TemplateWrapper`` instance::
$template = $twig->load('index.html');
.. note::
Before Twig 1.28, you should use ``loadTemplate()`` instead which returns a
``Twig_Template`` instance.
To render the template with some variables, call the ``render()`` method::
@@ -59,6 +67,14 @@ You can also load and render the template in one fell swoop::
echo $twig->render('index.html', array('the' => 'variables', 'go' => 'here'));
.. versionadded:: 1.28
The possibility to render blocks from the API was added in Twig 1.28.
If a template defines blocks, they can be rendered individually via the
``renderBlock()`` call::
echo $template->renderBlock('block_name', array('the' => 'variables', 'go' => 'here'));
.. _environment_options:
Environment Options
+7 -3
View File
@@ -34,14 +34,18 @@ You can disable access to the context by setting ``with_context`` to
{# no variables will be accessible #}
{{ include('template.html', with_context = false) }}
And if the expression evaluates to a ``Twig_Template`` object, Twig will use it
directly::
And if the expression evaluates to a ``Twig_Template`` or a
``Twig_TemplateWrapper`` instance, Twig will use it directly::
// {{ include(template) }}
// deprecated as of Twig 1.28
$template = $twig->loadTemplate('some_template.twig');
$twig->loadTemplate('template.twig')->display(array('template' => $template));
// as of Twig 1.28
$template = $twig->load('some_template.twig');
$twig->display('template.twig', array('template' => $template));
When you set the ``ignore_missing`` flag, Twig will return an empty string if
the template does not exist:
+6 -2
View File
@@ -153,13 +153,17 @@ Twig supports dynamic inheritance by using a variable as the base template:
{% extends some_var %}
If the variable evaluates to a ``Twig_Template`` object, Twig will use it as
the parent template::
If the variable evaluates to a ``Twig_Template`` or a ``Twig_TemplateWraper``
instance, Twig will use it as the parent template::
// {% extends layout %}
// deprecated as of Twig 1.28
$layout = $twig->loadTemplate('some_layout_template.twig');
// as of Twig 1.28
$layout = $twig->load('some_layout_template.twig');
$twig->display('template.twig', array('layout' => $layout));
You can also provide a list of templates that are checked for existence. The
+7 -3
View File
@@ -50,14 +50,18 @@ The template name can be any valid Twig expression:
{% include some_var %}
{% include ajax ? 'ajax.html' : 'not_ajax.html' %}
And if the expression evaluates to a ``Twig_Template`` object, Twig will use it
directly::
And if the expression evaluates to a ``Twig_Template`` or a
``Twig_TemplateWrapper`` instance, Twig will use it directly::
// {% include template %}
// deprecated as of Twig 1.28
$template = $twig->loadTemplate('some_template.twig');
$twig->loadTemplate('template.twig')->display(array('template' => $template));
// as of Twig 1.28
$template = $twig->load('some_template.twig');
$twig->display('template.twig', array('template' => $template));
You can mark an include with ``ignore missing`` in which case Twig will ignore
the statement if the template to be included does not exist. It has to be
+26 -1
View File
@@ -304,7 +304,30 @@ class Twig_Environment
}
/**
* Loads a template by name.
* Loads a template.
*
* @param string|Twig_TemplateWrapper|Twig_Template $name The template name
*
* @return Twig_TemplateWrapper
*/
public function load($name)
{
if ($name instanceof Twig_TemplateWrapper) {
return $name;
}
if ($name instanceof Twig_Template) {
return new Twig_TemplateWrapper($this, $name);
}
return new Twig_TemplateWrapper($this, $this->loadTemplate($name));
}
/**
* Loads a template internal representation.
*
* This method is for internal use only and should never be called
* directly.
*
* @param string $name The template name
* @param int $index The index if it is an embedded template
@@ -313,6 +336,8 @@ class Twig_Environment
*
* @throws Twig_Error_Loader When the template cannot be found
* @throws Twig_Error_Syntax When an error occurred during compilation
*
* @internal
*/
public function loadTemplate($name, $index = null)
{
+31 -11
View File
@@ -13,7 +13,13 @@
/**
* Default base class for compiled templates.
*
* This class is an implementation detail of how template compilation currently
* works, which might change. It should never be used directly. Use $twig->load()
* instead, which returns an instance of Twig_TemplateWrapper.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
abstract class Twig_Template
{
@@ -270,18 +276,34 @@ abstract class Twig_Template
}
/**
* Returns all block names.
* Returns all block names in the current context of the template.
*
* This method is for internal use only and should never be called
* directly.
* This method checks blocks defined in the current template
* or defined in "used" traits or defined in parent templates.
*
* @param string $name The block name
* @param array $context The context
* @param array $blocks The current set of blocks
*
* @return array An array of block names
*
* @internal
*/
public function getBlockNames()
public function getBlockNames(array $context = null, array $blocks = array())
{
return array_keys($this->blocks);
if (null === $context) {
@trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED);
return array_keys($this->blocks);
}
$names = array_merge(array_keys($blocks), array_keys($this->blocks));
if (false !== $parent = $this->getParent($context)) {
$names = array_merge($names, $parent->getBlockNames($context));
}
return array_unique($names);
}
protected function loadTemplate($template, $templateName = null, $line = null, $index = null)
@@ -295,6 +317,10 @@ abstract class Twig_Template
return $template;
}
if ($template instanceof Twig_TemplateWrapper) {
return $template;
}
return $this->env->loadTemplate($template, $index);
} catch (Twig_Error $e) {
if (!$e->getTemplateName()) {
@@ -595,12 +621,6 @@ abstract class Twig_Template
throw $e;
}
// useful when calling a template method from a template
// this is not supported but unfortunately heavily used in the Symfony profiler
if ($object instanceof self) {
return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
}
return $ret;
}
}
+134
View File
@@ -0,0 +1,134 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2016 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exposes a template to userland.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
final class Twig_TemplateWrapper
{
private $env;
private $template;
/**
* This method is for internal use only and should never be called
* directly (use Twig_Environment::load() instead).
*
* @internal
*/
public function __construct(Twig_Environment $env, Twig_Template $template)
{
$this->env = $env;
$this->template = $template;
}
/**
* Renders the template.
*
* @param array $context An array of parameters to pass to the template
*
* @return string The rendered template
*/
public function render($context = array())
{
return $this->template->render($context);
}
/**
* Displays the template.
*
* @param array $context An array of parameters to pass to the template
*/
public function display($context = array())
{
return $this->template->display($context);
}
/**
* Checks if a block is defined.
*
* @param string $name The block name
* @param array $context An array of parameters to pass to the template
*
* @return bool
*/
public function hasBlock($name, $context = array())
{
return $this->template->hasBlock($name, $context);
}
/**
* Returns defined block names in the template.
*
* @param array $context An array of parameters to pass to the template
*
* @return string[] An array of defined template block names
*/
public function getBlockNames($context = array())
{
return $this->template->getBlockNames($context);
}
/**
* Renders a template block.
*
* @param string $name The block name to render
* @param array $context An array of parameters to pass to the template
*
* @return string The rendered block
*/
public function renderBlock($name, $context = array())
{
ob_start();
$this->displayBlock($name, $context);
return ob_get_clean();
}
/**
* Displays a template block.
*
* @param string $name The block name to render
* @param array $context An array of parameters to pass to the template
*/
public function displayBlock($name, $context = array())
{
$context = $this->env->mergeGlobals($context);
$level = ob_get_level();
ob_start();
try {
$this->template->displayBlock($name, $context);
} catch (Exception $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
} catch (Throwable $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
}
return ob_get_clean();
}
/**
* @return Twig_Source
*/
public function getSourceContext()
{
return $this->template->getSourceContext();
}
}
+1
View File
@@ -130,6 +130,7 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
/**
* @dataProvider getGetAttributeWithTemplateAsObject
* @group legacy
*/
public function testGetAttributeWithTemplateAsObject($useExt)
{
+38
View File
@@ -0,0 +1,38 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Tests_TemplateWrapperTest extends PHPUnit_Framework_TestCase
{
public function testHasGetBlocks()
{
$twig = new Twig_Environment(new Twig_Loader_Array(array(
'index' => '{% block foo %}{% endblock %}',
'index_with_use' => '{% use "imported" %}{% block foo %}{% endblock %}',
'index_with_extends' => '{% extends "extended" %}{% block foo %}{% endblock %}',
'imported' => '{% block imported %}{% endblock %}',
'extended' => '{% block extended %}{% endblock %}',
)));
$wrapper = new Twig_TemplateWrapper($twig, $twig->loadTemplate('index'));
$this->assertTrue($wrapper->hasBlock('foo'));
$this->assertFalse($wrapper->hasBlock('bar'));
$this->assertEquals(array('foo'), $wrapper->getBlockNames());
$wrapper = new Twig_TemplateWrapper($twig, $twig->loadTemplate('index_with_use'));
$this->assertTrue($wrapper->hasBlock('foo'));
$this->assertTrue($wrapper->hasBlock('imported'));
$this->assertEquals(array('imported', 'foo'), $wrapper->getBlockNames());
$wrapper = new Twig_TemplateWrapper($twig, $twig->loadTemplate('index_with_extends'));
$this->assertTrue($wrapper->hasBlock('foo'));
$this->assertTrue($wrapper->hasBlock('extended'));
$this->assertEquals(array('foo', 'extended'), $wrapper->getBlockNames());
}
}