diff --git a/CHANGELOG b/CHANGELOG index 83361a98b..d568ae41c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,7 +17,15 @@ * improved the performance of the filesystem loader * removed features that were deprecated in 1.x -* 1.28.0 (2016-XX-XX) +* 1.28.2 (2016-XX-XX) + + * n/a + +* 1.28.1 (2016-11-18) + + * fixed block() function when used with a template argument + +* 1.28.0 (2016-11-17) * added support for the PHP 7 null coalescing operator for the ?? Twig implementation * exposed a way to access template data and methods in a portable way diff --git a/composer.json b/composer.json index 03c9046a2..f2cda779e 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7", + "symfony/phpunit-bridge": "~3.2@dev", "symfony/debug": "~2.7" }, "autoload": { diff --git a/doc/recipes.rst b/doc/recipes.rst index a05095d04..40c0efa26 100644 --- a/doc/recipes.rst +++ b/doc/recipes.rst @@ -510,18 +510,18 @@ include in your templates: ``interpolateProvider`` service, for instance at the module initialization time: - ```js - angular.module('myApp', []).config(function($interpolateProvider) { - $interpolateProvider.startSymbol('{[').endSymbol(']}'); - }); - ``` + ..code-block:: javascript + + angular.module('myApp', []).config(function($interpolateProvider) { + $interpolateProvider.startSymbol('{[').endSymbol(']}'); + }); * For Twig, change the delimiters via the ``tag_variable`` Lexer option: - ```php - $env->setLexer(new Twig_Lexer($env, array( - 'tag_variable' => array('{[', ']}'), - ))); - ``` + ..code-block:: php + + $env->setLexer(new Twig_Lexer($env, array( + 'tag_variable' => array('{[', ']}'), + ))); .. _callback: http://www.php.net/manual/en/function.is-callable.php diff --git a/doc/tags/with.rst b/doc/tags/with.rst index c40856e27..41cb72713 100644 --- a/doc/tags/with.rst +++ b/doc/tags/with.rst @@ -32,6 +32,8 @@ is equivalent to the following one: By default, the inner scope has access to the outer scope context; you can disable this behavior by appending the ``only`` keyword: +.. code-block:: jinja + {% set bar = 'bar' %} {% with { foo: 42 } only %} {# only foo is defined #} diff --git a/lib/Twig/Node/Expression/BlockReference.php b/lib/Twig/Node/Expression/BlockReference.php index ad41c3a4e..8c921b00c 100644 --- a/lib/Twig/Node/Expression/BlockReference.php +++ b/lib/Twig/Node/Expression/BlockReference.php @@ -30,46 +30,53 @@ class Twig_Node_Expression_BlockReference extends Twig_Node_Expression public function compile(Twig_Compiler $compiler) { if ($this->getAttribute('is_defined_test')) { - $compiler - ->raw('$this->hasBlock(') - ->subcompile($this->getNode('name')) - ->raw(', $context, $blocks)') - ; + $this->compileTemplateCall($compiler, 'hasBlock'); } else { if ($this->getAttribute('output')) { $compiler->addDebugInfo($this); $this - ->compileTemplateCall($compiler) - ->raw('->displayBlock(') - ->subcompile($this->getNode('name')) - ->raw(", \$context, \$blocks);\n") - ; + ->compileTemplateCall($compiler, 'displayBlock') + ->raw(";\n"); } else { - $this - ->compileTemplateCall($compiler) - ->raw('->renderBlock(') - ->subcompile($this->getNode('name')) - ->raw(', $context, $blocks)') - ; + $this->compileTemplateCall($compiler, 'renderBlock'); } } } - private function compileTemplateCall(Twig_Compiler $compiler) + private function compileTemplateCall(Twig_Compiler $compiler, $method) { if (!$this->hasNode('template')) { - return $compiler->write('$this'); + $compiler->write('$this'); + } else { + $compiler + ->write('$this->loadTemplate(') + ->subcompile($this->getNode('template')) + ->raw(', ') + ->repr($this->getTemplateName()) + ->raw(', ') + ->repr($this->getTemplateLine()) + ->raw(')') + ; } - return $compiler - ->write('$this->loadTemplate(') - ->subcompile($this->getNode('template')) - ->raw(', ') - ->repr($this->getTemplateName()) - ->raw(', ') - ->repr($this->getTemplateLine()) - ->raw(')') - ; + $compiler->raw(sprintf('->%s', $method)); + $this->compileBlockArguments($compiler); + + return $compiler; + } + + private function compileBlockArguments(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('name')) + ->raw(', $context'); + + if (!$this->hasNode('template')) { + $compiler->raw(', $blocks'); + } + + return $compiler->raw(')'); } } diff --git a/lib/Twig/TemplateWrapper.php b/lib/Twig/TemplateWrapper.php index 7325dcd3c..2db61cdad 100644 --- a/lib/Twig/TemplateWrapper.php +++ b/lib/Twig/TemplateWrapper.php @@ -87,20 +87,6 @@ final class Twig_TemplateWrapper * @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(); @@ -124,6 +110,17 @@ final class Twig_TemplateWrapper 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()) + { + $this->template->displayBlock($name, $this->env->mergeGlobals($context)); + } + /** * @return Twig_Source */ diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 6f6d1d25a..ce7732785 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -17,6 +17,14 @@ + + + + + + + + ./lib/Twig/ diff --git a/test/Twig/Tests/EnvironmentTest.php b/test/Twig/Tests/EnvironmentTest.php index bcd0eb1dd..66d97df57 100644 --- a/test/Twig/Tests/EnvironmentTest.php +++ b/test/Twig/Tests/EnvironmentTest.php @@ -485,6 +485,7 @@ class Twig_Tests_EnvironmentTest_Runtime } } +// to be removed in 2.0 interface Twig_EnvironmentTestLoaderInterface extends Twig_LoaderInterface, Twig_SourceContextLoaderInterface { } diff --git a/test/Twig/Tests/Fixtures/functions/block_with_template.test b/test/Twig/Tests/Fixtures/functions/block_with_template.test new file mode 100644 index 000000000..8305eb67f --- /dev/null +++ b/test/Twig/Tests/Fixtures/functions/block_with_template.test @@ -0,0 +1,22 @@ +--TEST-- +"block" function with a template argument +--TEMPLATE-- +{{ block('foo', 'included.twig') }} +{{ block('foo', included_loaded) }} +{{ block('foo', included_loaded_internal) }} +{% set output = block('foo', 'included.twig') %} +{{ output }} +{% block foo %}NOT FOO{% endblock %} +--TEMPLATE(included.twig)-- +{% block foo %}FOO{% endblock %} +--DATA-- +return array( + 'included_loaded' => $twig->load('included.twig'), + 'included_loaded_internal' => $twig->loadTemplate('included.twig'), +) +--EXPECT-- +FOO +FOO +FOO +FOO +NOT FOO diff --git a/test/Twig/Tests/Fixtures/tests/defined_for_blocks_with_template.test b/test/Twig/Tests/Fixtures/tests/defined_for_blocks_with_template.test new file mode 100644 index 000000000..2c651657e --- /dev/null +++ b/test/Twig/Tests/Fixtures/tests/defined_for_blocks_with_template.test @@ -0,0 +1,17 @@ +--TEST-- +"defined" support for blocks with a template argument +--TEMPLATE-- +{{ block('foo', 'included.twig') is defined ? 'ok' : 'ko' }} +{{ block('foo', included_loaded) is defined ? 'ok' : 'ko' }} +{{ block('foo', included_loaded_internal) is defined ? 'ok' : 'ko' }} +--TEMPLATE(included.twig)-- +{% block foo %}FOO{% endblock %} +--DATA-- +return array( + 'included_loaded' => $twig->load('included.twig'), + 'included_loaded_internal' => $twig->loadTemplate('included.twig'), +) +--EXPECT-- +ok +ok +ok diff --git a/test/Twig/Tests/NativeExtensionTest.php b/test/Twig/Tests/NativeExtensionTest.php index 942aff9e3..a692be1f3 100644 --- a/test/Twig/Tests/NativeExtensionTest.php +++ b/test/Twig/Tests/NativeExtensionTest.php @@ -11,6 +11,9 @@ class Twig_Tests_NativeExtensionTest extends PHPUnit_Framework_TestCase { + /** + * @requires PHP 5.3 + */ public function testGetProperties() { if (defined('HHVM_VERSION')) { diff --git a/test/Twig/Tests/TemplateTest.php b/test/Twig/Tests/TemplateTest.php index ff682f520..1fd67304d 100644 --- a/test/Twig/Tests/TemplateTest.php +++ b/test/Twig/Tests/TemplateTest.php @@ -350,9 +350,9 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase // tests when input is not an array or object $tests = array_merge($tests, array( - array(false, null, 42, 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a integer variable ("42").'), - array(false, null, 'string', 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a string variable ("string").'), - array(false, null, array(), 'a', array(), $anyType, false, 'Key "a" does not exist as the array is empty.'), + array(false, null, 42, 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a integer variable ("42") in "index.twig".'), + array(false, null, 'string', 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a string variable ("string") in "index.twig".'), + array(false, null, array(), 'a', array(), $anyType, false, 'Key "a" does not exist as the array is empty in "index.twig".'), )); // add twig_template_get_attributes tests @@ -372,12 +372,14 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase class Twig_TemplateTest extends Twig_Template { protected $useExtGetAttribute = false; + private $name; - public function __construct(Twig_Environment $env, $useExtGetAttribute = false) + public function __construct(Twig_Environment $env, $useExtGetAttribute = false, $name = 'index.twig') { parent::__construct($env); $this->useExtGetAttribute = $useExtGetAttribute; self::$cache = array(); + $this->name = $name; } public function getZero() @@ -402,6 +404,7 @@ class Twig_TemplateTest extends Twig_Template public function getTemplateName() { + return $this->name; } public function getDebugInfo() @@ -409,13 +412,9 @@ class Twig_TemplateTest extends Twig_Template return array(); } - public function getSource() - { - return ''; - } - protected function doGetParent(array $context) { + return false; } protected function doDisplay(array $context, array $blocks = array()) @@ -658,3 +657,8 @@ class CExtDisablingNodeVisitor implements Twig_NodeVisitorInterface return 0; } } + +// to be removed in 2.0 +interface Twig_TemplateTestLoaderInterface extends Twig_LoaderInterface, Twig_SourceContextLoaderInterface +{ +} diff --git a/test/Twig/Tests/TemplateWrapperTest.php b/test/Twig/Tests/TemplateWrapperTest.php index fbc4b4a20..9cd1ced9a 100644 --- a/test/Twig/Tests/TemplateWrapperTest.php +++ b/test/Twig/Tests/TemplateWrapperTest.php @@ -35,4 +35,30 @@ class Twig_Tests_TemplateWrapperTest extends PHPUnit_Framework_TestCase $this->assertTrue($wrapper->hasBlock('extended')); $this->assertEquals(array('foo', 'extended'), $wrapper->getBlockNames()); } + + public function testRenderBlock() + { + $twig = new Twig_Environment(new Twig_Loader_Array(array( + 'index' => '{% block foo %}{{ foo }}{{ bar }}{% endblock %}', + ))); + $twig->addGlobal('bar', 'BAR'); + + $wrapper = new Twig_TemplateWrapper($twig, $twig->loadTemplate('index')); + $this->assertEquals('FOOBAR', $wrapper->renderBlock('foo', array('foo' => 'FOO'))); + } + + public function testDisplayBlock() + { + $twig = new Twig_Environment(new Twig_Loader_Array(array( + 'index' => '{% block foo %}{{ foo }}{{ bar }}{% endblock %}', + ))); + $twig->addGlobal('bar', 'BAR'); + + $wrapper = new Twig_TemplateWrapper($twig, $twig->loadTemplate('index')); + + ob_start(); + $wrapper->displayBlock('foo', array('foo' => 'FOO')); + + $this->assertEquals('FOOBAR', ob_get_clean()); + } }