Use both "@index" and "@key" for associative arrays

This commit is contained in:
Dmitriy Simushev 2014-02-25 12:40:47 +00:00
parent 5b188ce19e
commit 9d62ffd581
4 changed files with 63 additions and 59 deletions

View File

@ -65,6 +65,12 @@ class Context
*/ */
protected $key = array(); protected $key = array();
/**
* @var array Special variables stack for sections. Each stack element can
* contain elements with "@index" and "@key" keys.
*/
protected $specialVariables = array();
/** /**
* Mustache rendering Context constructor. * Mustache rendering Context constructor.
* *
@ -90,27 +96,17 @@ class Context
} }
/** /**
* Push an Index onto the index stack * Push an array of special variables to stack.
* *
* @param integer $index Index of the current section item. * @param array $variables An associative array of special variables.
* *
* @return void * @return void
*/
public function pushIndex($index)
{
array_push($this->index, $index);
}
/**
* Push a Key onto the key stack
* *
* @param string $key Key of the current object property. * @see \Handlebars\Context::$specialVariables
*
* @return void
*/ */
public function pushKey($key) public function pushSpecialVariables($variables)
{ {
array_push($this->key, $key); array_push($this->specialVariables, $variables);
} }
/** /**
@ -124,23 +120,15 @@ class Context
} }
/** /**
* Pop the last index from the stack. * Pop the last special variables set from the stack.
* *
* @return int Last index * @return array Associative array of special variables.
*/
public function popIndex()
{
return array_pop($this->index);
}
/**
* Pop the last key from the stack.
* *
* @return string Last key * @see \Handlebars\Context::$specialVariables
*/ */
public function popKey() public function popSpecialVariables()
{ {
return array_pop($this->key); return array_pop($this->specialVariables);
} }
/** /**
@ -154,23 +142,15 @@ class Context
} }
/** /**
* Get the index of current section item. * Get the last special variables set from the stack.
* *
* @return mixed Last index * @return array Associative array of special variables.
*/
public function lastIndex()
{
return end($this->index);
}
/**
* Get the key of current object property.
* *
* @return mixed Last key * @see \Handlebars\Context::$specialVariables
*/ */
public function lastKey() public function lastSpecialVariables()
{ {
return end($this->key); return end($this->specialVariables);
} }
/** /**
@ -236,10 +216,17 @@ class Context
return ''; return '';
} elseif ($variableName == '.' || $variableName == 'this') { } elseif ($variableName == '.' || $variableName == 'this') {
return $current; return $current;
} elseif ($variableName == '@index') { } elseif ($variableName[0] == '@') {
$current = $this->lastIndex(); $specialVariables = $this->lastSpecialVariables();
} elseif ($variableName == '@key') { if (isset($specialVariables[$variableName])) {
$current = $this->lastKey(); return $specialVariables[$variableName];
} elseif ($strict) {
throw new \InvalidArgumentException(
'can not find variable in context'
);
} else {
return '';
}
} else { } else {
$chunks = $this->_splitVariableName($variableName); $chunks = $this->_splitVariableName($variableName);
foreach ($chunks as $chunk) { foreach ($chunks as $chunk) {

View File

@ -124,24 +124,22 @@ class Helpers
$template->setStopToken(false); $template->setStopToken(false);
$buffer = $template->render($context); $buffer = $template->render($context);
} elseif (is_array($tmp) || $tmp instanceof \Traversable) { } elseif (is_array($tmp) || $tmp instanceof \Traversable) {
$islist = ($tmp instanceof \Generator) || (array_keys($tmp) == range(0, count($tmp) - 1)); $isList = is_array($tmp) && (array_keys($tmp) == range(0, count($tmp) - 1));
$index = 0;
foreach ($tmp as $key => $var) { foreach ($tmp as $key => $var) {
if ($islist) { $specialVariables = array('@index' => $index);
$context->pushIndex($key); if (!$isList) {
} else { $specialVariables['@key'] = $key;
$context->pushKey($key);
} }
$context->pushSpecialVariables($specialVariables);
$context->push($var); $context->push($var);
$template->setStopToken('else'); $template->setStopToken('else');
$template->rewind(); $template->rewind();
$buffer .= $template->render($context); $buffer .= $template->render($context);
$context->pop(); $context->pop();
if ($islist) { $context->popSpecialVariables();
$context->popIndex(); $index++;
} else {
$context->popKey();
}
} }
$template->setStopToken(false); $template->setStopToken(false);

View File

@ -291,12 +291,20 @@ class Template
} }
$buffer = ''; $buffer = '';
if (is_array($sectionVar) || $sectionVar instanceof \Traversable) { if (is_array($sectionVar) || $sectionVar instanceof \Traversable) {
foreach ($sectionVar as $index => $d) { $isList = is_array($sectionVar) && (array_keys($sectionVar) == range(0, count($sectionVar) - 1));
$context->pushIndex($index); $index = 0;
foreach ($sectionVar as $key => $d) {
$specialVariables = array('@index' => $index);
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->popIndex(); $context->popSpecialVariables();
$index++;
} }
} elseif (is_object($sectionVar)) { } elseif (is_object($sectionVar)) {
//Act like with //Act like with

View File

@ -173,6 +173,16 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
array('data' => array('key1'=>1, 'key2'=>2,)), array('data' => array('key1'=>1, 'key2'=>2,)),
'key1=>1key2=>2' 'key1=>1key2=>2'
), ),
array(
'{{#each data}}{{@key}}=>{{this}}{{/each}}',
array('data' => new \ArrayIterator(array('key1'=>1, 'key2'=>2))),
'key1=>1key2=>2'
),
array(
'{{#each data}}{{@index}}=>{{this}},{{/each}}',
array('data' => array('key1'=>1, 'key2'=>2,)),
'0=>1,1=>2,'
),
array( array(
'{{#each data}}{{this}}{{else}}fail{{/each}}', '{{#each data}}{{this}}{{else}}fail{{/each}}',
array('data' => array(1, 2, 3, 4)), array('data' => array(1, 2, 3, 4)),
@ -274,6 +284,8 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('', $engine->render('{{#x}}yes{{/x}}', array ('x' => false))); $this->assertEquals('', $engine->render('{{#x}}yes{{/x}}', array ('x' => false)));
$this->assertEquals('yes', $engine->render('{{^x}}yes{{/x}}', array ('x' => false))); $this->assertEquals('yes', $engine->render('{{^x}}yes{{/x}}', array ('x' => false)));
$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('abc', $engine->render('{{#x}}{{@key}}{{/x}}', array ('x' => array ('a'=>1,'b'=>2,'c'=>3))));
$std = new stdClass(); $std = new stdClass();
$std->value = 1; $std->value = 1;
$this->assertEquals('1', $engine->render('{{#x}}{{value}}{{/x}}', array ('x' => $std))); $this->assertEquals('1', $engine->render('{{#x}}{{value}}{{/x}}', array ('x' => $std)));
@ -512,7 +524,6 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
$context->pop(); $context->pop();
$this->assertEquals('value', $context->get('value')); $this->assertEquals('value', $context->get('value'));
$this->assertEquals('value', $context->get('value', true)); $this->assertEquals('value', $context->get('value', true));
$this->assertFalse($context->lastIndex());
} }
/** /**