From 68c59e662765bdf9379712f764144249a8bd1830 Mon Sep 17 00:00:00 2001 From: Simon Wisselink Date: Mon, 23 Jan 2023 15:16:45 +0100 Subject: [PATCH] Fix all foreach unit tests --- src/Compile/Tag/ForeachClose.php | 6 +++--- src/Compile/Tag/ForeachElse.php | 10 +++++----- src/Compile/Tag/ForeachTag.php | 20 +++++++++++--------- src/Data.php | 20 +++++++++++++++++++- src/Parser/TemplateParser.y | 6 +++--- src/Runtime/ForeachRuntime.php | 13 ++++++------- src/Variable.php | 7 ++++++- 7 files changed, 53 insertions(+), 29 deletions(-) diff --git a/src/Compile/Tag/ForeachClose.php b/src/Compile/Tag/ForeachClose.php index 76975452..80599149 100644 --- a/src/Compile/Tag/ForeachClose.php +++ b/src/Compile/Tag/ForeachClose.php @@ -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 = "setVariable('{$item}', {$localVariablePrefix}Backup);\n"; } $output .= "}\n"; /* @var \Smarty\Compile\Tag\ForeachTag $foreachCompiler */ diff --git a/src/Compile/Tag/ForeachElse.php b/src/Compile/Tag/ForeachElse.php index 073478b1..3397bb4f 100644 --- a/src/Compile/Tag/ForeachElse.php +++ b/src/Compile/Tag/ForeachElse.php @@ -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 = "setVariable('{$item}', {$localVariablePrefix}Backup);\n"; } - $output .= "}\nif ({$itemVar}->do_else) {\n?>"; + $output .= "}\nif ({$localVariablePrefix}DoElse) {\n?>"; return $output; } } \ No newline at end of file diff --git a/src/Compile/Tag/ForeachTag.php b/src/Compile/Tag/ForeachTag.php index da9712ae..c77a5464 100644 --- a/src/Compile/Tag/ForeachTag.php +++ b/src/Compile/Tag/ForeachTag.php @@ -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; diff --git a/src/Data.php b/src/Data.php index dfa11934..eb0308aa 100644 --- a/src/Data.php +++ b/src/Data.php @@ -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 diff --git a/src/Parser/TemplateParser.y b/src/Parser/TemplateParser.y index 9ea9bde4..1c604e3c 100644 --- a/src/Parser/TemplateParser.y +++ b/src/Parser/TemplateParser.y @@ -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 diff --git a/src/Runtime/ForeachRuntime.php b/src/Runtime/ForeachRuntime.php index 5012ce4d..fc311df0 100644 --- a/src/Runtime/ForeachRuntime.php +++ b/src/Runtime/ForeachRuntime.php @@ -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--; diff --git a/src/Variable.php b/src/Variable.php index bd66b872..0e38d125 100644 --- a/src/Variable.php +++ b/src/Variable.php @@ -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