Fix all foreach unit tests

This commit is contained in:
Simon Wisselink
2023-01-23 15:16:45 +01:00
parent ad2703dd75
commit 68c59e6627
7 changed files with 53 additions and 29 deletions

View File

@@ -32,7 +32,7 @@ class ForeachClose extends Base {
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
$compiler->loopNesting--;
[$openTag, $nocache_pushed, $local, $itemVar, $restore] = $this->closeTag($compiler, ['foreach', 'foreachelse']);
[$openTag, $nocache_pushed, $localVariablePrefix, $item, $restore] = $this->closeTag($compiler, ['foreach', 'foreachelse']);
if ($nocache_pushed) {
// pop the pushed virtual nocache tag
@@ -41,8 +41,8 @@ class ForeachClose extends Base {
}
$output = "<?php\n";
if ($restore === 2) {
$output .= "{$itemVar} = {$local}saved;\n";
if ($restore) {
$output .= "\$_smarty_tpl->setVariable('{$item}', {$localVariablePrefix}Backup);\n";
}
$output .= "}\n";
/* @var \Smarty\Compile\Tag\ForeachTag $foreachCompiler */

View File

@@ -22,13 +22,13 @@ class ForeachElse extends Base {
*/
public function compile($args, \Smarty\Compiler\Template $compiler, $parameter = [], $tag = null, $function = null) {
[$openTag, $nocache_pushed, $local, $itemVar, $restore] = $this->closeTag($compiler, ['foreach']);
$this->openTag($compiler, 'foreachelse', ['foreachelse', $nocache_pushed, $local, $itemVar, 0]);
[$openTag, $nocache_pushed, $localVariablePrefix, $item, $restore] = $this->closeTag($compiler, ['foreach']);
$this->openTag($compiler, 'foreachelse', ['foreachelse', $nocache_pushed, $localVariablePrefix, $item, false]);
$output = "<?php\n";
if ($restore === 2) {
$output .= "{$itemVar} = {$local}saved;\n";
if ($restore) {
$output .= "\$_smarty_tpl->setVariable('{$item}', {$localVariablePrefix}Backup);\n";
}
$output .= "}\nif ({$itemVar}->do_else) {\n?>";
$output .= "}\nif ({$localVariablePrefix}DoElse) {\n?>";
return $output;
}
}

View File

@@ -39,7 +39,7 @@ class ForeachTag extends ForeachSection {
*
* @var int
*/
protected $counter = 0;
private static $counter = 0;
/**
* Name of this tag
@@ -120,8 +120,10 @@ class ForeachTag extends ForeachSection {
}
}
}
$itemVar = "\$_smarty_tpl->tpl_vars['{$item}']";
$local = '$__foreach_' . $attributes['item'] . '_' . $this->counter++ . '_';
$itemVar = "\$_smarty_tpl->getVariable('{$item}')";
$localVariablePrefix = '$foreach' . self::$counter++;
// search for used tag attributes
$itemAttr = [];
$namedAttr = [];
@@ -172,7 +174,7 @@ class ForeachTag extends ForeachSection {
}
$keyTerm = '';
if (isset($attributes['key'])) {
$keyTerm = "\$_smarty_tpl->tpl_vars['{$key}']->value => ";
$keyTerm = "\$_smarty_tpl->getVariable('{$key}')->value => ";
}
if (isset($itemAttr['key'])) {
$keyTerm = "{$itemVar}->key => ";
@@ -191,7 +193,7 @@ class ForeachTag extends ForeachSection {
$this->openTag(
$compiler,
'foreach',
['foreach', $compiler->tag_nocache, $local, $itemVar, empty($itemAttr) ? 1 : 2]
['foreach', $compiler->tag_nocache, $localVariablePrefix, $item, !empty($itemAttr)]
);
// generate output code
@@ -217,9 +219,9 @@ class ForeachTag extends ForeachSection {
if (isset($itemAttr['index'])) {
$output .= "{$itemVar}->index = -1;\n";
}
$output .= "{$itemVar}->do_else = true;\n";
$output .= "if (\$_from !== null) foreach (\$_from as {$keyTerm}{$itemVar}->value) {\n";
$output .= "{$itemVar}->do_else = false;\n";
$output .= "{$localVariablePrefix}DoElse = true;\n";
$output .= "foreach (\$_from ?? [] as {$keyTerm}{$itemVar}->value) {\n";
$output .= "{$localVariablePrefix}DoElse = false;\n";
if (isset($attributes['key']) && isset($itemAttr['key'])) {
$output .= "\$_smarty_tpl->assign('{$key}', {$itemVar}->key);\n";
}
@@ -250,7 +252,7 @@ class ForeachTag extends ForeachSection {
}
}
if (!empty($itemAttr)) {
$output .= "{$local}saved = {$itemVar};\n";
$output .= "{$localVariablePrefix}Backup = clone \$_smarty_tpl->getVariable('{$item}');\n";
}
$output .= '?>';
return $output;

View File

@@ -126,7 +126,14 @@ class Data
break;
case self::SCOPE_LOCAL:
default:
$this->tpl_vars[ $tpl_var ] = new Variable($value, $nocache);
if ($this->hasVariable($tpl_var)) {
$this->getVariable($tpl_var)->setValue($value);
if ($nocache) {
$this->getVariable($tpl_var)->setNocache(true);
}
} else {
$this->tpl_vars[ $tpl_var ] = new Variable($value, $nocache);
}
}
return $this;
@@ -251,6 +258,17 @@ class Data
return new UndefinedVariable();
}
/**
* Directly sets a complete Variable object in the variable with the given name.
* @param $varName
* @param Variable $variableObject
*
* @return void
*/
public function setVariable($varName, Variable $variableObject) {
$this->tpl_vars[$varName] = $variableObject;
}
/**
* Indicates if given variable has been set.
* @param $varName

View File

@@ -624,12 +624,12 @@ expr(res) ::= ternary(v). {
// ++$a / --$a
expr(res) ::= INCDEC(i2) DOLLARID(i). {
res = '$_smarty_tpl->_getVariable(\''. substr(i,1) .'\')->preIncDec(\'' . i2 . '\')';
res = '$_smarty_tpl->getVariable(\''. substr(i,1) .'\')->preIncDec(\'' . i2 . '\')';
}
// $a++ / $a--
expr(res) ::= DOLLARID(i) INCDEC(i2). {
res = '$_smarty_tpl->_getVariable(\''. substr(i,1) .'\')->postIncDec(\'' . i2 . '\')';
res = '$_smarty_tpl->getVariable(\''. substr(i,1) .'\')->postIncDec(\'' . i2 . '\')';
}
// resources/streams
@@ -845,7 +845,7 @@ variable(res) ::= varindexed(vi). {
// variable with property
variable(res) ::= varvar(v) AT ID(p). {
res = '$_smarty_tpl->_getVariable('. v .')->'.p;
res = '$_smarty_tpl->getVariable('. v .')->'.p;
}
// object

View File

@@ -62,7 +62,7 @@ class ForeachRuntime {
if ($tpl->hasVariable($item)) {
$saveVars['item'] = [
$item,
$tpl->getVariable($item),
$tpl->getVariable($item)->getValue(),
];
}
$tpl->assign($item,null);
@@ -73,7 +73,7 @@ class ForeachRuntime {
if ($tpl->hasVariable($key)) {
$saveVars['key'] = [
$key,
$tpl->getVariable($key),
clone $tpl->getVariable($key),
];
}
$tpl->assign($key, null);
@@ -87,7 +87,7 @@ class ForeachRuntime {
if ($tpl->hasVariable($namedVar)) {
$saveVars['named'] = [
$namedVar,
$tpl->getVariable($namedVar),
clone $tpl->getVariable($namedVar),
];
}
$namedProp = [];
@@ -147,14 +147,13 @@ class ForeachRuntime {
$saveVars = array_pop($this->stack);
if (!empty($saveVars)) {
if (isset($saveVars['item'])) {
$item = &$saveVars['item'];
$tpl->assign($item[0], $item[1]->getValue());
$tpl->getVariable($saveVars['item'][0])->setValue($saveVars['item'][1]);
}
if (isset($saveVars['key'])) {
$tpl->tpl_vars[$saveVars['key'][0]] = $saveVars['key'][1];
$tpl->setVariable($saveVars['key'][0], $saveVars['key'][1]);
}
if (isset($saveVars['named'])) {
$tpl->tpl_vars[$saveVars['named'][0]] = $saveVars['named'][1];
$tpl->setVariable($saveVars['named'][0], $saveVars['named'][1]);
}
}
$levels--;

View File

@@ -19,6 +19,11 @@ class Variable
*/
public $value = null;
/**
* Other r/w properties for foreach, for, while, etc.
*/
public $step, $total, $first, $last, $key, $show, $iteration, $index = null;
/**
* @param mixed|null $value
*/
@@ -31,7 +36,7 @@ class Variable
*
* @var boolean
*/
public $nocache = false;
private $nocache = false;
/**
* @param bool $nocache