- improvement rework of 'scope' attribute handling see see NEW_FEATURES.txt https://github.com/smarty-php/smarty/issues/194

https://github.com/smarty-php/smarty/issues/186 https://github.com/smarty-php/smarty/issues/179
This commit is contained in:
uwetews
2016-03-09 01:01:32 +01:00
parent d88168d1b6
commit abf5be58ad
9 changed files with 93 additions and 71 deletions

View File

@@ -50,46 +50,28 @@ Smarty 3.1.30
Scope Attributes Scope Attributes
================ ================
The scope handling has been updated to cover all cases of variable assignments in templates. The scope handling has been updated to cover all cases of variable assignments in templates.
A new option flag 'bubble_up' is introduced.
The tags {assign}, {append} direct assignments like {$foo = ...}, {$foo[...]= ...} support The tags {assign}, {append} direct assignments like {$foo = ...}, {$foo[...]= ...} support
the following optional scope attributes: the following optional scope attributes:
scope='parent' - the variable will be assigned in the current template and if the template scope='parent' - the variable will be assigned in the current template and if the template
was included by {include} the calling template was included by {include} the calling template
scope='tpl_root' - the variable will be assigned in the current template and if the template scope='tpl_root' - the variable will be assigned in the outermost root template called by $smarty->display()
was included by {include} the outermost root template or $smarty->fetch() and is bubbled up all {include} sub-templates to the current template.
scope='smarty' - the variable will be assigned in the current template and the Smarty object scope='smarty' - the variable will be assigned in the Smarty object and is bubbled up all {include} sub-templates
scope='global' - the variable will be assigned in the current template and as Smarty object to the current template.
global variable scope='global' - the variable will be assigned as Smarty object global variable and is bubbled up all {include}
scope='root' - the variable will be assigned in the current template and if a data object was sub-templates to the current template.
used for variable definitions in the data object or in the Smarty object otherwise scope='root' - the variable will be assigned if a data object was used for variable definitions in the data
object or in the Smarty object otherwise and is bubbled up all {include} sub-templates to the
current template.
scope='local' - this scope has only a meaning if the tag is called within a template {function}. scope='local' - this scope has only a meaning if the tag is called within a template {function}.
The variable will be assigned in the local scope of the template function and the The variable will be assigned in the local scope of the template function and the
template which did call the template function. template which did call the template function.
The scope attribute can be combined with the new option flag 'bubble_up' like
{$foo = 'bar' scope='global' bubble_up}
In addition to the assignments according to the scope attributes tpl_root, smarty, global, root the varibale
will also be assigned in all templates in the call chain from template root to the current template,
including all local template function scopes of nested template function calls.
In combination with scope local it does update the nested template function scopes.
Example:
$smarty->display('main.tpl');
main.tpl:
{include 'sub.tpl'}
sub.tpl:
{$foo = 'bar' scope='global' bubble_up}
Will assign the variable 'foo' with value 'bar' as Smarty global variable, in 'sub.tpl' and in
'main.tpl' because the 'bubble_up' option.
The {config_load} tag supports all of the above except the global scope. The {config_load} tag supports all of the above except the global scope.
The scope attribute and bubble_up option flag can be used also with the {include} tag. The scope attribute can be used also with the {include} tag.
Supported scope are parent, tpl_root, smarty, global and root. Supported scope are parent, tpl_root, smarty, global and root.
A scope used together with the {include} tag will cause that with some exceptions any variable A scope used together with the {include} tag will cause that with some exceptions any variable
assignment within that sub-template will update/assign the variable in other scopes according assignment within that sub-template will update/assign the variable in other scopes according
@@ -98,6 +80,15 @@ Smarty 3.1.30
Excluded are the key and value variables of {foreach}, {for} loop variables , variables passed by attributes Excluded are the key and value variables of {foreach}, {for} loop variables , variables passed by attributes
in {include} and direct increments/decrements like {$foo++}, {$foo--} in {include} and direct increments/decrements like {$foo++}, {$foo--}
Note: The scopes should be used only to the extend really need. If a variable value assigned in an included
sub-template should be returned to the calling sub-template just use {$foo='bar' scope='parent'}.
Use scopes only with variables for which it's realy needed. Avoid general scope settings with the
{include} tag as it can have a performance impact.
The {assign}, {append}, {config_load} and {$foo...=...} tags have a new option flag 'noscope'.Thi
Example: {$foo='bar' noscope} This will assign $foo only in the current template and any scope settings
at {include} is ignored.
Caching Caching
======= =======

View File

@@ -1,4 +1,8 @@
 ===== 3.1.30-dev ===== (xx.xx.xx)  ===== 3.1.30-dev ===== (xx.xx.xx)
09.03.2014
- improvement rework of 'scope' attribute handling see see NEW_FEATURES.txt https://github.com/smarty-php/smarty/issues/194
https://github.com/smarty-php/smarty/issues/186 https://github.com/smarty-php/smarty/issues/179
04.03.2016 04.03.2016
- bugfix change from 01.03.2016 will cause $smarty->isCached(..) failure if called multiple time for same template - bugfix change from 01.03.2016 will cause $smarty->isCached(..) failure if called multiple time for same template
(forum topic 25935) (forum topic 25935)

View File

@@ -121,7 +121,7 @@ class Smarty extends Smarty_Internal_TemplateBase
/** /**
* smarty version * smarty version
*/ */
const SMARTY_VERSION = '3.1.30-dev/52'; const SMARTY_VERSION = '3.1.30-dev/53';
/** /**
* define variable scopes * define variable scopes
@@ -138,8 +138,6 @@ class Smarty extends Smarty_Internal_TemplateBase
const SCOPE_GLOBAL = 32; const SCOPE_GLOBAL = 32;
const SCOPE_BUBBLE_UP = 64;
/** /**
* define caching modes * define caching modes
*/ */

View File

@@ -22,9 +22,9 @@ class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $option_flags = array('nocache', 'bubble_up'); public $option_flags = array('nocache', 'noscope');
/** /**
* Valid scope names * Valid scope names
* *
* @var array * @var array
@@ -65,7 +65,11 @@ class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase
$compiler->setNocacheInVariable($_attr[ 'var' ]); $compiler->setNocacheInVariable($_attr[ 'var' ]);
} }
// scope setup // scope setup
$_scope = $compiler->convertScope($_attr, $this->valid_scopes); if ($_attr[ 'noscope' ]) {
$_scope = - 1;
} else {
$_scope = $compiler->convertScope($_attr, $this->valid_scopes);
}
// optional parameter // optional parameter
$_params = ""; $_params = "";
if ($_nocache || $_scope) { if ($_nocache || $_scope) {

View File

@@ -46,7 +46,7 @@ class Smarty_Internal_Compile_Config_Load extends Smarty_Internal_CompileBase
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $option_flags = array('nocache', 'bubble_up'); public $option_flags = array('nocache', 'noscope');
/** /**
* Valid scope names * Valid scope names
@@ -83,7 +83,11 @@ class Smarty_Internal_Compile_Config_Load extends Smarty_Internal_CompileBase
$section = 'null'; $section = 'null';
} }
// scope setup // scope setup
$_scope = $compiler->convertScope($_attr, $this->valid_scopes); if ($_attr[ 'noscope' ]) {
$_scope = - 1;
} else {
$_scope = $compiler->convertScope($_attr, $this->valid_scopes);
}
// create config object // create config object
$_output = $_output =

View File

@@ -43,7 +43,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
* @var array * @var array
* @see Smarty_Internal_CompileBase * @see Smarty_Internal_CompileBase
*/ */
public $option_flags = array('nocache', 'inline', 'caching', 'bubble_up'); public $option_flags = array('nocache', 'inline', 'caching');
/** /**
* Attribute definition: Overwrites base class. * Attribute definition: Overwrites base class.
@@ -214,7 +214,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
} }
} }
// delete {include} standard attributes // delete {include} standard attributes
unset($_attr[ 'file' ], $_attr[ 'assign' ], $_attr[ 'cache_id' ], $_attr[ 'compile_id' ], $_attr[ 'cache_lifetime' ], $_attr[ 'nocache' ], $_attr[ 'caching' ], $_attr[ 'scope' ], $_attr[ 'inline' ], $_attr[ 'bubble_up' ]); unset($_attr[ 'file' ], $_attr[ 'assign' ], $_attr[ 'cache_id' ], $_attr[ 'compile_id' ], $_attr[ 'cache_lifetime' ], $_attr[ 'nocache' ], $_attr[ 'caching' ], $_attr[ 'scope' ], $_attr[ 'inline' ]);
// remaining attributes must be assigned as smarty variable // remaining attributes must be assigned as smarty variable
$_vars_nc = ''; $_vars_nc = '';
$_vars = 'array()'; $_vars = 'array()';

View File

@@ -76,21 +76,31 @@ class Smarty_Internal_Method_ConfigLoad
* load config variables into template object * load config variables into template object
* *
* @param \Smarty_Internal_Template $tpl * @param \Smarty_Internal_Template $tpl
* @param array $_config_vars * @param array $new_config_vars
* *
*/ */
public function _loadConfigVars(Smarty_Internal_Template $tpl, $_config_vars) public function _loadConfigVars(Smarty_Internal_Template $tpl, $new_config_vars)
{ {
$this->_assignConfigVars($tpl->parent, $tpl, $_config_vars); $this->_assignConfigVars($tpl->parent->config_vars, $tpl, $new_config_vars);
if ($tpl->parent->_objType == 2 && ($tpl->source->scope || $tpl->parent->scope)) { $tagScope = $tpl->source->scope;
$scope = $tpl->source->scope | $tpl->scope; if ($tagScope >= 0) {
if ($scope) { if ($tagScope == Smarty::SCOPE_LOCAL) {
// update scopes $this->_updateVarStack($tpl, $new_config_vars);
foreach ($tpl->smarty->ext->_updateScope->_getAffectedScopes($tpl->parent, $scope) as $ptr) { $tagScope = 0;
$this->_assignConfigVars($ptr, $tpl, $_config_vars); if (!$tpl->scope) {
return;
} }
if ($scope & Smarty::SCOPE_LOCAL) { }
//$this->_updateVarStack($tpl, $varName); if ($tpl->parent->_objType == 2 && ($tagScope || $tpl->parent->scope)) {
$mergedScope = $tagScope | $tpl->scope;
if ($mergedScope) {
// update scopes
foreach ($tpl->smarty->ext->_updateScope->_getAffectedScopes($tpl->parent, $mergedScope) as $ptr) {
$this->_assignConfigVars($ptr->config_vars, $tpl, $new_config_vars);
if ($tagScope && $ptr->_objType == 2 && isset($tpl->_cache[ 'varStack' ])) {
$this->_updateVarStack($tpl, $new_config_vars);
}
}
} }
} }
} }
@@ -99,32 +109,30 @@ class Smarty_Internal_Method_ConfigLoad
/** /**
* Assign all config variables in given scope * Assign all config variables in given scope
* *
* @param \Smarty_Internal_Data $scope_ptr * @param array $config_vars config variables in scope
* @param \Smarty_Internal_Template $tpl * @param \Smarty_Internal_Template $tpl
* @param array $_config_vars * @param array $new_config_vars loaded config variables
*/ */
public function _assignConfigVars(Smarty_Internal_Data $scope_ptr, Smarty_Internal_Template $tpl, $_config_vars) public function _assignConfigVars(&$config_vars, Smarty_Internal_Template $tpl, $new_config_vars)
{ {
// copy global config vars // copy global config vars
foreach ($_config_vars[ 'vars' ] as $variable => $value) { foreach ($new_config_vars[ 'vars' ] as $variable => $value) {
if ($tpl->smarty->config_overwrite || !isset($scope_ptr->config_vars[ $variable ])) { if ($tpl->smarty->config_overwrite || !isset($config_vars[ $variable ])) {
$scope_ptr->config_vars[ $variable ] = $value; $config_vars[ $variable ] = $value;
} else { } else {
$scope_ptr->config_vars[ $variable ] = $config_vars[ $variable ] = array_merge((array) $config_vars[ $variable ], (array) $value);
array_merge((array) $scope_ptr->config_vars[ $variable ], (array) $value);
} }
} }
// scan sections // scan sections
$sections = $tpl->source->config_sections; $sections = $tpl->source->config_sections;
if (!empty($sections)) { if (!empty($sections)) {
foreach ((array) $sections as $tpl_section) { foreach ((array) $sections as $tpl_section) {
if (isset($_config_vars[ 'sections' ][ $tpl_section ])) { if (isset($new_config_vars[ 'sections' ][ $tpl_section ])) {
foreach ($_config_vars[ 'sections' ][ $tpl_section ][ 'vars' ] as $variable => $value) { foreach ($new_config_vars[ 'sections' ][ $tpl_section ][ 'vars' ] as $variable => $value) {
if ($tpl->smarty->config_overwrite || !isset($scope_ptr->config_vars[ $variable ])) { if ($tpl->smarty->config_overwrite || !isset($config_vars[ $variable ])) {
$scope_ptr->config_vars[ $variable ] = $value; $config_vars[ $variable ] = $value;
} else { } else {
$scope_ptr->config_vars[ $variable ] = $config_vars[ $variable ] = array_merge((array) $config_vars[ $variable ], (array) $value);
array_merge((array) $scope_ptr->config_vars[ $variable ], (array) $value);
} }
} }
} }
@@ -132,6 +140,21 @@ class Smarty_Internal_Method_ConfigLoad
} }
} }
/**
* Update config variables in template local variable stack
*
* @param \Smarty_Internal_Template $tpl
* @param array $config_vars
*/
public function _updateVarStack(Smarty_Internal_Template $tpl, $config_vars)
{
$i = 0;
while (isset($tpl->_cache[ 'varStack' ][ $i ])) {
$this->_assignConfigVars($tpl->_cache[ 'varStack' ][ $i ][ 'config' ], $tpl, $config_vars);
$i ++;
}
}
/** /**
* gets a config variable value * gets a config variable value
* *

View File

@@ -383,8 +383,10 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
} else { } else {
$this->tpl_vars[ $varName ] = new Smarty_Variable($value, $nocache || $this->isRenderingCache); $this->tpl_vars[ $varName ] = new Smarty_Variable($value, $nocache || $this->isRenderingCache);
} }
if (isset($scope) || isset($this->scope)) { if ($scope >= 0) {
$this->smarty->ext->_updateScope->_updateScope($this, $varName, $scope); if (isset($scope) || isset($this->scope)) {
$this->smarty->ext->_updateScope->_updateScope($this, $varName, $scope);
}
} }
} }

View File

@@ -403,7 +403,6 @@ abstract class Smarty_Internal_TemplateCompilerBase
$this->smarty->_debug->end_compile($this->template); $this->smarty->_debug->end_compile($this->template);
} }
$this->_tag_stack = array(); $this->_tag_stack = array();
self::$_tag_objects = array();
// free memory // free memory
$this->parent_compiler = null; $this->parent_compiler = null;
$this->template = null; $this->template = null;
@@ -1140,9 +1139,6 @@ abstract class Smarty_Internal_TemplateCompilerBase
$err = var_export($_scopeName, true); $err = var_export($_scopeName, true);
$this->trigger_template_error("illegal value '{$err}' for \"scope\" attribute", null, true); $this->trigger_template_error("illegal value '{$err}' for \"scope\" attribute", null, true);
} }
if (isset($_attr[ 'bubble_up' ]) && $_attr[ 'bubble_up' ] && $_scope > 2) {
$_scope += Smarty::SCOPE_BUBBLE_UP;
}
} }
return $_scope; return $_scope;
} }