mirror of
https://github.com/smarty-php/smarty.git
synced 2025-08-02 17:34:26 +02:00
WIP fixing the complicated variables scopes architecture. Right now more tests are failing than before... :(
This commit is contained in:
@@ -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
|
||||
*
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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";
|
||||
}
|
||||
}
|
||||
|
@@ -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";
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
*
|
||||
|
166
src/Data.php
166
src/Data.php
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@@ -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)) {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -120,7 +120,6 @@ class InheritanceRuntime {
|
||||
$tpl->caching ? 9999 : 0,
|
||||
$tpl->cache_lifetime,
|
||||
[],
|
||||
2,
|
||||
false,
|
||||
$uid,
|
||||
$func
|
||||
|
@@ -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;
|
||||
|
179
src/Template.php
179
src/Template.php
@@ -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
|
||||
|
@@ -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
|
||||
*
|
||||
|
@@ -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;
|
||||
|
@@ -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() {
|
||||
|
@@ -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"]}'));
|
||||
}
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
# Ignore anything in here, but keep this directory
|
||||
*
|
@@ -1,2 +0,0 @@
|
||||
# Ignore anything in here, but keep this directory
|
||||
*
|
@@ -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}'));
|
||||
}
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
# Ignore anything in here, but keep this directory
|
||||
*
|
@@ -1,2 +0,0 @@
|
||||
# Ignore anything in here, but keep this directory
|
||||
*
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user