diff --git a/src/Handlebars/Parser.php b/src/Handlebars/Parser.php index 01b7aa2..df9e15b 100644 --- a/src/Handlebars/Parser.php +++ b/src/Handlebars/Parser.php @@ -2,10 +2,10 @@ /** * This file is part of Handlebars-php * Base on mustache-php https://github.com/bobthecow/mustache.php - * re-write to use with handlebars - * + * re-write to use with handlebars + * * PHP version 5.3 - * + * * @category Xamin * @package Handlebars * @author fzerorubigd @@ -18,7 +18,7 @@ /** * Handlebars parser (infact its a mustache parser) * This class is responsible for turning raw template source into a set of Mustache tokens. - * + * * @category Xamin * @package Handlebars * @author fzerorubigd @@ -33,7 +33,7 @@ class Handlebars_Parser /** * Process array of tokens and convert them into parse tree * - * @param array $tokens Set of + * @param array $tokens Set of * * @return array Token parse tree */ @@ -71,8 +71,8 @@ class Handlebars_Parser if ($result === null) { throw new LogicException('Unexpected closing tag: /'. $token[Handlebars_Tokenizer::NAME]); } - - if (!array_key_exists(Handlebars_Tokenizer::NODES, $result) + + if (!array_key_exists(Handlebars_Tokenizer::NODES, $result) && isset($result[Handlebars_Tokenizer::NAME]) && $result[Handlebars_Tokenizer::NAME] == $token[Handlebars_Tokenizer::NAME] ) { @@ -81,8 +81,8 @@ class Handlebars_Parser array_push($stack, $result); break 2; } else { - array_unshift($newNodes, $result); - } + array_unshift($newNodes, $result); + } } while (true); break; default: @@ -95,4 +95,4 @@ class Handlebars_Parser return $stack; } -} \ No newline at end of file +} diff --git a/src/Handlebars/Template.php b/src/Handlebars/Template.php index fc2cea6..3643d21 100644 --- a/src/Handlebars/Template.php +++ b/src/Handlebars/Template.php @@ -2,9 +2,9 @@ /** * This file is part of Handlebars-php * Base on mustache-php https://github.com/bobthecow/mustache.php - * + * * PHP version 5.3 - * + * * @category Xamin * @package Handlebars * @author fzerorubigd @@ -18,7 +18,7 @@ /** * Handlebars base template * contain some utility method to get context and helpers - * + * * @category Xamin * @package Handlebars * @author fzerorubigd @@ -34,7 +34,7 @@ class Handlebars_Template * @var Handlebars_Engine */ protected $handlebars; - + protected $tree = array(); @@ -83,37 +83,37 @@ class Handlebars_Template /** * Get current engine associated with this object - * + * * @return Handlebars_Engine */ public function getEngine() { return $this->handlebars; } - + /** * set stop token for render and discard method * * @param string $token token to set as stop token or false to remove - * - * @return void + * + * @return void */ public function setStopToken($token) { $this->_stopToken = $token; } - + /** - * get current stop token + * get current stop token * - * @return string|false + * @return string|false */ public function getStopToken() { return $this->_stopToken; - } + } /** * Render top tree * @@ -125,7 +125,7 @@ class Handlebars_Template { if (!$context instanceof Handlebars_Context) { $context = new Handlebars_Context($context); - } + } $topTree = end($this->_stack); //This method never pop a value from stack list($index ,$tree) = $topTree; @@ -133,9 +133,9 @@ class Handlebars_Template while (array_key_exists($index, $tree)) { $current = $tree[$index]; $index++; - //if the section is exactly like waitFor - if (is_string($this->_stopToken) - && $current[Handlebars_Tokenizer::TYPE] == Handlebars_Tokenizer::T_ESCAPED + //if the section is exactly like waitFor + if (is_string($this->_stopToken) + && $current[Handlebars_Tokenizer::TYPE] == Handlebars_Tokenizer::T_ESCAPED && $current[Handlebars_Tokenizer::NAME] === $this->_stopToken ) { //Ok break here, the helper should be aware of this. @@ -151,7 +151,13 @@ class Handlebars_Template $buffer .= $this->_section($context, $current); array_pop($this->_stack); break; - case Handlebars_Tokenizer::T_COMMENT : + case Handlebars_Tokenizer::T_INVERTED : + $newStack = isset($current[Handlebars_Tokenizer::NODES]) ? $current[Handlebars_Tokenizer::NODES] : array(); + array_push($this->_stack, array(0, $newStack)); + $buffer .= $this->_inverted($context, $current); + array_pop($this->_stack); + break; + case Handlebars_Tokenizer::T_COMMENT : $buffer .= ''; break; case Handlebars_Tokenizer::T_PARTIAL: @@ -174,7 +180,7 @@ class Handlebars_Template } return $buffer; } - + /** * Discard top tree * @@ -186,27 +192,27 @@ class Handlebars_Template { if (!$context instanceof Handlebars_Context) { $context = new Handlebars_Context($context); - } + } $topTree = end($this->_stack); //This method never pop a value from stack list($index ,$tree) = $topTree; while (array_key_exists($index, $tree)) { $current = $tree[$index]; $index++; - //if the section is exactly like waitFor - if (is_string($this->_stopToken) - && $current[Handlebars_Tokenizer::TYPE] == Handlebars_Tokenizer::T_ESCAPED + //if the section is exactly like waitFor + if (is_string($this->_stopToken) + && $current[Handlebars_Tokenizer::TYPE] == Handlebars_Tokenizer::T_ESCAPED && $current[Handlebars_Tokenizer::NAME] === $this->_stopToken ) { //Ok break here, the helper should be aware of this. $newStack = array_pop($this->_stack); $newStack[0] = $index; - array_push($this->_stack, $newStack); + array_push($this->_stack, $newStack); break; } } return ''; - } + } /** * Process section nodes @@ -215,7 +221,7 @@ class Handlebars_Template * @param array $current section node data * * @return string the result - */ + */ private function _section(Handlebars_Context $context, $current) { $helpers = $this->handlebars->getHelpers(); @@ -229,7 +235,7 @@ class Handlebars_Template ); } else { $source = ''; - } + } $params = array( $this, //First argument is this template $context, //Secound is current context @@ -237,12 +243,12 @@ class Handlebars_Template $source ); return call_user_func_array($helpers->$sectionName, $params); - } elseif (trim($current[Handlebars_Tokenizer::ARGS]) == '') { + } elseif (trim($current[Handlebars_Tokenizer::ARGS]) == '') { //Fallback for mustache style each/with/for just if there is no argument at all. try { $sectionVar = $context->get($sectionName, true); } catch (InvalidArgumentException $e) { - throw new RuntimeException($sectionName . ' is not registered as a helper'); + throw new RuntimeException($sectionName . ' is not registered as a helper'); } $buffer = ''; if (is_array($sectionVar) || $sectionVar instanceof Traversable) { @@ -252,7 +258,7 @@ class Handlebars_Template $context->pop(); } } elseif (is_object($sectionVar)) { - //Act like with + //Act like with $context->push($sectionVar); $buffer = $this->render($context); $context->pop(); @@ -262,7 +268,27 @@ class Handlebars_Template return $buffer; } else { throw new RuntimeException($sectionName . ' is not registered as a helper'); - } + } + } + + /** + * Process inverted section + * + * @param Handlebars_Context $context current context + * @param array $current section node data + * + * @return string the result + */ + private function _inverted(Handlebars_Context $context, $current) + { + $sectionName = $current[Handlebars_Tokenizer::NAME]; + $data = $context->get($sectionName); + if (!$data) { + return $this->render($context); + } else { + //No need to disacard here, since itshas no else + return ''; + } } /** @@ -298,6 +324,6 @@ class Handlebars_Template } return $value; } - - + + } diff --git a/src/Handlebars/Tokenizer.php b/src/Handlebars/Tokenizer.php index bb8e861..b8c4442 100644 --- a/src/Handlebars/Tokenizer.php +++ b/src/Handlebars/Tokenizer.php @@ -4,9 +4,9 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. * Changes to match xamin-std and handlebars made by xamin team - * + * * PHP version 5.3 - * + * * @category Xamin * @package Handlebars * @author Justin Hileman @@ -22,12 +22,12 @@ * Handlebars parser (infact its a mustache parser) * This class is responsible for turning raw template source into a set of Mustache tokens. * Some minor changes to handle Handlebars instead of Mustache - * + * * @category Xamin * @package Handlebars * @author Justin Hileman - * @copyright 2012 Justin Hileman * @author fzerorubigd + * @copyright 2012 Justin Hileman * @license MIT * @version Release: @package_version@ * @link http://xamin.ir @@ -42,7 +42,7 @@ class Handlebars_Tokenizer // Token types const T_SECTION = '#'; - //const T_INVERTED = '^'; //Must remove this + const T_INVERTED = '^'; const T_END_SECTION = '/'; const T_COMMENT = '!'; const T_PARTIAL = '>'; //Maybe remove this partials and replace them with helpers @@ -56,7 +56,7 @@ class Handlebars_Tokenizer // Valid token types private static $_tagTypes = array( self::T_SECTION => true, - //self::T_INVERTED => true, + self::T_INVERTED => true, self::T_END_SECTION => true, self::T_COMMENT => true, self::T_PARTIAL => true, @@ -132,7 +132,7 @@ class Handlebars_Tokenizer break; case self::IN_TAG_TYPE: - + $i += strlen($this->otag) - 1; if (isset(self::$_tagTypes[$text[$i + 1]])) { $tag = $text[$i + 1]; @@ -157,14 +157,14 @@ class Handlebars_Tokenizer default: if ($this->tagChange($this->ctag, $text, $i)) { // Sections (Helpers) can accept parameters - if ($this->tagType == self::T_SECTION /*|| $this->tagType == self::T_INVERTED*/) { + if ($this->tagType == self::T_SECTION) { $newBuffer = explode(' ', trim($this->buffer), 2); $args = ''; if (count($newBuffer) == 2) { $args = $newBuffer[1]; } $this->buffer = $newBuffer[0]; - } + } $t = array( self::TYPE => $this->tagType, self::NAME => trim($this->buffer),