diff --git a/src/Handlebars/Context.php b/src/Handlebars/Context.php index d9c2b73..2cbbfc6 100644 --- a/src/Handlebars/Context.php +++ b/src/Handlebars/Context.php @@ -65,6 +65,12 @@ class Context */ 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. * @@ -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 - */ - 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. - * - * @return void + * @see \Handlebars\Context::$specialVariables */ - 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 - */ - public function popIndex() - { - return array_pop($this->index); - } - - /** - * Pop the last key from the stack. + * @return array Associative array of special variables. * - * @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 - */ - public function lastIndex() - { - return end($this->index); - } - - /** - * Get the key of current object property. + * @return array Associative array of special variables. * - * @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 ''; } elseif ($variableName == '.' || $variableName == 'this') { return $current; - } elseif ($variableName == '@index') { - $current = $this->lastIndex(); - } elseif ($variableName == '@key') { - $current = $this->lastKey(); + } elseif ($variableName[0] == '@') { + $specialVariables = $this->lastSpecialVariables(); + if (isset($specialVariables[$variableName])) { + return $specialVariables[$variableName]; + } elseif ($strict) { + throw new \InvalidArgumentException( + 'can not find variable in context' + ); + } else { + return ''; + } } else { $chunks = $this->_splitVariableName($variableName); foreach ($chunks as $chunk) { diff --git a/src/Handlebars/Helpers.php b/src/Handlebars/Helpers.php index 467b150..288de00 100644 --- a/src/Handlebars/Helpers.php +++ b/src/Handlebars/Helpers.php @@ -124,24 +124,22 @@ class Helpers $template->setStopToken(false); $buffer = $template->render($context); } 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) { - if ($islist) { - $context->pushIndex($key); - } else { - $context->pushKey($key); + $specialVariables = array('@index' => $index); + if (!$isList) { + $specialVariables['@key'] = $key; } + $context->pushSpecialVariables($specialVariables); $context->push($var); $template->setStopToken('else'); $template->rewind(); $buffer .= $template->render($context); $context->pop(); - if ($islist) { - $context->popIndex(); - } else { - $context->popKey(); - } + $context->popSpecialVariables(); + $index++; } $template->setStopToken(false); diff --git a/src/Handlebars/Template.php b/src/Handlebars/Template.php index 0240e9a..c53bb28 100644 --- a/src/Handlebars/Template.php +++ b/src/Handlebars/Template.php @@ -291,12 +291,20 @@ class Template } $buffer = ''; if (is_array($sectionVar) || $sectionVar instanceof \Traversable) { - foreach ($sectionVar as $index => $d) { - $context->pushIndex($index); + $isList = is_array($sectionVar) && (array_keys($sectionVar) == range(0, count($sectionVar) - 1)); + $index = 0; + + foreach ($sectionVar as $key => $d) { + $specialVariables = array('@index' => $index); + if (!$isList) { + $specialVariables['@key'] = $key; + } + $context->pushSpecialVariables($specialVariables); $context->push($d); $buffer .= $this->render($context); $context->pop(); - $context->popIndex(); + $context->popSpecialVariables(); + $index++; } } elseif (is_object($sectionVar)) { //Act like with diff --git a/tests/Xamin/HandlebarsTest.php b/tests/Xamin/HandlebarsTest.php index 97ad045..9dd22ed 100644 --- a/tests/Xamin/HandlebarsTest.php +++ b/tests/Xamin/HandlebarsTest.php @@ -173,6 +173,16 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase array('data' => array('key1'=>1, 'key2'=>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( '{{#each data}}{{this}}{{else}}fail{{/each}}', 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('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('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->value = 1; $this->assertEquals('1', $engine->render('{{#x}}{{value}}{{/x}}', array ('x' => $std))); @@ -512,7 +524,6 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase $context->pop(); $this->assertEquals('value', $context->get('value')); $this->assertEquals('value', $context->get('value', true)); - $this->assertFalse($context->lastIndex()); } /**