Browse files

FEATURE: <% include %> inherits iterator scope of parent template

  • Loading branch information...
1 parent 596934b commit f6ff39369fb1646d95fd66bbd45dca10c9f18e65 @jthomerson jthomerson committed Jun 26, 2013
View
3 tests/templates/SSViewerTestIncludeScopeInheritance.ss
@@ -0,0 +1,3 @@
+<% loop Items %>
+ <% include SSViewerTestIncludeScopeInheritanceInclude %>
+<% end_loop %>
View
1 tests/templates/SSViewerTestIncludeScopeInheritanceInclude.ss
@@ -0,0 +1 @@
+$Title <% if ArgA %>- $ArgA <% end_if %>- <%if First %>First-<% end_if %><% if Last %>Last-<% end_if %><%if MultipleOf(2) %>EVEN<% else %>ODD<% end_if %> top:$Top.Title
View
3 tests/templates/SSViewerTestIncludeScopeInheritanceWithArgs.ss
@@ -0,0 +1,3 @@
+<% loop Items %>
+ <% include SSViewerTestIncludeScopeInheritanceInclude ArgA=$Title %>
+<% end_loop %>
View
52 tests/view/SSViewerTest.php
@@ -29,7 +29,57 @@ public function testTemplateWithoutHeadRenders() {
$result = $data->renderWith("SSViewerTestPartialTemplate");
$this->assertEquals('Test partial template: var value', trim(preg_replace("/<!--.*-->/U",'',$result)));
}
-
+
+ public function testIncludeScopeInheritance() {
+ $data = $this->getScopeInheritanceTestData();
+ $expected = array(
+ 'Item 1 - First-ODD top:Item 1',
+ 'Item 2 - EVEN top:Item 2',
+ 'Item 3 - ODD top:Item 3',
+ 'Item 4 - EVEN top:Item 4',
+ 'Item 5 - ODD top:Item 5',
+ 'Item 6 - Last-EVEN top:Item 6',
+ );
+
+ $result = $data->renderWith('SSViewerTestIncludeScopeInheritance');
+ $this->assertExpectedStrings($result, $expected);
+
+ // reset results for the tests that include arguments (the title is passed as an arg)
+ $expected = array(
+ 'Item 1 - Item 1 - First-ODD top:Item 1',
+ 'Item 2 - Item 2 - EVEN top:Item 2',
+ 'Item 3 - Item 3 - ODD top:Item 3',
+ 'Item 4 - Item 4 - EVEN top:Item 4',
+ 'Item 5 - Item 5 - ODD top:Item 5',
+ 'Item 6 - Item 6 - Last-EVEN top:Item 6',
+ );
+
+ $result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs');
+ $this->assertExpectedStrings($result, $expected);
+ }
+
+ private function getScopeInheritanceTestData() {
+ return new ArrayData(array(
+ 'Title' => 'TopTitleValue',
+ 'Items' => new ArrayList(array(
+ new ArrayData(array('Title' => 'Item 1')),
+ new ArrayData(array('Title' => 'Item 2')),
+ new ArrayData(array('Title' => 'Item 3')),
+ new ArrayData(array('Title' => 'Item 4')),
+ new ArrayData(array('Title' => 'Item 5')),
+ new ArrayData(array('Title' => 'Item 6'))
+ ))
+ ));
+ }
+
+ private function assertExpectedStrings($result, $expected) {
+ foreach ($expected as $expectedStr) {
+ $this->assertTrue(
+ (boolean) preg_match("/{$expectedStr}/", $result),
+ "Didn't find '{$expectedStr}' in:\n{$result}"
+ );
+ }
+ }
/**
* Small helper to render templates from strings
View
2 view/SSTemplateParser.php
@@ -3242,7 +3242,7 @@ function Include__finalise(&$res){
$arguments = $res['arguments'];
$res['php'] = '$val .= SSViewer::execute_template('.$template.', $scope->getItem(), array(' .
- implode(',', $arguments)."));\n";
+ implode(',', $arguments)."), \$scope);\n";
if($this->includeDebuggingComments) { // Add include filename comments on dev sites
$res['php'] =
View
2 view/SSTemplateParser.php.inc
@@ -701,7 +701,7 @@ class SSTemplateParser extends Parser {
$arguments = $res['arguments'];
$res['php'] = '$val .= SSViewer::execute_template('.$template.', $scope->getItem(), array(' .
- implode(',', $arguments)."));\n";
+ implode(',', $arguments)."), \$scope);\n";
if($this->includeDebuggingComments) { // Add include filename comments on dev sites
$res['php'] =
View
36 view/SSViewer.php
@@ -47,11 +47,17 @@ class SSViewer_Scope {
private $localIndex;
- public function __construct($item){
+ public function __construct($item, $inheritedScope = null) {
$this->item = $item;
$this->localIndex = 0;
$this->localStack = array();
- $this->itemStack[] = array($this->item, null, 0, null, null, 0);
+ if ($inheritedScope instanceof SSViewer_Scope) {
+ $this->itemIterator = $inheritedScope->itemIterator;
+ $this->itemIteratorTotal = $inheritedScope->itemIteratorTotal;
+ $this->itemStack[] = array($this->item, $this->itemIterator, $this->itemIteratorTotal, null, null, 0);
+ } else {
+ $this->itemStack[] = array($this->item, null, 0, null, null, 0);
+ }
}
public function getItem(){
@@ -357,8 +363,8 @@ class SSViewer_DataPresenter extends SSViewer_Scope {
*/
protected $underlay;
- public function __construct($item, $overlay = null, $underlay = null){
- parent::__construct($item);
+ public function __construct($item, $overlay = null, $underlay = null, $inheritedScope = null) {
+ parent::__construct($item, $inheritedScope);
// Build up global property providers array only once per request
if (self::$globalProperties === null) {
@@ -553,7 +559,7 @@ class SSViewer {
* @var boolean $source_file_comments
*/
private static $source_file_comments = false;
-
+
/**
* Set whether HTML comments indicating the source .SS file used to render this page should be
* included in the output. This is enabled by default
@@ -895,10 +901,11 @@ public function includeRequirements($incl = true) {
* @param Object $item - The item to use as the root scope for the template
* @param array|null $overlay - Any variables to layer on top of the scope
* @param array|null $underlay - Any variables to layer underneath the scope
+ * @param Object $inheritedScope - the current scope of a parent template including a sub-template
*
* @return string - The result of executing the template
*/
- protected function includeGeneratedTemplate($cacheFile, $item, $overlay, $underlay) {
+ protected function includeGeneratedTemplate($cacheFile, $item, $overlay, $underlay, $inheritedScope = null) {
if(isset($_GET['showtemplate']) && $_GET['showtemplate'] && Permission::check('ADMIN')) {
$lines = file($cacheFile);
echo "<h2>Template: $cacheFile</h2>";
@@ -910,7 +917,7 @@ protected function includeGeneratedTemplate($cacheFile, $item, $overlay, $underl
}
$cache = $this->getPartialCacheStore();
- $scope = new SSViewer_DataPresenter($item, $overlay, $underlay);
+ $scope = new SSViewer_DataPresenter($item, $overlay, $underlay, $inheritedScope);
$val = '';
include($cacheFile);
@@ -930,11 +937,12 @@ protected function includeGeneratedTemplate($cacheFile, $item, $overlay, $underl
* Note: You can call this method indirectly by {@link ViewableData->renderWith()}.
*
* @param ViewableData $item
- * @param SS_Cache $cache Optional cache backend.
+ * @param array|null $arguments - arguments to an included template
+ * @param Object $inheritedScope - the current scope of a parent template including a sub-template
*
* @return HTMLText Parsed template output.
*/
- public function process($item, $arguments = null) {
+ public function process($item, $arguments = null, $inheritedScope = null) {
SSViewer::$topLevel[] = $item;
if ($arguments && $arguments instanceof Zend_Cache_Core) {
@@ -979,7 +987,7 @@ public function process($item, $arguments = null) {
}
}
- $output = $this->includeGeneratedTemplate($cacheFile, $item, $arguments, $underlay);
+ $output = $this->includeGeneratedTemplate($cacheFile, $item, $arguments, $underlay, $inheritedScope);
if($this->includeRequirements) {
$output = Requirements::includeInHTML($template, $output);
@@ -1009,11 +1017,11 @@ public function process($item, $arguments = null) {
* Execute the given template, passing it the given data.
* Used by the <% include %> template tag to process templates.
*/
- public static function execute_template($template, $data, $arguments = null) {
+ public static function execute_template($template, $data, $arguments = null, $scope = null) {
$v = new SSViewer($template);
$v->includeRequirements(false);
- return $v->process($data, $arguments);
+ return $v->process($data, $arguments, $scope);
}
public static function parseTemplateContent($content, $template="") {
@@ -1071,7 +1079,7 @@ public function __construct($content) {
$this->content = $content;
}
- public function process($item, $arguments = null) {
+ public function process($item, $arguments = null, $scope = null) {
if ($arguments && $arguments instanceof Zend_Cache_Core) {
Deprecation::notice('3.0', 'Use setPartialCacheStore to override the partial cache storage backend, ' .
'the second argument to process is now an array of variables.');
@@ -1086,7 +1094,7 @@ public function process($item, $arguments = null) {
fwrite($fh, $template);
fclose($fh);
- $val = $this->includeGeneratedTemplate($tmpFile, $item, $arguments, null);
+ $val = $this->includeGeneratedTemplate($tmpFile, $item, $arguments, null, $scope);
unlink($tmpFile);
return $val;

0 comments on commit f6ff393

Please sign in to comment.