mirror of
https://github.com/Mibew/handlebars.php.git
synced 2024-11-15 08:44:12 +03:00
Fix context switching for mustache blocks
When you switch into a mustache block, an object shouldn't be iterated over. Associative arrays are closer to objects than lists, so their behavior should be more like objects.
This commit is contained in:
parent
b85cee07ea
commit
a07d25d6a3
@ -252,12 +252,17 @@ class Context
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$chunks = $this->_splitVariableName($variableName);
|
$chunks = $this->_splitVariableName($variableName);
|
||||||
|
do {
|
||||||
|
$current = current($this->stack);
|
||||||
foreach ($chunks as $chunk) {
|
foreach ($chunks as $chunk) {
|
||||||
if (is_string($current) and $current == '') {
|
if (is_string($current) and $current == '') {
|
||||||
return $current;
|
return $current;
|
||||||
}
|
}
|
||||||
$current = $this->_findVariableInContext($current, $chunk, $strict);
|
$current = $this->_findVariableInContext($current, $chunk, $strict);
|
||||||
}
|
}
|
||||||
|
prev($this->stack);
|
||||||
|
|
||||||
|
} while ($current === null && current($this->stack) !== false);
|
||||||
}
|
}
|
||||||
return $current;
|
return $current;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
namespace Handlebars;
|
namespace Handlebars;
|
||||||
use Handlebars\Arguments;
|
use Handlebars\Arguments;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handlebars base template
|
* Handlebars base template
|
||||||
@ -447,35 +448,29 @@ class Template
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
$buffer = '';
|
$buffer = '';
|
||||||
if (is_array($sectionVar) || $sectionVar instanceof \Traversable) {
|
if ($this->_checkIterable($sectionVar)) {
|
||||||
$isList = is_array($sectionVar) &&
|
|
||||||
(array_keys($sectionVar) === range(0, count($sectionVar) - 1));
|
|
||||||
$index = 0;
|
$index = 0;
|
||||||
$lastIndex = $isList ? (count($sectionVar) - 1) : false;
|
$lastIndex = (count($sectionVar) - 1);
|
||||||
|
|
||||||
foreach ($sectionVar as $key => $d) {
|
foreach ($sectionVar as $key => $d) {
|
||||||
$specialVariables = array(
|
$context->pushSpecialVariables(
|
||||||
|
array(
|
||||||
'@index' => $index,
|
'@index' => $index,
|
||||||
'@first' => ($index === 0),
|
'@first' => ($index === 0),
|
||||||
'@last' => ($index === $lastIndex),
|
'@last' => ($index === $lastIndex),
|
||||||
|
'@key' => $key
|
||||||
|
)
|
||||||
);
|
);
|
||||||
if (!$isList) {
|
|
||||||
$specialVariables['@key'] = $key;
|
|
||||||
}
|
|
||||||
$context->pushSpecialVariables($specialVariables);
|
|
||||||
$context->push($d);
|
$context->push($d);
|
||||||
$buffer .= $this->render($context);
|
$buffer .= $this->render($context);
|
||||||
$context->pop();
|
$context->pop();
|
||||||
$context->popSpecialVariables();
|
$context->popSpecialVariables();
|
||||||
$index++;
|
$index++;
|
||||||
}
|
}
|
||||||
} elseif (is_object($sectionVar)) {
|
} elseif ($sectionVar) {
|
||||||
//Act like with
|
//Act like with
|
||||||
$context->push($sectionVar);
|
$context->push($sectionVar);
|
||||||
$buffer = $this->render($context);
|
$buffer = $this->render($context);
|
||||||
$context->pop();
|
$context->pop();
|
||||||
} elseif ($sectionVar) {
|
|
||||||
$buffer = $this->render($context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $buffer;
|
return $buffer;
|
||||||
@ -712,4 +707,31 @@ class Template
|
|||||||
|
|
||||||
return $args->getPositionalArguments();
|
return $args->getPositionalArguments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether a value should be iterated over (e.g. in a section context).
|
||||||
|
*
|
||||||
|
* @param mixed $value Value to check if iterable.
|
||||||
|
*
|
||||||
|
* @return bool True if the value is 'iterable'
|
||||||
|
*
|
||||||
|
* @see https://github.com/bobthecow/mustache.php/blob/18a2adc/src/Mustache/Template.php#L85-L113
|
||||||
|
*/
|
||||||
|
private function _checkIterable($value)
|
||||||
|
{
|
||||||
|
switch (gettype($value)) {
|
||||||
|
case 'object':
|
||||||
|
return $value instanceof Traversable;
|
||||||
|
case 'array':
|
||||||
|
$i = 0;
|
||||||
|
foreach ($value as $k => $v) {
|
||||||
|
if ($k !== $i++) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -689,12 +689,18 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals('', $engine->render('{{^x}}yes{{/x}}', array('x' => true)));
|
$this->assertEquals('', $engine->render('{{^x}}yes{{/x}}', array('x' => true)));
|
||||||
$this->assertEquals('1234', $engine->render('{{#x}}{{this}}{{/x}}', array('x' => array(1, 2, 3, 4))));
|
$this->assertEquals('1234', $engine->render('{{#x}}{{this}}{{/x}}', array('x' => array(1, 2, 3, 4))));
|
||||||
$this->assertEquals('012', $engine->render('{{#x}}{{@index}}{{/x}}', array('x' => array('a', 'b', 'c'))));
|
$this->assertEquals('012', $engine->render('{{#x}}{{@index}}{{/x}}', array('x' => array('a', 'b', 'c'))));
|
||||||
$this->assertEquals('abc', $engine->render('{{#x}}{{@key}}{{/x}}', array('x' => array('a' => 1, 'b' => 2, 'c' => 3))));
|
$this->assertEquals('123', $engine->render('{{#x}}{{a}}{{b}}{{c}}{{/x}}', array('x' => array('a' => 1, 'b' => 2, 'c' => 3))));
|
||||||
$this->assertEquals('the_only_key', $engine->render('{{#x}}{{@key}}{{/x}}', array('x' => array('the_only_key' => 1))));
|
$this->assertEquals('1', $engine->render('{{#x}}{{the_only_key}}{{/x}}', array('x' => array('the_only_key' => 1))));
|
||||||
$std = new stdClass();
|
$std = new stdClass();
|
||||||
$std->value = 1;
|
$std->value = 1;
|
||||||
|
$std->other = 4;
|
||||||
$this->assertEquals('1', $engine->render('{{#x}}{{value}}{{/x}}', array('x' => $std)));
|
$this->assertEquals('1', $engine->render('{{#x}}{{value}}{{/x}}', array('x' => $std)));
|
||||||
$this->assertEquals('1', $engine->render('{{{x}}}', array('x' => 1)));
|
$this->assertEquals('1', $engine->render('{{{x}}}', array('x' => 1)));
|
||||||
|
$this->assertEquals('1 2', $engine->render('{{#x}}{{value}} {{parent}}{{/x}}', array('x' => $std, 'parent' => 2)));
|
||||||
|
|
||||||
|
$y = new stdClass();
|
||||||
|
$y->value = 2;
|
||||||
|
$this->assertEquals('2 1 3 4', $engine->render('{{#x}}{{#y}}{{value}} {{x.value}} {{from_root}} {{other}}{{/y}}{{/x}}', array('x' => $std, 'y' => $y, 'from_root' => 3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -962,6 +968,7 @@ EOM;
|
|||||||
|
|
||||||
$this->setExpectedException('RuntimeException');
|
$this->setExpectedException('RuntimeException');
|
||||||
$engine->render('{{>foo-again}}', array());
|
$engine->render('{{>foo-again}}', array());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user