From 3fc92fcdc569dd6276c4ab4ca66d30746ee8cc2e Mon Sep 17 00:00:00 2001 From: majortom731 Date: Wed, 12 Mar 2014 19:33:46 +0100 Subject: [PATCH] Added support for subexpressions in helper calls. Not sure if Template.php is the best place to handle subexpressions... --- src/Handlebars/Template.php | 150 +++++++++++++++++++++++++++--------- 1 file changed, 115 insertions(+), 35 deletions(-) diff --git a/src/Handlebars/Template.php b/src/Handlebars/Template.php index 0e8a777..0fd0a17 100644 --- a/src/Handlebars/Template.php +++ b/src/Handlebars/Template.php @@ -11,6 +11,7 @@ * @author Behrooz Shabani * @author Chris Gray * @author Dmitriy Simushev + * @author majortom731 * @copyright 2012 (c) ParsPooyesh Co * @copyright 2013 (c) Behrooz Shabani * @license MIT @@ -151,42 +152,42 @@ class Template break; } switch ($current[Tokenizer::TYPE]) { - case Tokenizer::T_SECTION : - $newStack = isset($current[Tokenizer::NODES]) - ? $current[Tokenizer::NODES] : array(); - array_push($this->_stack, array(0, $newStack, false)); - $buffer .= $this->_section($context, $current); - array_pop($this->_stack); - break; - case Tokenizer::T_INVERTED : - $newStack = isset($current[Tokenizer::NODES]) ? - $current[Tokenizer::NODES] : array(); - array_push($this->_stack, array(0, $newStack, false)); - $buffer .= $this->_inverted($context, $current); - array_pop($this->_stack); - break; - case Tokenizer::T_COMMENT : - $buffer .= ''; - break; - case Tokenizer::T_PARTIAL: - case Tokenizer::T_PARTIAL_2: - $buffer .= $this->_partial($context, $current); - break; - case Tokenizer::T_UNESCAPED: - case Tokenizer::T_UNESCAPED_2: - $buffer .= $this->_get($context, $current, false); - break; - case Tokenizer::T_ESCAPED: + case Tokenizer::T_SECTION : + $newStack = isset($current[Tokenizer::NODES]) + ? $current[Tokenizer::NODES] : array(); + array_push($this->_stack, array(0, $newStack, false)); + $buffer .= $this->_section($context, $current); + array_pop($this->_stack); + break; + case Tokenizer::T_INVERTED : + $newStack = isset($current[Tokenizer::NODES]) ? + $current[Tokenizer::NODES] : array(); + array_push($this->_stack, array(0, $newStack, false)); + $buffer .= $this->_inverted($context, $current); + array_pop($this->_stack); + break; + case Tokenizer::T_COMMENT : + $buffer .= ''; + break; + case Tokenizer::T_PARTIAL: + case Tokenizer::T_PARTIAL_2: + $buffer .= $this->_partial($context, $current); + break; + case Tokenizer::T_UNESCAPED: + case Tokenizer::T_UNESCAPED_2: + $buffer .= $this->_get($context, $current, false); + break; + case Tokenizer::T_ESCAPED: - $buffer .= $this->_get($context, $current, true); - break; - case Tokenizer::T_TEXT: - $buffer .= $current[Tokenizer::VALUE]; - break; - default: - throw new \RuntimeException( - 'Invalid node type : ' . json_encode($current) - ); + $buffer .= $this->_get($context, $current, true); + break; + case Tokenizer::T_TEXT: + $buffer .= $current[Tokenizer::VALUE]; + break; + default: + throw new \RuntimeException( + 'Invalid node type : ' . json_encode($current) + ); } } if ($stop) { @@ -272,6 +273,42 @@ class Template $source ); + // subexpression parsing loop + $subexprs = array(); // will contain all subexpressions inside outermost brackets + $lvl = 0; + $cur_start = 0; + for( $i=0; $i < strlen($params[2]); $i++ ) { + $cur = substr( $params[2], $i, 1 ); + if( $cur == '(' ) { + if( $lvl == 0 ) $cur_start = $i+1; + $lvl++; + } + if( $cur == ')' ) { + $lvl--; + if( $lvl == 0 ) $subexprs[] = substr( $params[2], $cur_start, $i - $cur_start); + } + } + + if( ! empty( $subexprs ) ) { + foreach( $subexprs as $expr ) { + $cmd = explode( " ", $expr ); + $name = trim( $cmd[0] ); + // construct artificial section node + $section_node = array( + Tokenizer::TYPE => Tokenizer::T_ESCAPED, + Tokenizer::NAME => $name, + Tokenizer::OTAG => $current[Tokenizer::OTAG], + Tokenizer::CTAG => $current[Tokenizer::CTAG], + Tokenizer::INDEX => $current[Tokenizer::INDEX], + Tokenizer::ARGS => implode( " ", array_slice( $cmd, 1 ) ) + ); + // resolve the node recursively + $resolved = $this->_handlebarsStyleSection( $context, $section_node ); + // replace original subexpression with result + $params[2] = str_replace( '('.$expr.')', $resolved, $params[2] ); + } + } + $return = call_user_func_array($helpers->$sectionName, $params); if ($return instanceof String) { return $this->handlebars->loadString($return)->render($context); @@ -280,6 +317,49 @@ class Template } } + /** + * Process handlebars subexpression + * + * @param Context $context current context + * @param array $current section node data + * + * @return mixed|string + */ + public function _handlebarsSubexpression(Context $context, $current) + { + $helpers = $this->handlebars->getHelpers(); + $sectionName = $current[Tokenizer::NAME]; + + if (isset($current[Tokenizer::END])) { + $source = substr( + $this->getSource(), + $current[Tokenizer::INDEX], + $current[Tokenizer::END] - $current[Tokenizer::INDEX] + ); + } else { + $source = ''; + } + $params = array( + $this, //First argument is this template + $context, //Second is current context + $current[Tokenizer::ARGS], //Arguments + $source + ); + +// echo "Context: ", "\n"; +// print_r( $params[1] ); + echo "arguments: ", $params[2], "\n"; + echo "src: ", $params[3], "\n"; + + $return = call_user_func_array($helpers->$sectionName, $params); + echo "result: ", $return, "\n\n"; + if ($return instanceof String) { + return $return; + } else { + return $return; + } + } + /** * Process Mustache section style *