Merge pull request #2150 from hafriedlander/fix/templatevars-v2

FIX Arguments to method calls reseting scope
This commit is contained in:
Simon Welsh 2013-06-25 21:59:14 -07:00
commit aecda4882b
4 changed files with 89 additions and 8 deletions

View File

@ -1074,7 +1074,7 @@ after')
$origEnv = Config::inst()->get('Director', 'environment_type');
Config::inst()->update('Director', 'environment_type', 'dev');
Config::inst()->update('SSViewer', 'source_file_comments', true);
$f = FRAMEWORK_PATH . '/tests/templates/SSViewerTestComments';
$f = FRAMEWORK_PATH . '/tests/templates/SSViewerTestComments';
$templates = array(
array(
'name' => 'SSViewerTestCommentsFullSource',
@ -1090,7 +1090,8 @@ after')
array(
'name' => 'SSViewerTestCommentsFullSourceHTML4Doctype',
'expected' => ""
. "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\t\t\"http://www.w3.org/TR/html4/strict.dtd\">"
. "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML "
. "4.01//EN\"\t\t\"http://www.w3.org/TR/html4/strict.dtd\">"
. "<!-- template $f/SSViewerTestCommentsFullSourceHTML4Doctype.ss -->"
. "<html>"
. "\t<head></head>"
@ -1209,6 +1210,45 @@ after')
"tests/forms/RequirementsTest_a.js"
));
}
public function testCallsWithArguments() {
$data = new ArrayData(array(
'Set' => new ArrayList(array(
new SSViewerTest_Object("1"),
new SSViewerTest_Object("2"),
new SSViewerTest_Object("3"),
new SSViewerTest_Object("4"),
new SSViewerTest_Object("5"),
)),
'Level' => new SSViewerTest_LevelTest(1),
'Nest' => array(
'Level' => new SSViewerTest_LevelTest(2),
),
));
$tests = array(
'$Level.output(1)' => '1-1',
'$Nest.Level.output($Set.First.Number)' => '2-1',
'<% with $Set %>$Up.Level.output($First.Number)<% end_with %>' => '1-1',
'<% with $Set %>$Top.Nest.Level.output($First.Number)<% end_with %>' => '2-1',
'<% loop $Set %>$Up.Nest.Level.output($Number)<% end_loop %>' => '2-12-22-32-42-5',
'<% loop $Set %>$Top.Level.output($Number)<% end_loop %>' => '1-11-21-31-41-5',
'<% with $Nest %>$Level.output($Top.Set.First.Number)<% end_with %>' => '2-1',
'<% with $Level %>$output($Up.Set.Last.Number)<% end_with %>' => '1-5',
'<% with $Level.forWith($Set.Last.Number) %>$output("hi")<% end_with %>' => '5-hi',
'<% loop $Level.forLoop($Set.First.Number) %>$Number<% end_loop %>' => '!0',
'<% with $Nest %>
<% with $Level.forWith($Up.Set.First.Number) %>$output("hi")<% end_with %>
<% end_with %>' => '1-hi',
'<% with $Nest %>
<% loop $Level.forLoop($Top.Set.Last.Number) %>$Number<% end_loop %>
<% end_with %>' => '!0!1!2!3!4',
);
foreach($tests as $template => $expected) {
$this->assertEquals($expected, trim($this->render($template, $data)));
}
}
}
/**
@ -1347,3 +1387,28 @@ class SSViewerTest_GlobalProvider implements TemplateGlobalProvider, TestOnly {
}
}
class SSViewerTest_LevelTest extends ViewableData implements TestOnly {
protected $depth;
public function __construct($depth = 1) {
$this->depth = $depth;
}
public function output($val) {
return "$this->depth-$val";
}
public function forLoop($number) {
$ret = array();
for($i = 0; $i < (int)$number; ++$i) {
$ret[] = new SSViewerTest_Object("!$i");
}
return new ArrayList($ret);
}
public function forWith($number) {
return new self($number);
}
}

View File

@ -615,7 +615,7 @@ class SSTemplateParser extends Parser {
function Lookup__construct(&$res) {
$res['php'] = '$scope';
$res['php'] = '$scope->locally()';
$res['LookupSteps'] = array();
}

View File

@ -157,7 +157,7 @@ class SSTemplateParser extends Parser {
*/
function Lookup__construct(&$res) {
$res['php'] = '$scope';
$res['php'] = '$scope->locally()';
$res['LookupSteps'] = array();
}

View File

@ -49,18 +49,34 @@ class SSViewer_Scope {
public function __construct($item){
$this->item = $item;
$this->localIndex=0;
$this->localIndex = 0;
$this->localStack = array();
$this->itemStack[] = array($this->item, null, 0, null, null, 0);
}
public function getItem(){
return $this->itemIterator ? $this->itemIterator->current() : $this->item;
}
public function resetLocalScope(){
/** Called at the start of every lookup chain by SSTemplateParser to indicate a new lookup from local scope */
public function locally() {
list($this->item, $this->itemIterator, $this->itemIteratorTotal, $this->popIndex, $this->upIndex,
$this->currentIndex) = $this->itemStack[$this->localIndex];
array_splice($this->itemStack, $this->localIndex+1);
// Remember any un-completed (resetLocalScope hasn't been called) lookup chain. Even if there isn't an
// un-completed chain we need to store an empty item, as resetLocalScope doesn't know the difference later
$this->localStack[] = array_splice($this->itemStack, $this->localIndex+1);
return $this;
}
public function resetLocalScope(){
$previousLocalState = $this->localStack ? array_pop($this->localStack) : null;
array_splice($this->itemStack, $this->localIndex+1, count($this->itemStack), $previousLocalState);
list($this->item, $this->itemIterator, $this->itemIteratorTotal, $this->popIndex, $this->upIndex,
$this->currentIndex) = end($this->itemStack);
}
public function getObj($name, $arguments = null, $forceReturnedObject = true, $cache = false, $cacheName = null) {