mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #2139 from jthomerson/pulls/template_includes_with_scope
FEATURE: <% include %> inherits scope of parent template
This commit is contained in:
commit
10b55170ea
3
tests/templates/SSViewerTestIncludeScopeInheritance.ss
Normal file
3
tests/templates/SSViewerTestIncludeScopeInheritance.ss
Normal file
@ -0,0 +1,3 @@
|
||||
<% loop Items %>
|
||||
<% include SSViewerTestIncludeScopeInheritanceInclude %>
|
||||
<% end_loop %>
|
@ -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
|
@ -0,0 +1,3 @@
|
||||
<% loop Items %>
|
||||
<% include SSViewerTestIncludeScopeInheritanceInclude ArgA=$Title %>
|
||||
<% end_loop %>
|
@ -29,7 +29,57 @@ class SSViewerTest extends SapphireTest {
|
||||
$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
|
||||
|
@ -3242,7 +3242,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'] =
|
||||
|
@ -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'] =
|
||||
|
@ -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 @@ class SSViewer {
|
||||
* @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 @@ class SSViewer {
|
||||
}
|
||||
|
||||
$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 @@ class SSViewer {
|
||||
* 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 @@ class SSViewer {
|
||||
}
|
||||
}
|
||||
|
||||
$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 @@ class SSViewer {
|
||||
* 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 @@ class SSViewer_FromString extends SSViewer {
|
||||
$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 @@ class SSViewer_FromString extends SSViewer {
|
||||
fwrite($fh, $template);
|
||||
fclose($fh);
|
||||
|
||||
$val = $this->includeGeneratedTemplate($tmpFile, $item, $arguments, null);
|
||||
$val = $this->includeGeneratedTemplate($tmpFile, $item, $arguments, null, $scope);
|
||||
|
||||
unlink($tmpFile);
|
||||
return $val;
|
||||
|
Loading…
Reference in New Issue
Block a user