- optimization of generated code for doublequoted strings containing variables

- rewrite of {function} tag handling
  - can now be declared in an external subtemplate
  - can contain nocache sections (nocache_hash handling)
  - can be called in noccache sections (nocache_hash handling)
  - new {call..} tag to call template functions with a variable name {call name=$foo}
- fixed nocache_hash handling in merged compiled templates
This commit is contained in:
Uwe.Tews
2009-12-31 16:38:12 +00:00
parent a6c4c0b192
commit 72219be200
8 changed files with 141 additions and 70 deletions

View File

@@ -1,3 +1,12 @@
12/31/2009
- optimization of generated code for doublequoted strings containing variables
- rewrite of {function} tag handling
- can now be declared in an external subtemplate
- can contain nocache sections (nocache_hash handling)
- can be called in noccache sections (nocache_hash handling)
- new {call..} tag to call template functions with a variable name {call name=$foo}
- fixed nocache_hash handling in merged compiled templates
12/30/2009
- bugfix for plugins defined in the script as smarty_function_foo

View File

@@ -32,32 +32,14 @@ class Smarty_Internal_Compile_Call extends Smarty_Internal_CompileBase {
// output will be stored in a smarty variable instead of beind displayed
$_assign = $_attr['assign'];
}
$_name = trim($_attr['name'], "'");
// create template object
$_output = "<?php \$_template = new {$compiler->smarty->template_class} ('string:', \$_smarty_tpl->smarty, \$_smarty_tpl);\n";
$_output .= "\$_template->properties['nocache_hash'] = \$_smarty_tpl->smarty->template_functions['$_name']['nocache_hash'];\n";
// set flag (compiled code of {function} must be included in cache file
if ($this->compiler->nocache || $this->compiler->tag_nocache) {
$compiler->smarty->template_functions[$_name]['called_nocache'] = true;
$compiler->template->properties['function'][$_name]['called_nocache'] = true;
}
// assign default paramter
if (isset($this->smarty->template_functions[$_name]['parameter'])) {
// function is already compiled
foreach ($this->smarty->template_functions[$_name]['parameter'] as $_key => $_value) {
if (!isset($_attr[$_key])) {
$_output .= "\$_template->assign('$_key',$_value);\n";
}
}
}
if (isset($compiler->template->properties['function'][$_name]['parameter'])) {
// for recursive call during function compilation
foreach ($compiler->template->properties['function'][$_name]['parameter'] as $_key => $_value) {
if (!isset($_attr[$_key])) {
$_output .= "\$_template->assign('$_key',$_value);\n";
}
}
$nocache = 'true';
} else {
$nocache = 'false';
}
// create template object
$_output = "<?php \$_template = new Smarty_Internal_Function_Call_Handler ({$_attr['name']}, \$_smarty_tpl->smarty, \$_smarty_tpl, {$nocache});\n";
// delete {include} standard attributes
unset($_attr['name'], $_attr['assign']);
// remaining attributes must be assigned as smarty variable
@@ -67,14 +49,13 @@ class Smarty_Internal_Compile_Call extends Smarty_Internal_CompileBase {
$_output .= "\$_template->assign('$_key',$_value);\n";
}
}
// load compiled function
$_output .= "\$_template->compiled_template = \$this->smarty->template_functions['$_name']['compiled'];\n\$_template->mustCompile = false;\n";
// was there an assign attribute
if (isset($_assign)) {
$_output .= "\$_smarty_tpl->assign($_assign,\$_template->getRenderedTemplate()); ?>";
$_output .= "\$_smarty_tpl->assign({$_assign},\$_template->getRenderedTemplate());\n";
} else {
$_output .= "echo \$_template->getRenderedTemplate(); ?>";
$_output .= "echo \$_template->getRenderedTemplate();\n";
}
$_output .= 'unset($_template);?>';
return $_output;
}
}

View File

@@ -26,7 +26,8 @@ class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase {
$this->optional_attributes = array('_any');
// check and get attributes
$_attr = $this->_get_attributes($args);
$save = array($_attr, $compiler->template->extracted_compiled_code, $compiler->template->extract_code, $compiler->template->has_nocache_code);
$save = array($_attr, $compiler->template->extracted_compiled_code, $compiler->template->extract_code,
$compiler->template->has_nocache_code, $compiler->template->required_plugins);
$this->_open_tag('function', $save);
$_name = trim($_attr['name'], "'");
unset($_attr['name']);
@@ -35,6 +36,8 @@ class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase {
}
// make function known for recursive calls
$this->compiler->smarty->template_functions[$_name]['compiled'] = '';
// Init temporay context
$compiler->template->required_plugins = array('compiled' => array(), 'cache' => array());
$compiler->template->extract_code = true;
$compiler->template->extracted_compiled_code = '';
$compiler->template->has_code = false;
@@ -61,17 +64,34 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase
$_attr = $this->_get_attributes($args);
$saved_data = $this->_close_tag(array('function'));
$_name = trim($saved_data[0]['name'], "'");
$compiler->template->properties['function'][$_name]['compiled'] = $compiler->template->extracted_compiled_code;
// build plugin include code
$plugins_string = '';
if (!empty($compiler->template->required_plugins['compiled'])) {
$plugins_string = '<?php ';
foreach($compiler->template->required_plugins['compiled'] as $plugin_name => $data) {
$plugin = 'smarty_' . $data['type'] . '_' . $plugin_name;
$plugins_string .= "if (!is_callable('{$plugin}')) include '{$data['file']}';\n";
}
$plugins_string .= '?>';
}
if (!empty($compiler->template->required_plugins['cache'])) {
$plugins_string .= "<?php echo '/*%%SmartyNocache:{$compiler->template->properties['nocache_hash']}%%*/<?php ";
foreach($compiler->template->required_plugins['cache'] as $plugin_name => $data) {
$plugin = 'smarty_' . $data['type'] . '_' . $plugin_name;
$plugins_string .= "if (!is_callable(\'{$plugin}\')) include \'{$data['file']}\';\n";
}
$plugins_string .= "?>/*/%%SmartyNocache:{$compiler->template->properties['nocache_hash']}%%*/';?>\n";
}
$compiler->template->properties['function'][$_name]['compiled'] = $plugins_string . $compiler->template->extracted_compiled_code;
$compiler->template->properties['function'][$_name]['nocache_hash'] = $compiler->template->properties['nocache_hash'];
$compiler->template->properties['function'][$_name]['has_nocache_code'] = $compiler->template->has_nocache_code;
$this->compiler->smarty->template_functions[$_name]['compiled'] = $compiler->template->extracted_compiled_code;
$this->compiler->smarty->template_functions[$_name]['parameter'] = $compiler->template->properties['function'][$_name]['parameter'];
$this->compiler->smarty->template_functions[$_name]['nocache_hash'] = $compiler->template->properties['nocache_hash'];
$this->compiler->smarty->template_functions[$_name]['has_nocache_code'] = $compiler->template->has_nocache_code;
// restore old code extraction status
// $compiler->template->properties['function'][$_name]['plugins'] = $compiler->template->required_plugins;
$this->compiler->smarty->template_functions[$_name] = $compiler->template->properties['function'][$_name];
// restore old compiler status
$compiler->template->extracted_compiled_code = $saved_data[1];
$compiler->template->extract_code = $saved_data[2];
$compiler->template->has_nocache_code = $saved_data[3];
$compiler->template->required_plugins = $saved_data[4];
return true;
}
}

View File

@@ -107,7 +107,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase {
}
}
// create template object
$_output = "<?php \$_template = new {$compiler->smarty->template_class}($include_file, \$_smarty_tpl->smarty, \$_smarty_tpl, \$_smarty_tpl->cache_id, \$_smarty_tpl->compile_id, $_caching, $_cache_lifetime);";
$_output = "<?php \$_template = new {$compiler->smarty->template_class}($include_file, \$_smarty_tpl->smarty, \$_smarty_tpl, \$_smarty_tpl->cache_id, \$_smarty_tpl->compile_id, $_caching, $_cache_lifetime);\n";
// delete {include} standard attributes
unset($_attr['file'], $_attr['assign'], $_attr['cache_lifetime'], $_attr['nocache'], $_attr['caching'], $_attr['scope'], $_attr['inline']);
// remaining attributes must be assigned as smarty variable
@@ -126,6 +126,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase {
$_output .= "\$_smarty_tpl->assign($_assign,\$_template->getRenderedTemplate());?>";
} else {
if ($has_compiled_template && !($compiler->template->caching && ($this->compiler->tag_nocache || $this->compiler->nocache))) {
$_output .= "\$_template->properties['nocache_hash'] = '{$compiler->template->properties['nocache_hash']}';\n";
$_output .= "\$_tpl_stack[] = \$_smarty_tpl; \$_smarty_tpl = \$_template;?>\n";
$_output .= $compiled_tpl;
$_output .= "<?php \$_smarty_tpl->updateParentVariables($_parent_scope);?>";

View File

@@ -0,0 +1,47 @@
<?php
/**
* Smarty Internal Plugin Function Call Handler
*
* @package Smarty
* @subpackage Security
* @author Uwe Tews
*/
/**
* This class does call function defined with the {function} tag
*/
class Smarty_Internal_Function_Call_Handler extends Smarty_Internal_Template {
function __construct($name, $smarty, $parent, $nocache)
{
parent::__construct('string:', $smarty, $parent);
if (!isset($this->smarty->template_functions[$name])) {
throw new Exception("Call to undefined template function \"{$name}\" in template \"{$parent->template_resource}\"");
}
$this->called_nocache = $nocache;
$this->mustCompile = false;
if ($nocache) {
$smarty->template_functions[$name]['called_nocache'] = true;
$this->properties['function'][$name]['called_nocache'] = true;
}
$this->properties['nocache_hash'] = $smarty->template_functions[$name]['nocache_hash'];
// load compiled function
if ($nocache) {
// if called in nocache mode convert nocache code to real code
$this->compiled_template = preg_replace(array("!(<\?php echo ')?/\*/?%%SmartyNocache:{$this->smarty->template_functions[$name]['nocache_hash']}%%\*/(';\?>)?!", "!\\\'!"), array('', "'"), $smarty->template_functions[$name]['compiled']);
} else {
$this->compiled_template = $smarty->template_functions[$name]['compiled'];
}
// assign default paramter
if (isset($smarty->template_functions[$name]['parameter'])) {
$_smarty_tpl = $this;
foreach ($smarty->template_functions[$name]['parameter'] as $_key => $_value) {
$this->assign($_key, eval("return {$_value};"));
}
}
// set flag if {function} contains nocache code
if ($smarty->template_functions[$name]['has_nocache_code']) {
$this->has_nocache_code = true;
}
}
}
?>

View File

@@ -484,6 +484,11 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
if ($this->smarty->debugging) {
Smarty_Internal_Debug::start_cache($this);
}
// dummy renderung because of {function} nocache handling
$_smarty_tpl = $this;
ob_start();
eval("?>" . $this->rendered_content);
ob_get_clean();
// write rendered template
if (!$this->cacheFileWritten) {
$this->writeCachedContent($this);
@@ -495,10 +500,11 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
Smarty_Internal_Debug::end_cache($this);
}
} else {
// var_dump('renderTemplate',$this->has_nocache_code,$this->template_resource, $this->has_nocache_code, $this->properties['nocache_hash'], $this->parent->properties['nocache_hash'], $this->rendered_content);
// var_dump('renderTemplate', $this->has_nocache_code, $this->template_resource, $this->properties['nocache_hash'], $this->parent->properties['nocache_hash'], $this->rendered_content);
if ($this->has_nocache_code && !empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) {
// replace nocache_hash
$this->rendered_content = preg_replace("/{$this->properties['nocache_hash']}/", $this->parent->properties['nocache_hash'], $this->rendered_content);
$this->parent->has_nocache_code = $this->has_nocache_code;
}
}
}
@@ -780,6 +786,7 @@ class Smarty_Internal_Template extends Smarty_Internal_Data {
$this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']);
}
if (!empty($properties['function'])) {
$this->properties['function'] = array_merge($this->properties['function'], $properties['function']);
$this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']);
}
}

View File

@@ -117,7 +117,7 @@ class Smarty_Internal_TemplateCompilerBase {
if (($_output = $this->callTagCompiler($tag, $args)) === false) {
if (isset($this->smarty->template_functions[$tag])) {
// template defined by {template} tag
$args['name'] = $tag;
$args['name'] = "'" . $tag . "'";
$_output = $this->callTagCompiler('call', $args);
}
}
@@ -287,29 +287,30 @@ class Smarty_Internal_TemplateCompilerBase {
foreach((array)$this->smarty->plugins_dir as $_plugin_dir) {
$file = rtrim($_plugin_dir, '/\\') . DS . $type . '.' . $plugin_name . '.php';
if (file_exists($file)) {
require_once($file);
// require_once($file);
$found = true;
break;
}
}
if ($found) {
if (is_callable($plugin)) {
$this->template->required_plugins_call[$plugin_name][$type] = $plugin;
if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
$this->template->required_plugins['cache'][$plugin_name]['file'] = $file;
$this->template->required_plugins['cache'][$plugin_name]['type'] = $type;
} else {
$this->template->required_plugins['compiled'][$plugin_name]['file'] = $file;
$this->template->required_plugins['compiled'][$plugin_name]['type'] = $type;
}
if ($type == 'modifier') {
$this->template->saved_modifer[$plugin_name] = true;
}
return $plugin;
// if (is_callable($plugin)) {
$this->template->required_plugins_call[$plugin_name][$type] = $plugin;
if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
$this->template->required_plugins['cache'][$plugin_name]['file'] = $file;
$this->template->required_plugins['cache'][$plugin_name]['type'] = $type;
} else {
$this->template->required_plugins['compiled'][$plugin_name]['file'] = $file;
$this->template->required_plugins['compiled'][$plugin_name]['type'] = $type;
}
if ($type == 'modifier') {
$this->template->saved_modifer[$plugin_name] = true;
}
return $plugin;
/* } else {
throw new Exception("Plugin {$type} \"{$plugin_name}\" not callable");
}
*/
}
return false;
}

View File

@@ -1826,9 +1826,9 @@ static public $yy_action = array(
174 => 174,
175 => 175,
179 => 179,
182 => 179,
180 => 180,
180 => 179,
181 => 181,
182 => 182,
183 => 183,
184 => 184,
);
@@ -2273,20 +2273,25 @@ static public $yy_action = array(
function yy_r175(){ $this->_retvalue = '\''.$this->yystack[$this->yyidx + -2]->minor.'\'=>'.$this->yystack[$this->yyidx + 0]->minor; }
#line 2269 "smarty_internal_templateparser.php"
#line 515 "smarty_internal_templateparser.y"
function yy_r179(){$this->_retvalue = '".'.$this->yystack[$this->yyidx + -1]->minor.'."'; $this->compiler->has_variable_string = true; }
function yy_r179(){$this->_retvalue = '{'.$this->yystack[$this->yyidx + -1]->minor.'}'; $this->compiler->has_variable_string = true; }
#line 2272 "smarty_internal_templateparser.php"
#line 516 "smarty_internal_templateparser.y"
function yy_r180(){$this->_retvalue = '".('.$this->yystack[$this->yyidx + -1]->minor.')."'; $this->compiler->has_variable_string = true; }
#line 2275 "smarty_internal_templateparser.php"
#line 517 "smarty_internal_templateparser.y"
function yy_r181(){$this->_retvalue = '".'.'$_smarty_tpl->getVariable(\''. substr($this->yystack[$this->yyidx + 0]->minor,1) .'\')->value'.'."'; $this->compiler->tag_nocache=$this->compiler->tag_nocache|$this->template->getVariable(trim($this->yystack[$this->yyidx + 0]->minor,"'"), null, true, false)->nocache; $this->compiler->has_variable_string = true; }
#line 2278 "smarty_internal_templateparser.php"
#line 519 "smarty_internal_templateparser.y"
function yy_r181(){$this->_retvalue = '{$_smarty_tpl->getVariable(\''. substr($this->yystack[$this->yyidx + 0]->minor,1) .'\')->value}'; $this->compiler->tag_nocache=$this->compiler->tag_nocache|$this->template->getVariable(trim($this->yystack[$this->yyidx + 0]->minor,"'"), null, true, false)->nocache; $this->compiler->has_variable_string = true; }
#line 2275 "smarty_internal_templateparser.php"
#line 518 "smarty_internal_templateparser.y"
function yy_r182(){if (substr($this->yystack[$this->yyidx + -1]->minor,0,1) == '\'') {
$this->_retvalue = '".'.$this->yystack[$this->yyidx + -1]->minor.'."'; $this->compiler->has_variable_string = true;
} else {
$this->_retvalue = '{'.$this->yystack[$this->yyidx + -1]->minor.'}'; $this->compiler->has_variable_string = true;
}
}
#line 2283 "smarty_internal_templateparser.php"
#line 524 "smarty_internal_templateparser.y"
function yy_r183(){ $this->_retvalue = '".('.$this->yystack[$this->yyidx + -1]->minor.')."'; $this->compiler->has_variable_string = true; }
#line 2281 "smarty_internal_templateparser.php"
#line 520 "smarty_internal_templateparser.y"
function yy_r184(){ $this->prefix_number++; $this->compiler->prefix_code[] = '<?php ob_start();?>'.$this->yystack[$this->yyidx + 0]->minor.'<?php $_tmp'.$this->prefix_number.'=ob_get_clean();?>'; $this->_retvalue = '".$_tmp'.$this->prefix_number.'."'; $this->compiler->has_variable_string = true; }
#line 2284 "smarty_internal_templateparser.php"
#line 2286 "smarty_internal_templateparser.php"
#line 525 "smarty_internal_templateparser.y"
function yy_r184(){ $this->prefix_number++; $this->compiler->prefix_code[] = '<?php ob_start();?>'.$this->yystack[$this->yyidx + 0]->minor.'<?php $_tmp'.$this->prefix_number.'=ob_get_clean();?>'; $this->_retvalue = '{$_tmp'.$this->prefix_number.'}'; $this->compiler->has_variable_string = true; }
#line 2289 "smarty_internal_templateparser.php"
private $_retvalue;
@@ -2348,7 +2353,7 @@ static public $yy_action = array(
$this->internalError = true;
$this->yymajor = $yymajor;
$this->compiler->trigger_template_error();
#line 2347 "smarty_internal_templateparser.php"
#line 2352 "smarty_internal_templateparser.php"
}
function yy_accept()
@@ -2365,7 +2370,7 @@ static public $yy_action = array(
$this->internalError = false;
$this->retvalue = $this->_retvalue;
//echo $this->retvalue."\n\n";
#line 2365 "smarty_internal_templateparser.php"
#line 2370 "smarty_internal_templateparser.php"
}
function doParse($yymajor, $yytokenvalue)