Inherit parent vars and add own vars when a template is included with vars from another template that has vars; add unit tests for vars inheritance

This commit is contained in:
Kijin Sung 2023-10-21 13:52:02 +09:00
parent 5b47151440
commit 6085b82d19
7 changed files with 92 additions and 12 deletions

View file

@ -215,7 +215,7 @@ class Template
}
elseif (is_object($vars))
{
$this->vars = $vars;
$this->vars = clone $vars;
}
else
{
@ -223,6 +223,25 @@ class Template
}
}
/**
* Add vars.
*
* @param array|object $vars
* @return void
*/
public function addVars($vars): void
{
if (!isset($this->vars))
{
$this->vars = new \stdClass;
}
foreach (is_object($vars) ? get_object_vars($vars) : $vars as $key => $val)
{
$this->vars->$key = $val;
}
}
/**
* Compile and execute a template file.
*
@ -535,9 +554,13 @@ class Template
}
// Set variables.
if ($this->vars)
{
$template->setVars($this->vars);
}
if ($vars !== null)
{
$template->setVars($vars);
$template->addVars($vars);
}
// Compile and return.

View file

@ -402,7 +402,8 @@ class TemplateParser_v2
// Generate the code to create a new Template object and compile it.
$tpl = '<?php $__tpl = new \Rhymix\Framework\Template(' . $dir . ', "' . $path . '", "' . ($this->template->extension ?: 'auto') . '"); ';
$tpl .= !empty($attrs['vars']) ? '$__tpl->setVars(' . self::_convertVariableScope($attrs['vars']) . '); ' : '';
$tpl .= 'if ($this->vars): $__tpl->setVars($this->vars); endif; ';
$tpl .= !empty($attrs['vars']) ? '$__tpl->addVars(' . self::_convertVariableScope($attrs['vars']) . '); ' : '';
$tpl .= 'echo $__tpl->compile(); ?>';
// Add conditions around the code.

View file

@ -0,0 +1,3 @@
<config version="2" />
<div>{{ $foobar }}</div>
<div>{{ $globalonly }}</div>

View file

@ -0,0 +1,5 @@
<config version="2" />
<div class="self">{{ $foobar }}</div>
<div class="incl">
<include src="incl/scopetest1.html" vars="['foobar' => 'Included #3']" />
</div>

View file

@ -0,0 +1,18 @@
<div class="global">
<div>Rhymix Template</div>
<div>Context Variable</div>
</div>
<div class="test1">
<div>Included #1</div>
<div></div>
</div>
<div class="test2">
<div class="self">Included #2</div>
<div class="incl">
<div>Included #3</div>
<div></div>
</div>
</div>

View file

@ -0,0 +1,18 @@
@version(2)
@php
$foobar = 'Rhymix Template';
$globalonly = 'Context Variable';
@endphp
<div class="global">
@include ('incl/scopetest1.html')
</div>
<div class="test1">
@include ('incl/scopetest1.html', ['foobar' => 'Included #1'])
</div>
<div class="test2">
@include ('incl/scopetest2.html', ['foobar' => 'Included #2'])
</div>

View file

@ -50,42 +50,42 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
{
// Basic usage
$source = '<include src="foobar" />';
$target = '<?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "foobar", "html"); echo $__tpl->compile(); ?>';
$target = '<?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "foobar", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>';
$this->assertEquals($target, $this->_parse($source));
// Legacy 'target' attribute
$source = '<include target="subdir/foobar" />';
$target = '<?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "subdir/foobar", "html"); echo $__tpl->compile(); ?>';
$target = '<?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "subdir/foobar", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?>';
$this->assertEquals($target, $this->_parse($source));
// Conditional include
$source = '<include src="../up/foobar" if="$cond" />';
$target = '<?php if(!empty($cond)): ?><?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "../up/foobar", "html"); echo $__tpl->compile(); ?><?php endif; ?>';
$target = '<?php if(!empty($cond)): ?><?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "../up/foobar", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?><?php endif; ?>';
$this->assertEquals($target, $this->_parse($source));
// Conditional include with legacy 'cond' attribute
$source = '<include target="legacy/cond.statement.html" cond="$cond" />';
$target = '<?php if(!empty($cond)): ?><?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "legacy/cond.statement.html", "html"); echo $__tpl->compile(); ?><?php endif; ?>';
$target = '<?php if(!empty($cond)): ?><?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "legacy/cond.statement.html", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?><?php endif; ?>';
$this->assertEquals($target, $this->_parse($source));
// Path relative to Rhymix installation directory
$source = '<include src="^/modules/foobar/views/baz" when="$cond" />';
$target = '<?php if(!empty($cond)): ?><?php $__tpl = new \Rhymix\Framework\Template("modules/foobar/views", "baz", "html"); echo $__tpl->compile(); ?><?php endif; ?>';
$target = '<?php if(!empty($cond)): ?><?php $__tpl = new \Rhymix\Framework\Template("modules/foobar/views", "baz", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?><?php endif; ?>';
$this->assertEquals($target, $this->_parse($source));
// Unless
$source = '<include src="^/modules/foobar/views/baz" unless="$cond" />';
$target = '<?php if(empty($cond)): ?><?php $__tpl = new \Rhymix\Framework\Template("modules/foobar/views", "baz", "html"); echo $__tpl->compile(); ?><?php endif; ?>';
$target = '<?php if(empty($cond)): ?><?php $__tpl = new \Rhymix\Framework\Template("modules/foobar/views", "baz", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?><?php endif; ?>';
$this->assertEquals($target, $this->_parse($source));
// With variables
$source = '<include src="foobar" vars="$vars" />';
$target = '<?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "foobar", "html"); $__tpl->setVars($__Context->vars); echo $__tpl->compile(); ?>';
$target = '<?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "foobar", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; $__tpl->addVars($__Context->vars); echo $__tpl->compile(); ?>';
$this->assertEquals($target, $this->_parse($source));
// With array literal passed as variables
$source = '<include src="foobar" vars="[\'foo\' => \'bar\']" />';
$target = '<?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "foobar", "html"); $__tpl->setVars([\'foo\' => \'bar\']); echo $__tpl->compile(); ?>';
$target = '<?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "foobar", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; $__tpl->addVars([\'foo\' => \'bar\']); echo $__tpl->compile(); ?>';
$this->assertEquals($target, $this->_parse($source));
// Blade-style @include
@ -1071,7 +1071,7 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
// cond is OK in includes
$source = '<include src="foo.html" cond="$bar" />';
$target = '<?php if(!empty($bar)): ?><?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "foo.html", "html"); echo $__tpl->compile(); ?><?php endif; ?>';;
$target = '<?php if(!empty($bar)): ?><?php $__tpl = new \Rhymix\Framework\Template($this->relative_dirname, "foo.html", "html"); if ($this->vars): $__tpl->setVars($this->vars); endif; echo $__tpl->compile(); ?><?php endif; ?>';;
$this->assertEquals($target, $this->_parse($source));
// loop
@ -1171,6 +1171,18 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
$this->_normalizeWhitespace($expected),
$this->_normalizeWhitespace($executed_output)
);
// Variable scope check
$tmpl = new \Rhymix\Framework\Template('./tests/_data/template', 'v2varscope.html');
$tmpl->disableCache();
$executed_output = $tmpl->compile();
//Rhymix\Framework\Storage::write(\RX_BASEDIR . 'tests/_data/template/v2varscope.executed.html', $executed_output);
$expected = file_get_contents(\RX_BASEDIR . 'tests/_data/template/v2varscope.executed.html');
$this->assertEquals(
$this->_normalizeWhitespace($expected),
$this->_normalizeWhitespace($executed_output)
);
}
/**