WIP fixing the complicated variables scopes architecture. Right now more tests are failing than before... :(

This commit is contained in:
Simon Wisselink
2023-01-10 23:49:33 +01:00
parent 3d10630510
commit 51075e0421
22 changed files with 160 additions and 493 deletions

View File

@@ -5,6 +5,9 @@
*/
namespace Smarty\Compile;
use Smarty\Data;
use Smarty\Exception;
/**
* This class does extend all internal compile plugins
*
@@ -225,6 +228,39 @@ abstract class Base implements CompilerInterface {
$compiler->trigger_template_error('unexpected closing tag', null, true);
}
/**
* @param array $_attr tag attributes
* @param array $invalidScopes
*
* @return int
* @throws Exception
*/
protected function convertScope($_attr, $invalidScopes = []): int {
static $scopes = [
'local' => Data::SCOPE_LOCAL, 'parent' => Data::SCOPE_PARENT,
'root' => Data::SCOPE_ROOT, 'global' => Data::SCOPE_GLOBAL,
'tpl_root' => Data::SCOPE_TPL_ROOT, 'smarty' => Data::SCOPE_SMARTY
];
if (!isset($_attr['scope'])) {
return 0;
}
$_scopeName = trim($_attr['scope'], '\'"');
if (is_numeric($_scopeName) && in_array($_scopeName, $scopes)) {
return (int) $_scopeName;
}
$_scopeName = trim($_scopeName, '\'"');
if (isset($scopes[$_scopeName])) {
return $scopes[$_scopeName];
}
$err = var_export($_scopeName, true);
throw new Exception("illegal value '{$err}' for \"scope\" attribute");
}
/**
* Compiles code for the tag
*

View File

@@ -30,17 +30,6 @@ class Assign extends Base
*/
protected $option_flags = array('nocache', 'noscope');
/**
* Valid scope names
*
* @var array
*/
protected $valid_scopes = array(
'local' => Smarty::SCOPE_LOCAL, 'parent' => Smarty::SCOPE_PARENT,
'root' => Smarty::SCOPE_ROOT, 'global' => Smarty::SCOPE_GLOBAL,
'tpl_root' => Smarty::SCOPE_TPL_ROOT, 'smarty' => Smarty::SCOPE_SMARTY
);
/**
* Compiles code for the {assign} tag
*
@@ -76,16 +65,14 @@ class Assign extends Base
if ($_attr[ 'noscope' ]) {
$_scope = -1;
} else {
$_scope = $compiler->convertScope($_attr, $this->valid_scopes);
$_scope = $this->convertScope($_attr);
}
// optional parameter
$_params = '';
if ($_nocache || $_scope) {
if ($_nocache) {
$_params .= ' ,' . var_export($_nocache, true);
}
if ($_scope) {
$_params .= ' ,' . $_scope;
}
if (isset($parameter[ 'smarty_internal_index' ])) {
$output =
"<?php \$_tmp_array = \$_smarty_tpl->getValue({$_var}) ?? [];\n";
@@ -93,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->_assignInScope({$_var}, \$_tmp_array{$_params});?>";
$output .= "\$_smarty_tpl->assign({$_var}, \$_tmp_array{$_params}, false, {$_scope});?>";
} else {
$output = "<?php \$_smarty_tpl->_assignInScope({$_var}, {$_attr['value']}{$_params});?>";
$output = "<?php \$_smarty_tpl->assign({$_var}, {$_attr['value']}{$_params}, false, {$_scope});?>";
}
return $output;
}

View File

@@ -53,17 +53,6 @@ class ConfigLoad extends Base {
*/
protected $option_flags = ['nocache', 'noscope'];
/**
* Valid scope names
*
* @var array
*/
protected $valid_scopes = [
'local' => Smarty::SCOPE_LOCAL, 'parent' => Smarty::SCOPE_PARENT,
'root' => Smarty::SCOPE_ROOT, 'tpl_root' => Smarty::SCOPE_TPL_ROOT,
'smarty' => Smarty::SCOPE_SMARTY, 'global' => Smarty::SCOPE_SMARTY,
];
/**
* Compiles code for the {config_load} tag
*
@@ -86,9 +75,9 @@ class ConfigLoad extends Base {
if ($_attr['noscope']) {
$_scope = -1;
} else {
$_scope = $compiler->convertScope($_attr, $this->valid_scopes);
$_scope = $this->convertScope($_attr);
}
// create config object
return "<?php\n\$_smarty_tpl->_loadConfigfile({$conf_file}, {$section}, {$_scope});\n?>\n";
return "<?php\n\$_smarty_tpl->_loadConfigfile({$conf_file}, {$section});\n?>\n";
}
}

View File

@@ -12,6 +12,7 @@ namespace Smarty\Compile\Tag;
use Smarty\Compile\Base;
use Smarty\Compiler\Template;
use Smarty\Data;
use Smarty\Smarty;
use Smarty\Template\Compiled;
@@ -60,17 +61,6 @@ class IncludeTag extends Base {
*/
protected $optional_attributes = ['_any'];
/**
* Valid scope names
*
* @var array
*/
protected $valid_scopes = [
'parent' => Smarty::SCOPE_PARENT, 'root' => Smarty::SCOPE_ROOT,
'global' => Smarty::SCOPE_GLOBAL, 'tpl_root' => Smarty::SCOPE_TPL_ROOT,
'smarty' => Smarty::SCOPE_SMARTY,
];
/**
* Compiles code for the {include} tag
*
@@ -125,13 +115,8 @@ class IncludeTag extends Base {
$variable_template = true;
}
// scope setup
$_scope = $compiler->convertScope($_attr, $this->valid_scopes);
// set flag to cache subtemplate object when called within loop or template name is variable.
if ($cache_tpl || $variable_template || $compiler->loopNesting > 0) {
$_cache_tpl = 'true';
} else {
$_cache_tpl = 'false';
}
$_scope = $this->convertScope($_attr, [Data::SCOPE_LOCAL]);
// assume caching is off
$_caching = Smarty::CACHING_OFF;
$call_nocache = $compiler->tag_nocache || $compiler->nocache;
@@ -244,16 +229,16 @@ class IncludeTag extends Base {
}
if (!empty($_attr) && $_caching === 9999 && $compiler->template->caching) {
$_vars_nc = "foreach ($_vars as \$ik => \$iv) {\n";
$_vars_nc .= "\$_smarty_tpl->tpl_vars[\$ik] = new \\Smarty\\Variable(\$iv);\n";
$_vars_nc .= "\$_smarty_tpl->assign(\$ik, \$iv);\n";
$_vars_nc .= "}\n";
$_output .= substr($compiler->processNocacheCode('<?php ' . $_vars_nc . "?>\n", true), 6, -3);
}
if (isset($_assign)) {
$_output .= "ob_start();\n";
}
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_scope}, {$_cache_tpl}, '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['uid']}', '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['func']}');\n";
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['uid']}', '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['func']}');\n";
if (isset($_assign)) {
$_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n";
$_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean(), false, {$_scope});\n";
}
if ($update_compile_id) {
$_output .= $compiler->makeNocacheCode("\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n");
@@ -272,9 +257,9 @@ class IncludeTag extends Base {
if (isset($_assign)) {
$_output .= "ob_start();\n";
}
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_scope, {$_cache_tpl});\n";
$_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars);\n";
if (isset($_assign)) {
$_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n";
$_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean(), false, {$_scope});\n";
}
if ($update_compile_id) {
$_output .= "\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n";

View File

@@ -140,7 +140,7 @@ class Configfile extends BaseCompiler {
date("Y-m-d H:i:s"),
str_replace('*/', '* /', $this->template->source->filepath)
);
$code = '<?php $_smarty_tpl->_loadConfigVars(' .
$code = '<?php $_smarty_tpl->assignConfigVars(' .
var_export($this->config_data, true) . '); ?>';
return $template_header . $this->template->createCodeFrame($code);
}

View File

@@ -770,33 +770,6 @@ class Template extends BaseCompiler {
}
}
/**
* @param array $_attr tag attributes
* @param array $validScopes
*
* @return int|string
* @throws \Smarty\CompilerException
*/
public function convertScope($_attr, $validScopes) {
$_scope = 0;
if (isset($_attr['scope'])) {
$_scopeName = trim($_attr['scope'], '\'"');
if (is_numeric($_scopeName) && in_array($_scopeName, $validScopes)) {
$_scope = $_scopeName;
} elseif (is_string($_scopeName)) {
$_scopeName = trim($_scopeName, '\'"');
$_scope = isset($validScopes[$_scopeName]) ? $validScopes[$_scopeName] : false;
} else {
$_scope = false;
}
if ($_scope === false) {
$err = var_export($_scopeName, true);
$this->trigger_template_error("illegal value '{$err}' for \"scope\" attribute", null, true);
}
}
return $_scope;
}
/**
* Generate nocache code string
*

View File

@@ -4,15 +4,7 @@ namespace Smarty;
/**
* Smarty Internal Plugin Data
* This file contains the basic classes and methods for template and variable creation
*
* @author Uwe Tews
*/
/**
* Base class with template and variable methods
* This file contains the basic properties and methods for holding config and template variables
*/
abstract class Data
{
@@ -55,25 +47,47 @@ abstract class Data
*/
public $config_vars = array();
/**
* assigns a Smarty variable
*
* @param array|string $tpl_var the template variable name(s)
* @param mixed $value the value to assign
* @param boolean $nocache if true any output of this variable will be not cached
*
* @return Data current Data (or Smarty or \Smarty\Template) instance for
* chaining
*/
public function assign($tpl_var, $value = null, $nocache = false)
/**
* assigns a Smarty variable
*
* @param array|string $tpl_var the template variable name(s)
* @param mixed $value the value to assign
* @param boolean $nocache if true any output of this variable will be not cached
* @param int $scope one of self::SCOPE_* constants
*
* @return Data current Data (or Smarty or \Smarty\Template) instance for
* chaining
*/
public function assign($tpl_var, $value = null, $nocache = false, $scope = 0)
{
if (is_array($tpl_var)) {
foreach ($tpl_var as $_key => $_val) {
$this->assign($_key, $_val, $nocache);
$this->assign($_key, $_val, $nocache, $scope);
}
} else {
$this->tpl_vars[ $tpl_var ] = new Variable($value, $nocache);
}
switch ($scope) {
case self::SCOPE_GLOBAL:
case self::SCOPE_SMARTY:
$this->_getSmartyObj()->assign($tpl_var, $value);
break;
case self::SCOPE_TPL_ROOT:
case self::SCOPE_ROOT:
$ptr = $this;
while (isset($ptr->parent) && !($ptr->parent instanceof Smarty)) {
$ptr = $ptr->parent;
}
$ptr->assign($tpl_var, $value);
break;
case self::SCOPE_PARENT:
if ($this->parent) {
$this->parent->assign($tpl_var, $value);
}
break;
default:
$this->tpl_vars[ $tpl_var ] = new Variable($value, $nocache);
}
return $this;
}
@@ -125,9 +139,12 @@ abstract class Data
* @param boolean $nocache if true any output of this variable will be not cached
*
* @return Data
* @deprecated since 5.0
*/
public function assignGlobal($varName, $value = null, $nocache = false)
{
trigger_error(__METHOD__ . " is deprecated. Use \\Smarty\\Smarty::assign() to assign a variable " .
" at the Smarty level.", E_USER_DEPRECATED);
return $this->_getSmartyObj()->assign($varName, $value, $nocache);
}
@@ -146,39 +163,9 @@ abstract class Data
{
if (isset($varName)) {
return $this->getValue($varName, $searchParents);
$_var = $_ptr->getVariable($varName, $searchParents, false);
if (is_object($_var)) {
return $_var->value;
} else {
return null;
}
} else {
$_result = array();
if ($_ptr === null) {
$_ptr = $this;
}
while ($_ptr !== null) {
foreach ($_ptr->tpl_vars as $key => $var) {
if (!array_key_exists($key, $_result)) {
$_result[ $key ] = $var->value;
}
}
// not found, try at parent
if ($searchParents && isset($_ptr->parent)) {
$_ptr = $_ptr->parent;
} else {
$_ptr = null;
}
}
if ($searchParents) {
foreach ($this->_getSmartyObj()->getAllGlobalTemplateVars() as $key => $var) {
if (!array_key_exists($key, $_result)) {
$_result[ $key ] = $var->value;
}
}
}
return $_result;
}
return array_merge($this->parent && $searchParents ? $this->parent->getTemplateVars() : [], $this->tpl_vars);
}
/**
@@ -246,6 +233,38 @@ abstract class Data
return isset($variable) ? $variable->getValue() : null;
}
/**
* load config variables into template object
*
* @param array $new_config_vars
*/
public function assignConfigVars($new_config_vars) {
// copy global config vars
foreach ($new_config_vars['vars'] as $variable => $value) {
if ($this->smarty->config_overwrite || !isset($this->config_vars[$variable])) {
$this->config_vars[$variable] = $value;
} else {
$this->config_vars[$variable] = array_merge((array)$this->config_vars[$variable], (array)$value);
}
}
// scan sections
$sections = $this->source->config_sections;
if (!empty($sections)) {
foreach ((array)$sections as $tpl_section) {
if (isset($new_config_vars['sections'][$tpl_section])) {
foreach ($new_config_vars['sections'][$tpl_section]['vars'] as $variable => $value) {
if ($this->smarty->config_overwrite || !isset($this->config_vars[$variable])) {
$this->config_vars[$variable] = $value;
} else {
$this->config_vars[$variable] = array_merge((array)$this->config_vars[$variable], (array)$value);
}
}
}
}
}
}
/**
* Get Smarty object
*
@@ -312,19 +331,15 @@ abstract class Data
return $this;
}
/**
* Gets a config variable value
*
* @param null $varName the name of the config variable
* @param string $varName the name of the config variable
*
* @return mixed the value of the config variable
* @throws Exception
*/
public function getConfigVariable($varName = null)
public function getConfigVariable($varName)
{
if (isset($this->config_vars[$varName])) {
@@ -343,12 +358,13 @@ abstract class Data
/**
* Returns a single or all config variables
*
* @api Smarty::getConfigVars()
* @link https://www.smarty.net/docs/en/api.get.config.vars.tpl
*
* @param string $varname variable name or null
* @param string $varname variable name or null
*
* @return mixed variable value or or array of variables
* @throws Exception
* @link https://www.smarty.net/docs/en/api.get.config.vars.tpl
*
* @api Smarty::getConfigVars()
*/
public function getConfigVars($varname = null)
{
@@ -367,24 +383,14 @@ abstract class Data
* @param string $varName variable name or null
*
* @return string|array variable value or or array of variables
*
* @deprecated since 5.0
*/
public function getGlobal($varName = null)
{
if (isset($varName)) {
if ($this->_getSmartyObj()->getGlobalVariable($varName)) {
return $this->_getSmartyObj()->getGlobalVariable($varName)->getValue();
} else {
return '';
}
} else {
$_result = [];
foreach ($this->_getSmartyObj()->getAllGlobalTemplateVars() as $key => $var) {
$_result[ $key ] = $var->value;
}
return $_result;
}
trigger_error(__METHOD__ . " is deprecated. Use \\Smarty\\Smarty::getValue() to retrieve a variable " .
" at the Smarty level.", E_USER_DEPRECATED);
return $this->_getSmartyObj()->getValue($varName);
}
}

View File

@@ -36,7 +36,6 @@ class DataObject extends Data {
* @throws Exception
*/
public function __construct($_parent = null, $smarty = null, $name = null) {
parent::__construct();
$this->smarty = $smarty;
if (is_object($_parent)) {

View File

@@ -226,9 +226,8 @@ class Debug extends Data
$_template = new \Smarty\Template($debObj->debug_tpl, $debObj);
if ($obj instanceof \Smarty\Template) {
$_template->assign('template_name', $obj->source->type . ':' . $obj->source->name);
}
if ($obj->_objType === 1 || $full) {
$_template->assign('template_data', $this->template_data[ $this->index ]);
} elseif ($obj instanceof Smarty || $full) {
$_template->assign('template_data', $this->template_data[$this->index]);
} else {
$_template->assign('template_data', null);
}

View File

@@ -120,7 +120,6 @@ class InheritanceRuntime {
$tpl->caching ? 9999 : 0,
$tpl->cache_lifetime,
[],
2,
false,
$uid,
$func

View File

@@ -454,13 +454,6 @@ class Smarty extends \Smarty\TemplateBase
*/
public $_parserdebug = false;
/**
* This object type (Smarty = 1, template = 2, data = 4)
*
* @var int
*/
public $_objType = 1;
/**
* Debug object
*
@@ -550,7 +543,7 @@ class Smarty extends \Smarty\TemplateBase
*/
public function __construct()
{
parent::__construct();
if (is_callable('mb_internal_encoding')) {
mb_internal_encoding(\Smarty\Smarty::$_CHARSET);
}
@@ -2294,7 +2287,7 @@ class Smarty extends \Smarty\TemplateBase
* @return Template
* @throws Exception
*/
private function returnOrCreateTemplate($template, $cache_id, $compile_id, $parent) {
private function returnOrCreateTemplate($template, $cache_id = null, $compile_id = null, $parent = null) {
if (!($template instanceof Template)) {
$template = $this->createTemplate($template, $cache_id, $compile_id, $parent ?: $this, false);
$template->caching = $this->caching;

View File

@@ -27,13 +27,6 @@ use Smarty\Template\Config;
#[\AllowDynamicProperties]
class Template extends TemplateBase {
/**
* This object type (Smarty = 1, template = 2, data = 4)
*
* @var int
*/
public $_objType = 2;
/**
* Source instance
*
@@ -69,13 +62,6 @@ class Template extends TemplateBase {
*/
public $templateId = null;
/**
* Scope in which variables shall be assigned
*
* @var int
*/
public $scope = 0;
/**
* Flag which is set while rending a cache file
*
@@ -148,7 +134,7 @@ class Template extends TemplateBase {
// Template resource
$this->template_resource = $template_resource;
$this->source = $_isConfig ? Config::load($this) : Source::load($this);
parent::__construct();
if ($smarty->security_policy && method_exists($smarty->security_policy, 'registerCallBacks')) {
$smarty->security_policy->registerCallBacks($this);
}
@@ -244,8 +230,6 @@ class Template extends TemplateBase {
* @param integer $caching cache mode
* @param integer $cache_lifetime life time of cache data
* @param array $data passed parameter template variables
* @param int $scope scope in which {include} should execute
* @param bool $forceTplCache cache template object
* @param string $uid file dependency uid
* @param string $content_func function name
*
@@ -259,8 +243,6 @@ class Template extends TemplateBase {
$caching,
$cache_lifetime,
$data,
$scope,
$forceTplCache,
$uid = null,
$content_func = null
) {
@@ -296,8 +278,6 @@ class Template extends TemplateBase {
}
$tpl->caching = $caching;
$tpl->cache_lifetime = $cache_lifetime;
// set template scope
$tpl->scope = $scope;
if (!empty($data)) {
// set up variable values
@@ -341,8 +321,8 @@ class Template extends TemplateBase {
return isset($this->parent) && $this->parent instanceof Template;
}
public function assign($tpl_var, $value = null, $nocache = false) {
return parent::assign($tpl_var, $value, $nocache || $this->isRenderingCache);
public function assign($tpl_var, $value = null, $nocache = false, $scope = 0) {
return parent::assign($tpl_var, $value, $nocache || $this->isRenderingCache, $scope);
}
/**
@@ -612,82 +592,7 @@ class Template extends TemplateBase {
}
}
/**
* load config variables into template object
*
* @param array $new_config_vars
*/
public function _loadConfigVars($new_config_vars) {
$this->_assignConfigVars($this->parent->config_vars, $new_config_vars);
$tagScope = $this->source->scope;
if ($tagScope >= 0) {
if ($tagScope === \Smarty\Smarty::SCOPE_LOCAL) {
$this->_updateConfigVarStack($new_config_vars);
$tagScope = 0;
if (!$this->scope) {
return;
}
}
if ($this->parent instanceof Template && ($tagScope || $this->parent->scope)) {
$mergedScope = $tagScope | $this->scope;
if ($mergedScope) {
// update scopes
/* @var \Smarty\Data $ptr */
foreach ($this->parent->_getAffectedScopes($mergedScope) as $ptr) {
$this->_assignConfigVars($ptr->config_vars, $new_config_vars);
if ($tagScope && $ptr instanceof Template && isset($this->_var_stack)) {
$this->_updateConfigVarStack($new_config_vars);
}
}
}
}
}
}
/**
* Assign all config variables in given scope
*
* @param array $config_vars config variables in scope
* @param array $new_config_vars loaded config variables
*/
private function _assignConfigVars(&$config_vars, $new_config_vars) {
// copy global config vars
foreach ($new_config_vars['vars'] as $variable => $value) {
if ($this->smarty->config_overwrite || !isset($config_vars[$variable])) {
$config_vars[$variable] = $value;
} else {
$config_vars[$variable] = array_merge((array)$config_vars[$variable], (array)$value);
}
}
// scan sections
$sections = $this->source->config_sections;
if (!empty($sections)) {
foreach ((array)$sections as $tpl_section) {
if (isset($new_config_vars['sections'][$tpl_section])) {
foreach ($new_config_vars['sections'][$tpl_section]['vars'] as $variable => $value) {
if ($this->smarty->config_overwrite || !isset($config_vars[$variable])) {
$config_vars[$variable] = $value;
} else {
$config_vars[$variable] = array_merge((array)$config_vars[$variable], (array)$value);
}
}
}
}
}
}
/**
* Update config variables in template local variable stack
*
* @param array $config_vars
*/
private function _updateConfigVarStack($config_vars) {
$i = 0;
while (isset($this->_var_stack[$i])) {
$this->_assignConfigVars($this->_var_stack[$i]['config'], $config_vars);
$i++;
}
}
/**
* Returns if the current template must be compiled by the Smarty compiler
@@ -716,74 +621,6 @@ class Template extends TemplateBase {
return $this->mustCompile;
}
/**
* Update new assigned template or config variable in other effected scopes
*
* @param string|null $varName variable name
* @param int $tagScope tag scope to which bubble up variable value
*/
protected function _updateScope($varName, $tagScope = 0) {
if ($tagScope) {
$this->_updateVarStack($this, $varName);
$tagScope = $tagScope & ~\Smarty\Smarty::SCOPE_LOCAL;
if (!$this->scope && !$tagScope) {
return;
}
}
$mergedScope = $tagScope | $this->scope;
if ($mergedScope) {
if ($mergedScope & \Smarty\Smarty::SCOPE_GLOBAL && $varName) {
$this->_getSmartyObj()->setGlobalVariable($varName, $this->tpl_vars[$varName]);
}
// update scopes
foreach ($this->_getAffectedScopes($mergedScope) as $ptr) {
$this->_updateVariableInOtherScope($ptr->tpl_vars, $varName);
if ($tagScope && $ptr instanceof Template && isset($this->_var_stack)) {
$this->_updateVarStack($ptr, $varName);
}
}
}
}
/**
* Get array of objects which needs to be updated by given scope value
*
* @param int $mergedScope merged tag and template scope to which bubble up variable value
*
* @return array
*/
private function _getAffectedScopes($mergedScope) {
$_stack = [];
$ptr = $this->parent;
if ($mergedScope && isset($ptr) && $ptr instanceof Template) {
$_stack[] = $ptr;
$mergedScope = $mergedScope & ~\Smarty\Smarty::SCOPE_PARENT;
if (!$mergedScope) {
// only parent was set, we are done
return $_stack;
}
$ptr = $ptr->parent;
}
while (isset($ptr) && $ptr instanceof Template) {
$_stack[] = $ptr;
$ptr = $ptr->parent;
}
if ($mergedScope & \Smarty\Smarty::SCOPE_SMARTY) {
if (isset($this->smarty)) {
$_stack[] = $this->smarty;
}
} elseif ($mergedScope & \Smarty\Smarty::SCOPE_ROOT) {
while (isset($ptr)) {
if (!$ptr instanceof Template) {
$_stack[] = $ptr;
break;
}
$ptr = $ptr->parent;
}
}
return $_stack;
}
private function getFrameCompiler(): Compiler\CodeFrame {
return new \Smarty\Compiler\CodeFrame($this);
}
@@ -856,9 +693,9 @@ class Template extends TemplateBase {
/**
* @inheritdoc
*/
public function _loadConfigfile($config_file, $sections = null, $scope = 0)
public function _loadConfigfile($config_file, $sections = null)
{
$confObj = parent::_loadConfigfile($config_file, $sections, $scope);
$confObj = parent::_loadConfigfile($config_file, $sections);
$this->compiled->file_dependency[ $confObj->source->uid ] =
array($confObj->source->filepath, $confObj->source->getTimeStamp(), $confObj->source->type);
@@ -922,10 +759,8 @@ class Template extends TemplateBase {
$errorHandler->activate();
}
/* @var Template $parent */
if (isset($parent->_objType) && ($parent->_objType === 2) && !empty($parent->tplFunctions)) {
$this->tplFunctions = array_merge($parent->tplFunctions, $this->tplFunctions);
}
$this->tplFunctions = array_merge($parent->tplFunctions ?? [], $this->tplFunctions ?? []);
if ($function === 2) {
if ($this->caching) {
// return cache status of template

View File

@@ -21,13 +21,6 @@ class Config extends Source {
*/
public $config_sections = null;
/**
* scope into which the config variables shall be loaded
*
* @var int
*/
public $scope = 0;
/**
* Flag that source is a config file
*

View File

@@ -12,9 +12,6 @@ namespace Smarty;
/**
* Class with shared smarty/template methods
*
* @property int $_objType
*
*/
abstract class TemplateBase extends Data {
@@ -452,7 +449,7 @@ abstract class TemplateBase extends Data {
*/
public function configLoad($config_file, $sections = null)
{
$this->_loadConfigfile($config_file, $sections, null);
$this->_loadConfigfile($config_file, $sections);
return $this;
}
@@ -462,22 +459,20 @@ abstract class TemplateBase extends Data {
* @param string $config_file filename
* @param mixed $sections array of section names, single
* section or null
* @param int $scope scope into which config variables
* shall be loaded
* @returns Template
* @throws \Exception
* @link https://www.smarty.net/docs/en/api.config.load.tpl
*
* @api Smarty::configLoad()
*/
public function _loadConfigfile($config_file, $sections = null, $scope = 0)
public function _loadConfigfile($config_file, $sections = null)
{
$smarty = $this->_getSmartyObj();
$confObj = new Template($config_file, $smarty, $this, null, null, null, null, true);
$confObj->caching = Smarty::CACHING_OFF;
$confObj->source->config_sections = $sections;
$confObj->source->scope = $scope;
$confObj->compiled = \Smarty\Template\Compiled::load($confObj);
$confObj->compiled->render($confObj);
return $confObj;

View File

@@ -65,26 +65,12 @@ class UndefinedTemplateVarTest extends PHPUnit_Smarty
*/
public function testError()
{
$exceptionThrown = false;
try {
$e1 = error_reporting();
$this->assertEquals('undefined = ', $this->smarty->fetch('001_main.tpl'));
$e2 = error_reporting();
$this->assertEquals($e1, $e2);
} catch (Exception $e) {
$exceptionThrown = true;
$this->assertStringStartsWith('Undefined ', $e->getMessage());
$this->assertTrue(in_array(
get_class($e),
[
'PHPUnit\Framework\Error\Warning',
'PHPUnit\Framework\Error\Notice',
]
));
}
$this->assertTrue($exceptionThrown);
$this->expectException(PHPUnit\Framework\Error\Error::class);
$this->expectExceptionMessage('Undefined ');
$e1 = error_reporting();
$this->assertEquals('undefined = ', $this->smarty->fetch('001_main.tpl'));
$e2 = error_reporting();
$this->assertEquals($e1, $e2);
}
public function testUndefinedSimpleVar() {

View File

@@ -1,62 +0,0 @@
<?php
/**
* Smarty PHPunit tests appendByRef method
*
* @author Uwe Tews
*/
/**
* class for appendByRef tests
*
*
*
*
*/
class AppendByRefTest extends PHPUnit_Smarty
{
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
}
/**
* test appendByRef
*/
public function testAppendByRef()
{
$bar = 'bar';
$bar2 = 'bar2';
$this->smarty->appendByRef('foo', $bar);
$this->smarty->appendByRef('foo', $bar2);
$bar = 'newbar';
$bar2 = 'newbar2';
$this->assertEquals('newbar newbar2', $this->smarty->fetch('eval:{$foo[0]} {$foo[1]}'));
}
/**
* test appendByRef to unassigned variable
*/
public function testAppendByRefUnassigned()
{
$bar2 = 'bar2';
$this->smarty->appendByRef('foo', $bar2);
$bar2 = 'newbar2';
$this->assertEquals('newbar2', $this->smarty->fetch('eval:{$foo[0]}'));
}
/**
* test appendByRef merge
*/
public function testAppendByRefMerge()
{
$foo = array('a' => 'a', 'b' => 'b', 'c' => 'c');
$bar = array('b' => 'd');
$this->smarty->assignByRef('foo', $foo);
$this->smarty->appendByRef('foo', $bar, true);
$this->assertEquals('a d c', $this->smarty->fetch('eval:{$foo["a"]} {$foo["b"]} {$foo["c"]}'));
$bar = array('b' => 'newd');
$this->smarty->appendByRef('foo', $bar, true);
$this->assertEquals('a newd c', $this->smarty->fetch('eval:{$foo["a"]} {$foo["b"]} {$foo["c"]}'));
}
}

View File

@@ -1,2 +0,0 @@
# Ignore anything in here, but keep this directory
*

View File

@@ -1,2 +0,0 @@
# Ignore anything in here, but keep this directory
*

View File

@@ -1,33 +0,0 @@
<?php
/**
* Smarty PHPunit tests assignByRef method
*
* @author Uwe Tews
*/
/**
* class for assignByRef tests
*
*
*
*
*/
class AssignByRefTest extends PHPUnit_Smarty
{
public function setUp(): void
{
$this->setUpSmarty(__DIR__);
}
/**
* test simple assignByRef
*/
public function testSimpleAssignByRef()
{
$bar = 'bar';
$this->smarty->assignByRef('foo', $bar);
$bar = 'newbar';
$this->assertEquals('newbar', $this->smarty->fetch('eval:{$foo}'));
}
}

View File

@@ -1,2 +0,0 @@
# Ignore anything in here, but keep this directory
*

View File

@@ -1,2 +0,0 @@
# Ignore anything in here, but keep this directory
*

View File

@@ -31,8 +31,6 @@ class ScopeTest extends PHPUnit_Smarty
/**
* Test scope
*
*
*
* @dataProvider dataTestAppendScope
*/
public function testAppendScope($code, $useSmarty, $result, $testName, $testNumber)
@@ -50,8 +48,8 @@ class ScopeTest extends PHPUnit_Smarty
"test - {$code} - {$testName}");
}
/*
* Data provider für testAppendScope
/**
* Data provider for testAppendScope
*/
public function dataTestAppendScope()
{
@@ -78,9 +76,6 @@ class ScopeTest extends PHPUnit_Smarty
/**
* Test scope
*
* @not runInSeparateProcess
*
* @dataProvider dataTestAssignScope
*/
public function testAssignScope($code, $useSmarty, $result, $testName, $testNumber)