Fixed scope in variable assignments in included and extended templates, fixed dependencies for testing freshness of caches. Added some unit tests and fixed a class reference to pass some more tests.

This commit is contained in:
Simon Wisselink
2023-01-13 23:29:05 +01:00
parent b02061878f
commit f5b432dea4
10 changed files with 85 additions and 21 deletions

View File

@@ -65,7 +65,7 @@ class Assign extends Base
if ($_attr[ 'noscope' ]) {
$_scope = -1;
} else {
$_scope = isset($_attr['scope']) ? $this->convertScope($_attr['scope']) : 0;
$_scope = isset($_attr['scope']) ? $this->convertScope($_attr['scope']) : null;
}
// optional parameter
$_params = '';
@@ -80,9 +80,9 @@ class Assign extends Base
$output .= "settype(\$_tmp_array, 'array');\n";
$output .= "}\n";
$output .= "\$_tmp_array{$parameter['smarty_internal_index']} = {$_attr['value']};\n";
$output .= "\$_smarty_tpl->assign({$_var}, \$_tmp_array{$_params}, false, {$_scope});?>";
$output .= "\$_smarty_tpl->assign({$_var}, \$_tmp_array{$_params}, false, " . var_export($_scope, true) . ");?>";
} else {
$output = "<?php \$_smarty_tpl->assign({$_var}, {$_attr['value']}{$_params}, false, {$_scope});?>";
$output = "<?php \$_smarty_tpl->assign({$_var}, {$_attr['value']}{$_params}, false, " . var_export($_scope, true) . ");?>";
}
return $output;
}

View File

@@ -217,7 +217,9 @@ class IncludeTag extends Base {
if (isset($_assign)) {
$_output .= "ob_start();\n";
}
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, {$_cache_id}, \$_smarty_tpl->compile_id, {$_caching}, {$_cache_lifetime}, {$_vars}, '{$compiler->getParentCompiler()->mergedSubTemplatesData[$uid][$t_hash]['uid']}', '{$compiler->getParentCompiler()->mergedSubTemplatesData[$uid][$t_hash]['func']}');\n";
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, {$_cache_id}, \$_smarty_tpl->compile_id,
{$_caching}, {$_cache_lifetime}, {$_vars}, '{$compiler->getParentCompiler()->mergedSubTemplatesData[$uid][$t_hash]['uid']}',
'{$compiler->getParentCompiler()->mergedSubTemplatesData[$uid][$t_hash]['func']}', (int) {$_scope});\n";
if (isset($_assign)) {
$_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean(), false, {$_scope});\n";
}
@@ -232,7 +234,7 @@ class IncludeTag extends Base {
if (isset($_assign)) {
$_output .= "ob_start();\n";
}
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, $_cache_id, \$_smarty_tpl->compile_id, $_caching, $_cache_lifetime, $_vars);\n";
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, $_cache_id, \$_smarty_tpl->compile_id, $_caching, $_cache_lifetime, $_vars, null, null, (int) {$_scope});\n";
if (isset($_assign)) {
$_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean(), false, {$_scope});\n";
}

View File

@@ -72,8 +72,10 @@ class CodeFrame
$output .= ");\n";
}
if ($cache && $this->_template->getSmarty()->hasRuntime('TplFunction')) {
$output .= "\$_smarty_tpl->getSmarty()->getRuntime('TplFunction')->registerTplFunctions(\$_smarty_tpl, " .
var_export($this->_template->getSmarty()->getRuntime('TplFunction')->getTplFunction($this->_template), true) . ");\n";
if ($tplfunctions = $this->_template->getSmarty()->getRuntime('TplFunction')->getTplFunction($this->_template)) {
$output .= "\$_smarty_tpl->getSmarty()->getRuntime('TplFunction')->registerTplFunctions(\$_smarty_tpl, " .
var_export($tplfunctions, true) . ");\n";
}
}
$output .= "?>";
$output .= $content;

View File

@@ -47,6 +47,12 @@ class Data
*/
public $config_vars = array();
/**
* Default scope for new variables
* @var int
*/
private $defaultScope = self::SCOPE_LOCAL;
/**
* create Smarty data object
*
@@ -83,7 +89,7 @@ class Data
* @return Data current Data (or Smarty or \Smarty\Template) instance for
* chaining
*/
public function assign($tpl_var, $value = null, $nocache = false, $scope = 0)
public function assign($tpl_var, $value = null, $nocache = false, $scope = null)
{
if (is_array($tpl_var)) {
foreach ($tpl_var as $_key => $_val) {
@@ -91,8 +97,7 @@ class Data
}
return;
}
switch ($scope) {
switch ($scope ?? $this->getDefaultScope()) {
case self::SCOPE_GLOBAL:
case self::SCOPE_SMARTY:
$this->getSmarty()->assign($tpl_var, $value);
@@ -119,6 +124,7 @@ class Data
$this->assign($tpl_var, $value);
}
break;
case self::SCOPE_LOCAL:
default:
$this->tpl_vars[ $tpl_var ] = new Variable($value, $nocache);
}
@@ -439,4 +445,21 @@ class Data
return $this;
}
/**
* Sets the default scope for new variables assigned in this template.
* @param int $scope
*
* @return void
*/
protected function setDefaultScope(int $scope) {
$this->defaultScope = $scope;
}
/**
* Returns the default scope for new variables assigned in this template.
* @return int
*/
public function getDefaultScope(): int {
return $this->defaultScope;
}
}

View File

@@ -105,6 +105,7 @@ class Template extends TemplateBase {
*/
private $right_delimiter = null;
/**
* Create template data object
* Some of the global Smarty settings copied to template scope
@@ -233,13 +234,13 @@ class Template extends TemplateBase {
* @param mixed $cache_id cache id
* @param mixed $compile_id compile id
* @param integer $caching cache mode
* @param integer $cache_lifetime life time of cache data
* @param integer $cache_lifetime lifetime of cache data
* @param array $extra_vars passed parameter template variables
* @param string $uid file dependency uid
* @param string $content_func function name
* @param null $uid file dependency uid
* @param null $content_func function name
* @param int|null $scope
*
* @throws \Exception
* @throws \Smarty\Exception
* @throws Exception
*/
public function _subTemplateRender(
$template_name,
@@ -249,12 +250,18 @@ class Template extends TemplateBase {
$cache_lifetime,
array $extra_vars,
$uid = null,
$content_func = null
$content_func = null,
int $scope = null
) {
$baseFilePath = $this->source && $this->getSource()->filepath ? dirname($this->getSource()->filepath) : null;
$tpl = $this->getSmarty()->createTemplate($template_name, $cache_id, $compile_id, $this, $caching, $cache_lifetime, $baseFilePath);
$tpl->setCached($this->getCached()); // re-use the same Cache object across subtemplates to gather hashes and file dependencies.
if ($scope) {
$tpl->setDefaultScope($scope);
}
// copy variables
$tpl->tpl_vars = $this->tpl_vars;
@@ -313,9 +320,6 @@ class Template extends TemplateBase {
// $tpl->render();
// }
}
// Merge the hashes... @TODO refactor this?
$this->getCached()->hashes = array_merge($this->getCached()->hashes, $tpl->getCached()->hashes);
}
/**
@@ -327,7 +331,7 @@ class Template extends TemplateBase {
return isset($this->parent) && $this->parent instanceof Template;
}
public function assign($tpl_var, $value = null, $nocache = false, $scope = 0) {
public function assign($tpl_var, $value = null, $nocache = false, $scope = null) {
return parent::assign($tpl_var, $value, $nocache || $this->isRenderingCache, $scope);
}
@@ -810,4 +814,16 @@ class Template extends TemplateBase {
public function setSource($source): void {
$this->source = $source;
}
/**
* Sets the Cached object, so subtemplates can share one Cached object to gather meta-data.
*
* @param Cached $cached
*
* @return void
*/
private function setCached(Cached $cached) {
$this->cached = $cached;
}
}

View File

@@ -89,6 +89,23 @@ class ExtendsResourceTest extends PHPUnit_Smarty
$this->assertStringContainsString("test:{$testNumber} compiled:{$compileTestNumber} rendered:{$renderTestNumber}", $result, $testName . ' - fetch() failure');
}
/**
* @dataProvider data
*/
public function testCompileBlockIncreaseInChild_050($caching, $merge, $testNumber, $compileTestNumber, $renderTestNumber, $testName)
{
$this->smarty->registerFilter('pre', array($this, 'compiledPrefilter'));
$this->smarty->assign('test', $testNumber);
$this->smarty->caching = $caching;
$this->smarty->merge_compiled_includes = $merge;
if ($merge) {
$this->smarty->compile_id = 1;
}
$result = $this->smarty->fetch('extends:050_parent.tpl|050_child.tpl|050_grandchild.tpl');
$this->assertStringContainsString("var-bar-var", $result, $testName . ' - content');
$this->assertStringContainsString("test:{$testNumber} compiled:{$compileTestNumber} rendered:{$renderTestNumber}", $result, $testName . ' - fetch() failure');
}
/**
* test grandchild/child/parent dependency test1
*/

View File

@@ -0,0 +1 @@
{$notfoo="notbar"}

View File

@@ -0,0 +1 @@
{$foo="bar"}

View File

@@ -0,0 +1,2 @@
test:{$test nocache} compiled:# rendered:{$test}
{block name='test'}var-{$foo}-var{/block}

View File

@@ -36,7 +36,7 @@ function smarty_function_checkvar($params, \Smarty\Template $template)
$i ++;
}
$ptr = $ptr->parent;
} elseif (in_array('data', $types) && !($ptr instanceof Template || $ptr instanceof Smarty)) {
} elseif (in_array('data', $types) && !($ptr instanceof Template || $ptr instanceof \Smarty\Smarty)) {
$output .= "#data:\${$var} =";
$output .= $ptr->hasVariable($var) ? preg_replace('/\s/', '', var_export($ptr->getValue($var), true)) : '>unassigned<';
$ptr = $ptr->parent;