From efd40aa8465054967c31682ae77c269812c221fc Mon Sep 17 00:00:00 2001 From: maryo Date: Mon, 23 Jan 2023 15:11:45 +0100 Subject: [PATCH] Bubbling up of parent scope in template blocks with inheritance chain --- CHANGELOG.md | 1 + .../smarty_internal_method_configload.php | 5 ++--- .../smarty_internal_runtime_updatescope.php | 19 ++++++++++++++++--- .../TemplateSource/X_Scopes/ScopeTest.php | 11 ++++++++++- .../test_scope_inheritance_child.tpl | 1 + ..._scope_inheritance_child_assign_parent.tpl | 1 + .../test_scope_inheritance_include.tpl | 1 + ...cope_inheritance_include_assign_parent.tpl | 1 + .../test_scope_inheritance_parent.tpl | 1 + ...scope_inheritance_parent_assign_parent.tpl | 1 + 10 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_child.tpl create mode 100644 tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_child_assign_parent.tpl create mode 100644 tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_include.tpl create mode 100644 tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_include_assign_parent.tpl create mode 100644 tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_parent.tpl create mode 100644 tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_parent_assign_parent.tpl diff --git a/CHANGELOG.md b/CHANGELOG.md index d300faff4..7697525ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed +- Updating variable in parent scope (when the `scope=parent` is explicitly used on a tag like `assign`) now bubbles up (to the including template) even when the included template is part of an inheritance chain as it did pre `v3.1.28`. - `$smarty->muteUndefinedOrNullWarnings()` now also mutes PHP7 notices for undefined array indexes [#736](https://github.com/smarty-php/smarty/issues/736) - `$smarty->muteUndefinedOrNullWarnings()` now treats undefined vars and array access of a null or false variables equivalent across all supported PHP versions diff --git a/libs/sysplugins/smarty_internal_method_configload.php b/libs/sysplugins/smarty_internal_method_configload.php index c3174d2d0..2a476d13d 100644 --- a/libs/sysplugins/smarty_internal_method_configload.php +++ b/libs/sysplugins/smarty_internal_method_configload.php @@ -89,11 +89,10 @@ public function _loadConfigVars(Smarty_Internal_Template $tpl, $new_config_vars) } } if ($tpl->parent->_isTplObj() && ($tagScope || $tpl->parent->scope)) { - $mergedScope = $tagScope | $tpl->scope; - if ($mergedScope) { + if ($tagScope | $tpl->scope) { // update scopes /* @var \Smarty_Internal_Template|\Smarty|\Smarty_Internal_Data $ptr */ - foreach ($tpl->smarty->ext->_updateScope->_getAffectedScopes($tpl->parent, $mergedScope) as $ptr) { + foreach ($tpl->smarty->ext->_updateScope->_getAffectedScopes($tpl->parent, $tagScope) as $ptr) { $this->_assignConfigVars($ptr->config_vars, $tpl, $new_config_vars); if ($tagScope && $ptr->_isTplObj() && isset($tpl->_cache[ 'varStack' ])) { $this->_updateVarStack($tpl, $new_config_vars); diff --git a/libs/sysplugins/smarty_internal_runtime_updatescope.php b/libs/sysplugins/smarty_internal_runtime_updatescope.php index 2240f97ca..1470dd2c7 100644 --- a/libs/sysplugins/smarty_internal_runtime_updatescope.php +++ b/libs/sysplugins/smarty_internal_runtime_updatescope.php @@ -31,7 +31,7 @@ public function _updateScope(Smarty_Internal_Template $tpl, $varName, $tagScope Smarty::$global_tpl_vars[ $varName ] = $tpl->tpl_vars[ $varName ]; } // update scopes - foreach ($this->_getAffectedScopes($tpl, $mergedScope) as $ptr) { + foreach ($this->_getAffectedScopes($tpl, $tagScope) as $ptr) { $this->_updateVariableInOtherScope($ptr->tpl_vars, $tpl, $varName); if ($tagScope && $ptr->_isTplObj() && isset($tpl->_cache[ 'varStack' ])) { $this->_updateVarStack($ptr, $varName); @@ -44,16 +44,29 @@ public function _updateScope(Smarty_Internal_Template $tpl, $varName, $tagScope * Get array of objects which needs to be updated by given scope value * * @param Smarty_Internal_Template $tpl - * @param int $mergedScope merged tag and template scope to which bubble up variable value + * @param int $tagScope tag scope to which bubble up variable value * * @return array */ - public function _getAffectedScopes(Smarty_Internal_Template $tpl, $mergedScope) + public function _getAffectedScopes(Smarty_Internal_Template $tpl, $tagScope) { + $mergedScope = $tagScope | $tpl->scope; $_stack = array(); $ptr = $tpl->parent; if ($mergedScope && isset($ptr) && $ptr->_isTplObj()) { $_stack[] = $ptr; + if ($tpl->inheritance && $tagScope & Smarty::SCOPE_PARENT) { + $inheritanceRoot = $tpl; + while ($inheritanceRoot->inheritance && $inheritanceRoot->parent + && $inheritanceRoot->parent->_isTplObj() + && $inheritanceRoot->parent->inheritance === $inheritanceRoot->inheritance + ) { + $inheritanceRoot = $inheritanceRoot->parent; + } + if ($inheritanceRoot->parent && $inheritanceRoot->parent !== $ptr) { + $_stack[] = $inheritanceRoot->parent; + } + } $mergedScope = $mergedScope & ~Smarty::SCOPE_PARENT; if (!$mergedScope) { // only parent was set, we are done diff --git a/tests/UnitTests/TemplateSource/X_Scopes/ScopeTest.php b/tests/UnitTests/TemplateSource/X_Scopes/ScopeTest.php index 8c0a7156e..a686b8651 100644 --- a/tests/UnitTests/TemplateSource/X_Scopes/ScopeTest.php +++ b/tests/UnitTests/TemplateSource/X_Scopes/ScopeTest.php @@ -238,7 +238,16 @@ public function dataTestIncludeScope() '', $i ++), array('{include \'test_scope_assign_noscope.tpl\' scope=root}', true, '#test_scope_assign_noscope.tpl:$foo =\'newvar\'#testIncludeScope_' . $i . '.tpl:$foo =\'data\'#test_scope.tpl:$foo =\'data\'#data:$foo =\'data\'#Smarty:$foo =\'smarty\'#global:$foo =\'global\'', - '', $i ++),); + '', $i ++), + array('{include \'test_scope_inheritance_include.tpl\'}', true, + '#test_scope_inheritance_include.tpl:$foo =\'data\'#testIncludeScope_'. $i . + '.tpl:$foo =\'data\'#test_scope.tpl:$foo =\'data\'#data:$foo =\'data\'#Smarty:$foo =\'smarty\'#global:$foo =\'global\'', + '', $i ++), + array('{include \'test_scope_inheritance_include_assign_parent.tpl\'}', true, + '#test_scope_inheritance_include_assign_parent.tpl:$foo =\'parent\'#testIncludeScope_'. $i . + '.tpl:$foo =\'data\'#test_scope.tpl:$foo =\'data\'#data:$foo =\'data\'#Smarty:$foo =\'smarty\'#global:$foo =\'global\'', + '', $i ++) + ); } /** diff --git a/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_child.tpl b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_child.tpl new file mode 100644 index 000000000..c68406adf --- /dev/null +++ b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_child.tpl @@ -0,0 +1 @@ +{extends './test_scope_inheritance_parent.tpl'} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_child_assign_parent.tpl b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_child_assign_parent.tpl new file mode 100644 index 000000000..26cf42665 --- /dev/null +++ b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_child_assign_parent.tpl @@ -0,0 +1 @@ +{extends './test_scope_inheritance_parent_assign_parent.tpl'} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_include.tpl b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_include.tpl new file mode 100644 index 000000000..50864f271 --- /dev/null +++ b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_include.tpl @@ -0,0 +1 @@ +{include './test_scope_inheritance_child.tpl'}{checkvar var=foo} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_include_assign_parent.tpl b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_include_assign_parent.tpl new file mode 100644 index 000000000..8dd28ea51 --- /dev/null +++ b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_include_assign_parent.tpl @@ -0,0 +1 @@ +{include './test_scope_inheritance_child_assign_parent.tpl'}{checkvar var=foo} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_parent.tpl b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_parent.tpl new file mode 100644 index 000000000..f6abff6d4 --- /dev/null +++ b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_parent.tpl @@ -0,0 +1 @@ +{$foo = 'parent'} \ No newline at end of file diff --git a/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_parent_assign_parent.tpl b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_parent_assign_parent.tpl new file mode 100644 index 000000000..1658829d4 --- /dev/null +++ b/tests/UnitTests/TemplateSource/X_Scopes/templates/test_scope_inheritance_parent_assign_parent.tpl @@ -0,0 +1 @@ +{$foo = 'parent' scope=parent} \ No newline at end of file