mirror of
				https://github.com/Mibew/handlebars.php.git
				synced 2025-11-04 04:05:07 +03:00 
			
		
		
		
	Merge pull request #164 from mAAdhaTTah/bugfix/mustache-context-switch
Fix context switching for mustache blocks
This commit is contained in:
		
						commit
						38c743f79b
					
				@ -73,7 +73,7 @@ class Context
 | 
			
		||||
    protected $key = array();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Special variables stack for sections. 
 | 
			
		||||
     * Special variables stack for sections.
 | 
			
		||||
     *
 | 
			
		||||
     * @var array Each stack element can
 | 
			
		||||
     * contain elements with "@index", "@key", "@first" and "@last" keys.
 | 
			
		||||
@ -186,7 +186,7 @@ class Context
 | 
			
		||||
     * @param boolean $strict       strict search? if not found then throw exception
 | 
			
		||||
     *
 | 
			
		||||
     * @throws \InvalidArgumentException in strict mode and variable not found
 | 
			
		||||
     * @throws \RuntimeException if supplied argument is a malformed quoted string 
 | 
			
		||||
     * @throws \RuntimeException if supplied argument is a malformed quoted string
 | 
			
		||||
     * @throws \InvalidArgumentException if variable name is invalid
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
@ -252,12 +252,17 @@ class Context
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            $chunks = $this->_splitVariableName($variableName);
 | 
			
		||||
            foreach ($chunks as $chunk) {
 | 
			
		||||
                if (is_string($current) and $current == '') {
 | 
			
		||||
                    return $current;
 | 
			
		||||
            do {
 | 
			
		||||
                $current = current($this->stack);
 | 
			
		||||
                foreach ($chunks as $chunk) {
 | 
			
		||||
                    if (is_string($current) and $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;
 | 
			
		||||
    }
 | 
			
		||||
@ -316,18 +321,18 @@ class Context
 | 
			
		||||
        $bad_chars = preg_quote(self::NOT_VALID_NAME_CHARS, '/');
 | 
			
		||||
        $bad_seg_chars = preg_quote(self::NOT_VALID_SEGMENT_NAME_CHARS, '/');
 | 
			
		||||
 | 
			
		||||
        $name_pattern = "(?:[^" 
 | 
			
		||||
            . $bad_chars 
 | 
			
		||||
            . "\s]+)|(?:\[[^" 
 | 
			
		||||
            . $bad_seg_chars 
 | 
			
		||||
        $name_pattern = "(?:[^"
 | 
			
		||||
            . $bad_chars
 | 
			
		||||
            . "\s]+)|(?:\[[^"
 | 
			
		||||
            . $bad_seg_chars
 | 
			
		||||
            . "]+\])";
 | 
			
		||||
        
 | 
			
		||||
        $check_pattern = "/^((" 
 | 
			
		||||
            . $name_pattern 
 | 
			
		||||
            . ")\.)*(" 
 | 
			
		||||
            . $name_pattern  
 | 
			
		||||
 | 
			
		||||
        $check_pattern = "/^(("
 | 
			
		||||
            . $name_pattern
 | 
			
		||||
            . ")\.)*("
 | 
			
		||||
            . $name_pattern
 | 
			
		||||
            . ")\.?$/";
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        $get_pattern = "/(?:" . $name_pattern . ")/";
 | 
			
		||||
 | 
			
		||||
        if (!preg_match($check_pattern, $variableName)) {
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@
 | 
			
		||||
 | 
			
		||||
namespace Handlebars;
 | 
			
		||||
use Handlebars\Arguments;
 | 
			
		||||
use Traversable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handlebars base template
 | 
			
		||||
@ -447,35 +448,29 @@ class Template
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        $buffer = '';
 | 
			
		||||
        if (is_array($sectionVar) || $sectionVar instanceof \Traversable) {
 | 
			
		||||
            $isList = is_array($sectionVar) &&
 | 
			
		||||
                (array_keys($sectionVar) === range(0, count($sectionVar) - 1));
 | 
			
		||||
        if ($this->_checkIterable($sectionVar)) {
 | 
			
		||||
            $index = 0;
 | 
			
		||||
            $lastIndex = $isList ? (count($sectionVar) - 1) : false;
 | 
			
		||||
 | 
			
		||||
            $lastIndex = (count($sectionVar) - 1);
 | 
			
		||||
            foreach ($sectionVar as $key => $d) {
 | 
			
		||||
                $specialVariables = array(
 | 
			
		||||
                    '@index' => $index,
 | 
			
		||||
                    '@first' => ($index === 0),
 | 
			
		||||
                    '@last' => ($index === $lastIndex),
 | 
			
		||||
                $context->pushSpecialVariables(
 | 
			
		||||
                    array(
 | 
			
		||||
                        '@index' => $index,
 | 
			
		||||
                        '@first' => ($index === 0),
 | 
			
		||||
                        '@last' => ($index === $lastIndex),
 | 
			
		||||
                        '@key' => $key
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
                if (!$isList) {
 | 
			
		||||
                    $specialVariables['@key'] = $key;
 | 
			
		||||
                }
 | 
			
		||||
                $context->pushSpecialVariables($specialVariables);
 | 
			
		||||
                $context->push($d);
 | 
			
		||||
                $buffer .= $this->render($context);
 | 
			
		||||
                $context->pop();
 | 
			
		||||
                $context->popSpecialVariables();
 | 
			
		||||
                $index++;
 | 
			
		||||
            }
 | 
			
		||||
        } elseif (is_object($sectionVar)) {
 | 
			
		||||
        } elseif ($sectionVar) {
 | 
			
		||||
            //Act like with
 | 
			
		||||
            $context->push($sectionVar);
 | 
			
		||||
            $buffer = $this->render($context);
 | 
			
		||||
            $context->pop();
 | 
			
		||||
        } elseif ($sectionVar) {
 | 
			
		||||
            $buffer = $this->render($context);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $buffer;
 | 
			
		||||
@ -712,4 +707,31 @@ class Template
 | 
			
		||||
 | 
			
		||||
        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('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))));
 | 
			
		||||
        $this->assertEquals('the_only_key', $engine->render('{{#x}}{{@key}}{{/x}}', array('x' => array('the_only_key' => 1))));
 | 
			
		||||
        $this->assertEquals('123', $engine->render('{{#x}}{{a}}{{b}}{{c}}{{/x}}', array('x' => array('a' => 1, 'b' => 2, 'c' => 3))));
 | 
			
		||||
        $this->assertEquals('1', $engine->render('{{#x}}{{the_only_key}}{{/x}}', array('x' => array('the_only_key' => 1))));
 | 
			
		||||
        $std = new stdClass();
 | 
			
		||||
        $std->value = 1;
 | 
			
		||||
        $std->other = 4;
 | 
			
		||||
        $this->assertEquals('1', $engine->render('{{#x}}{{value}}{{/x}}', array('x' => $std)));
 | 
			
		||||
        $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');
 | 
			
		||||
        $engine->render('{{>foo-again}}', array());
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user