From 72219be200321b9827eae44890f2bfe558bbefc6 Mon Sep 17 00:00:00 2001 From: "Uwe.Tews" Date: Thu, 31 Dec 2009 16:38:12 +0000 Subject: [PATCH] - 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 --- change_log.txt | 9 ++++ .../smarty_internal_compile_call.php | 35 ++++---------- .../smarty_internal_compile_function.php | 38 +++++++++++---- .../smarty_internal_compile_include.php | 5 +- .../smarty_internal_function_call_handler.php | 47 +++++++++++++++++++ libs/sysplugins/smarty_internal_template.php | 9 +++- .../smarty_internal_templatecompilerbase.php | 33 ++++++------- .../smarty_internal_templateparser.php | 35 ++++++++------ 8 files changed, 141 insertions(+), 70 deletions(-) create mode 100644 libs/sysplugins/smarty_internal_function_call_handler.php diff --git a/change_log.txt b/change_log.txt index 79477d43..3d4803ac 100644 --- a/change_log.txt +++ b/change_log.txt @@ -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 diff --git a/libs/sysplugins/smarty_internal_compile_call.php b/libs/sysplugins/smarty_internal_compile_call.php index 4e548926..6fd8aa89 100644 --- a/libs/sysplugins/smarty_internal_compile_call.php +++ b/libs/sysplugins/smarty_internal_compile_call.php @@ -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 = "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 = "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; } } diff --git a/libs/sysplugins/smarty_internal_compile_function.php b/libs/sysplugins/smarty_internal_compile_function.php index c2e121b1..7ebf5e47 100644 --- a/libs/sysplugins/smarty_internal_compile_function.php +++ b/libs/sysplugins/smarty_internal_compile_function.php @@ -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']); @@ -34,7 +35,9 @@ class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase { $compiler->template->properties['function'][$_name]['parameter'][$_key] = $_data; } // make function known for recursive calls - $this->compiler->smarty->template_functions[$_name]['compiled'] = ''; + $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; @@ -60,18 +63,35 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase $this->compiler->has_code = false; $_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; + $_name = trim($saved_data[0]['name'], "'"); + // build plugin include code + $plugins_string = ''; + if (!empty($compiler->template->required_plugins['compiled'])) { + $plugins_string = '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 .= "template->properties['nocache_hash']}%%*/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; } } diff --git a/libs/sysplugins/smarty_internal_compile_include.php b/libs/sysplugins/smarty_internal_compile_include.php index f489fe7d..52a4ff91 100644 --- a/libs/sysplugins/smarty_internal_compile_include.php +++ b/libs/sysplugins/smarty_internal_compile_include.php @@ -44,7 +44,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase { // make sure that template is up to date and merge template properties $tpl->renderTemplate(); // compiled code for {function} tags - $compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $tpl->properties['function']); + $compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $tpl->properties['function']); // get compiled code $compiled_tpl = $tpl->getCompiledTemplate(); // remove header code @@ -107,7 +107,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase { } } // create template object - $_output = "smarty->template_class}($include_file, \$_smarty_tpl->smarty, \$_smarty_tpl, \$_smarty_tpl->cache_id, \$_smarty_tpl->compile_id, $_caching, $_cache_lifetime);"; + $_output = "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 .= "updateParentVariables($_parent_scope);?>"; diff --git a/libs/sysplugins/smarty_internal_function_call_handler.php b/libs/sysplugins/smarty_internal_function_call_handler.php new file mode 100644 index 00000000..cdbd3fae --- /dev/null +++ b/libs/sysplugins/smarty_internal_function_call_handler.php @@ -0,0 +1,47 @@ +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; + } + } +} + +?> diff --git a/libs/sysplugins/smarty_internal_template.php b/libs/sysplugins/smarty_internal_template.php index 0531c96a..3458c0e4 100644 --- a/libs/sysplugins/smarty_internal_template.php +++ b/libs/sysplugins/smarty_internal_template.php @@ -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']); } } diff --git a/libs/sysplugins/smarty_internal_templatecompilerbase.php b/libs/sysplugins/smarty_internal_templatecompilerbase.php index a4d82000..45d06551 100644 --- a/libs/sysplugins/smarty_internal_templatecompilerbase.php +++ b/libs/sysplugins/smarty_internal_templatecompilerbase.php @@ -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; } diff --git a/libs/sysplugins/smarty_internal_templateparser.php b/libs/sysplugins/smarty_internal_templateparser.php index 4977916a..c297c5ef 100644 --- a/libs/sysplugins/smarty_internal_templateparser.php +++ b/libs/sysplugins/smarty_internal_templateparser.php @@ -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[] = ''.$this->yystack[$this->yyidx + 0]->minor.'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[] = ''.$this->yystack[$this->yyidx + 0]->minor.'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)