From c5cdd90352e19f51af2b3f03b3aad1fae3abbcfd Mon Sep 17 00:00:00 2001 From: Uwe Tews Date: Fri, 31 Jul 2015 01:03:29 +0200 Subject: [PATCH] - optimize {foreach} and {section} compiler --- change_log.txt | 3 + libs/Smarty.class.php | 2 +- .../smarty_internal_compile_foreach.php | 172 +++------ ...nternal_compile_private_foreachsection.php | 238 ++++++++++++ ...ernal_compile_private_special_variable.php | 29 +- .../smarty_internal_compile_section.php | 353 ++++++++---------- 6 files changed, 483 insertions(+), 314 deletions(-) create mode 100644 libs/sysplugins/smarty_internal_compile_private_foreachsection.php diff --git a/change_log.txt b/change_log.txt index 1141a9d4..b2395dca 100644 --- a/change_log.txt +++ b/change_log.txt @@ -1,4 +1,7 @@  ===== 3.1.28-dev===== (xx.xx.2015) + 31.07.2015 + - optimize {foreach} and {section} compiler + 29.07.2015 - optimize {section} compiler for speed and size of compiled code diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index eeb0bf9d..925d6916 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -111,7 +111,7 @@ class Smarty extends Smarty_Internal_TemplateBase /** * smarty version */ - const SMARTY_VERSION = '3.1.28-dev/34'; + const SMARTY_VERSION = '3.1.28-dev/35'; /** * define variable scopes diff --git a/libs/sysplugins/smarty_internal_compile_foreach.php b/libs/sysplugins/smarty_internal_compile_foreach.php index ad34d11b..ab37a63c 100644 --- a/libs/sysplugins/smarty_internal_compile_foreach.php +++ b/libs/sysplugins/smarty_internal_compile_foreach.php @@ -14,7 +14,7 @@ * @package Smarty * @subpackage Compiler */ -class Smarty_Internal_Compile_Foreach extends Smarty_Internal_CompileBase +class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_ForeachSection { /** * Attribute definition: Overwrites base class. @@ -41,11 +41,39 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_CompileBase public $shorttag_order = array('from', 'item', 'key', 'name'); /** - * Foreach counter + * counter * * @var int */ - public $foreach_number = 0; + public $counter = 0; + + /** + * Name of this tag + * + * @var string + */ + public $tagName = 'foreach'; + + /** + * Valid properties of $smarty.foreach.name.xxx variable + * + * @var array + */ + public static $nameProperties = array('first','last','index','iteration','show','total'); + + /** + * Valid properties of $item@xxx variable + * + * @var array + */ + public $itemProperties = array('first','last','index','iteration','show','total', 'key'); + + /** + * Flag if tag had name attribute + * + * @var bool + */ + public $isNamed = false; /** * Compiles code for the {foreach} tag @@ -59,6 +87,8 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_CompileBase */ public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) { + // init + $this->isNamed = false; // check and get attributes $_attr = $this->getAttributes($compiler, $args); $from = $_attr['from']; @@ -75,6 +105,7 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_CompileBase $attributes['key'] = $key; } if (isset($_attr['name'])) { + $this->isNamed = true; $attributes['name'] = $compiler->getId($_attr['name']); } foreach ($attributes as $a => $v) { @@ -90,76 +121,20 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_CompileBase } } } - $attributes['no'] = $this->foreach_number ++ . '_' . (isset($attributes['name']) ? $attributes['name'] : $attributes['item']); + $attributes['no'] = $this->counter ++ . '_' . (isset($attributes['name']) ? $attributes['name'] : $attributes['item']); $this->openTag($compiler, 'foreach', array('foreach', $compiler->nocache, $attributes, true)); // maybe nocache because of nocache variables $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; - // prepare preg - if ($has_name = isset($attributes['name'])) { - $smartyPreg = "|([\$]smarty[.]foreach[.]{$attributes['name']}[.]((first)|(last)|(index)|(iteration)|(show)|(total)))"; - } else { - $smartyPreg = ''; - } - $itemPreg = "([\$]{$attributes['item']}[@]((first)|(last)|(index)|(iteration)|(show)|(total)|(key)))"; - $preg = '~(' . $itemPreg . $smartyPreg . ')\W~i'; + // search for used tag attributes $itemAttr = array(); - $smartyAttr = array(); - - // search template source - preg_match_all($preg, $compiler->lex->data, $match, PREG_SET_ORDER); - foreach ($match as $m) { - if (isset($m[3]) && !empty($m[3])) { - $itemAttr[strtolower($m[3])] = true; - } - if ($has_name && isset($m[12]) && !empty($m[12])) { - $smartyAttr[strtolower($m[12])] = true; - } + $namedAttr = array(); + $this->scanForProperties($attributes, $compiler); + if (!empty($this->matchResults['item'])) { + $itemAttr = $this->matchResults['item']; } - - // search {block} sources - foreach ($compiler->template->block_data as $b) { - if (isset($b['source'])) { - preg_match_all($preg, $b['source'], $match, PREG_SET_ORDER); - foreach ($match as $m) { - if (isset($m[3]) && !empty($m[3])) { - $itemAttr[strtolower($m[3])] = true; - } - if ($has_name && isset($m[12]) && !empty($m[12])) { - $smartyAttr[strtolower($m[12])] = true; - } - } - } - } - if (class_exists('Smarty_Internal_Compile_Block', false)) { - foreach (Smarty_Internal_Compile_Block::$block_data as $b) { - if (isset($b['source'])) { - preg_match_all($preg, $b['source'], $match, PREG_SET_ORDER); - foreach ($match as $m) { - if (isset($m[3]) && !empty($m[3])) { - $itemAttr[strtolower($m[3])] = true; - } - if ($has_name && isset($m[12]) && !empty($m[12])) { - $smartyAttr[strtolower($m[12])] = true; - } - } - } - } - } - - // search parent compiler template source - $nextCompiler = $compiler; - while ($nextCompiler !== $nextCompiler->parent_compiler) { - $nextCompiler = $nextCompiler->parent_compiler; - preg_match_all($preg, $nextCompiler->template->source->getContent(), $match, PREG_SET_ORDER); - foreach ($match as $m) { - if (isset($m[3]) && !empty($m[3])) { - $itemAttr[strtolower($m[3])] = true; - } - if ($has_name && isset($m[12]) && !empty($m[12])) { - $smartyAttr[strtolower($m[12])] = true; - } - } + if (!empty($this->matchResults['named'])) { + $namedAttr = $this->matchResults['named']; } if (!isset($itemAttr['index']) && (isset($itemAttr['first']) || isset($itemAttr['last']))) { @@ -168,12 +143,12 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_CompileBase if (isset($itemAttr['last'])) { $itemAttr['total'] = true; } - if ($has_name) { - if (!isset($smartyAttr['index']) && (isset($smartyAttr['first']) || isset($smartyAttr['last']))) { - $smartyAttr['iteration'] = true; + if ($this->isNamed) { + if (!isset($namedAttr['index']) && (isset($namedAttr['first']) || isset($namedAttr['last']))) { + $namedAttr['iteration'] = true; } - if (isset($smartyAttr['last'])) { - $smartyAttr['total'] = true; + if (isset($namedAttr['last'])) { + $namedAttr['total'] = true; } } @@ -218,28 +193,28 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_CompileBase $output .= "\$_smarty_tpl->tpl_vars['{$item}']->show = (\$_smarty_tpl->_count(\$_from) > 0);\n"; } } - if ($has_name) { + if ($this->isNamed) { $prop = array(); - if (isset($smartyAttr['total'])) { + if (isset($namedAttr['total'])) { $prop['total'] = "'total' => "; - $prop['total'] .= isset($smartyAttr['show']) ? '$total = ' : ''; + $prop['total'] .= isset($namedAttr['show']) ? '$total = ' : ''; $prop['total'] .= '$_smarty_tpl->_count($_from)'; } - if (isset($smartyAttr['iteration'])) { + if (isset($namedAttr['iteration'])) { $prop['iteration'] = "'iteration' => 0"; } - if (isset($smartyAttr['index'])) { + if (isset($namedAttr['index'])) { $prop['index'] = "'index' => -1"; } - if (isset($smartyAttr['show'])) { + if (isset($namedAttr['show'])) { $prop['show'] = "'show' => "; - if (isset($smartyAttr['total'])) { + if (isset($namedAttr['total'])) { $prop['show'] .= "(\$total > 0)"; } else { $prop['show'] .= "(\$_smarty_tpl->_count(\$_from) > 0)"; } } - if (!empty($smartyAttr)) { + if (!empty($namedAttr)) { $_vars = 'array(' . join(', ', $prop) . ')'; $foreachVar = "'__foreach_{$attributes['name']}'"; $output .= "\$_smarty_tpl->tpl_vars[$foreachVar] = new Smarty_Variable({$_vars});\n"; @@ -270,22 +245,22 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_CompileBase $output .= "\$_smarty_tpl->tpl_vars['{$item}']->last = \$_smarty_tpl->tpl_vars['{$item}']->iteration == \$_smarty_tpl->tpl_vars['{$item}']->total;\n"; } } - if ($has_name) { - if (isset($smartyAttr['iteration'])) { + if ($this->isNamed) { + if (isset($namedAttr['iteration'])) { $output .= "\$_smarty_tpl->tpl_vars[$foreachVar]->value['iteration']++;\n"; } - if (isset($smartyAttr['index'])) { + if (isset($namedAttr['index'])) { $output .= "\$_smarty_tpl->tpl_vars[$foreachVar]->value['index']++;\n"; } - if (isset($smartyAttr['first'])) { - if (isset($smartyAttr['index'])) { + if (isset($namedAttr['first'])) { + if (isset($namedAttr['index'])) { $output .= "\$_smarty_tpl->tpl_vars[$foreachVar]->value['first'] = \$_smarty_tpl->tpl_vars[$foreachVar]->value['index'] == 0;\n"; } else { $output .= "\$_smarty_tpl->tpl_vars[$foreachVar]->value['first'] = \$_smarty_tpl->tpl_vars[$foreachVar]->value['iteration'] == 1;\n"; } } - if (isset($smartyAttr['last'])) { - if (isset($smartyAttr['index'])) { + if (isset($namedAttr['last'])) { + if (isset($namedAttr['index'])) { $output .= "\$_smarty_tpl->tpl_vars[$foreachVar]->value['last'] = \$_smarty_tpl->tpl_vars[$foreachVar]->value['index'] + 1 == \$_smarty_tpl->tpl_vars[$foreachVar]->value['total'];\n"; } else { $output .= "\$_smarty_tpl->tpl_vars[$foreachVar]->value['last'] = \$_smarty_tpl->tpl_vars[$foreachVar]->value['iteration'] == \$_smarty_tpl->tpl_vars[$foreachVar]->value['total'];\n"; @@ -297,29 +272,6 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_CompileBase return $output; } - - /** - * Compiles code for the {$smarty.foreach} tag - * - * @param array $args array with attributes from parser - * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object - * @param array $parameter array with compilation parameter - * - * @return string compiled code - * @throws \SmartyCompilerException - */ - public static function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) - { - if (!isset($parameter[1]) || false === $name = $compiler->getId($parameter[1])) { - $compiler->trigger_template_error("missing or illegal \$Smarty.foreach name attribute", $compiler->lex->taglineno); - } - if ((!isset($parameter[2]) || false === $property = $compiler->getId($parameter[2])) || !in_array(strtolower($property), array('first', 'last', 'index', 'iteration', 'show', 'total'))) { - $compiler->trigger_template_error("missing or illegal \$Smarty.foreach property attribute", $compiler->lex->taglineno); - } - $property = strtolower($property); - $foreachVar = "'__foreach_{$name}'"; - return "(isset(\$_smarty_tpl->tpl_vars[{$foreachVar}]->value['{$property}']) ? \$_smarty_tpl->tpl_vars[{$foreachVar}]->value['{$property}'] : null)"; - } } /** diff --git a/libs/sysplugins/smarty_internal_compile_private_foreachsection.php b/libs/sysplugins/smarty_internal_compile_private_foreachsection.php new file mode 100644 index 00000000..4492d982 --- /dev/null +++ b/libs/sysplugins/smarty_internal_compile_private_foreachsection.php @@ -0,0 +1,238 @@ +propertyPreg = '~('; + $this->startOffset = 0; + $this->resultOffsets = array(); + $this->matchResults = array('named' => array(), 'item' => array()); + if ($this->isNamed) { + $this->buildPropertyPreg(true, $attributes); + } + if (isset($this->itemProperties)) { + if ($this->isNamed) { + $this->propertyPreg .= '|'; + } + $this->buildPropertyPreg(false, $attributes); + } + $this->propertyPreg .= ')\W~i'; + // Template source + $this->matchTemplateSource($compiler); + // Parent template source + $this->matchParentTemplateSource($compiler); + // {block} source + $this->matchBlockSource($compiler); + } + + /** + * Build property preg string + * + * @param bool $named + * @param array $attributes + */ + public function buildPropertyPreg($named, $attributes) + { + if ($named) { + $this->resultOffsets['named'] = $this->startOffset + 3; + $this->propertyPreg .= "([\$]smarty[.]{$this->tagName}[.]{$attributes['name']}[.]("; + $className = get_class($this); + $properties = $className::$nameProperties; + } else { + $this->resultOffsets['item'] = $this->startOffset + 3; + $this->propertyPreg .= "([\$]{$attributes['item']}[@]("; + $properties = $this->itemProperties; + } + $this->startOffset += count($properties) + 2; + $propName = reset($properties); + while ($propName) { + $this->propertyPreg .= "({$propName})"; + $propName = next($properties); + if ($propName) { + $this->propertyPreg .= '|'; + } + } + $this->propertyPreg .= '))'; + } + + /** + * Find matches in source string + * + * @param string $source + */ + public function matchProperty($source) + { + preg_match_all($this->propertyPreg, $source, $match, PREG_SET_ORDER); + foreach ($this->resultOffsets as $key => $offset) { + foreach ($match as $m) { + if (isset($m[$offset]) && !empty($m[$offset])) { + $this->matchResults[$key][strtolower($m[$offset])] = true; + } + } + } + } + + /** + * Find matches in template source + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + */ + public function matchTemplateSource(Smarty_Internal_TemplateCompilerBase $compiler) + { + $this->matchProperty($compiler->lex->data); + } + + /** + * Find matches in all parent template source + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + */ + public function matchParentTemplateSource(Smarty_Internal_TemplateCompilerBase $compiler) + { + // search parent compiler template source + $nextCompiler = $compiler; + while ($nextCompiler !== $nextCompiler->parent_compiler) { + $nextCompiler = $nextCompiler->parent_compiler; + if ($compiler !== $nextCompiler) { + // get template source + $_content = $nextCompiler->template->source->getContent(); + if ($_content != '') { + // run pre filter if required + if ((isset($nextCompiler->smarty->autoload_filters['pre']) || + isset($nextCompiler->smarty->registered_filters['pre'])) && !$nextCompiler->suppressFilter + ) { + $_content = Smarty_Internal_Filter_Handler::runFilter('pre', $_content, $nextCompiler->template); + } + $this->matchProperty($_content); + } + } + } + } + + /** + * Find matches in {block} tag source + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + */ + public function matchBlockSource(Smarty_Internal_TemplateCompilerBase $compiler) + { + foreach ($compiler->template->block_data as $b) { + if (isset($b['source'])) { + $this->matchProperty($b['source']); + } + } + if (class_exists('Smarty_Internal_Compile_Block', false)) { + foreach (Smarty_Internal_Compile_Block::$block_data as $b) { + if (isset($b['source'])) { + $this->matchProperty($b['source']); + } + } + } + + $this->matchProperty($compiler->lex->data); + } + + /** + * Compiles code for the {$smarty.foreach.xxx} or {$smarty.section.xxx}tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + * @throws \SmartyCompilerException + */ + public static function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + // make all lower case + $parameter = array_map('strtolower', $parameter); + $tag = trim($parameter[0], '"\''); + if (!isset($parameter[1]) || false === $name = $compiler->getId($parameter[1])) { + $compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", $compiler->lex->taglineno); + } + $className = 'Smarty_Internal_Compile_' . ucfirst($tag); + if ((!isset($parameter[2]) || false === $property = $compiler->getId($parameter[2])) || + !in_array($property, $className::$nameProperties) + ) { + $compiler->trigger_template_error("missing or illegal \$smarty.{$tag} property attribute", $compiler->lex->taglineno); + } + $tagVar = "'__{$tag}_{$name}'"; + return "(isset(\$_smarty_tpl->tpl_vars[{$tagVar}]->value['{$property}']) ? \$_smarty_tpl->tpl_vars[{$tagVar}]->value['{$property}'] : null)"; + } +} \ No newline at end of file diff --git a/libs/sysplugins/smarty_internal_compile_private_special_variable.php b/libs/sysplugins/smarty_internal_compile_private_special_variable.php index df94d528..d734aa84 100644 --- a/libs/sysplugins/smarty_internal_compile_private_special_variable.php +++ b/libs/sysplugins/smarty_internal_compile_private_special_variable.php @@ -29,22 +29,25 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C { $_index = preg_split("/\]\[/", substr($parameter, 1, strlen($parameter) - 2)); $compiled_ref = ' '; - $variable = $compiler->getId($_index[0]); + $variable = strtolower($compiler->getId($_index[0])); if ($variable === false) { $compiler->trigger_template_error("special \$Smarty variable name index can not be variable", $compiler->lex->taglineno); - } - if (!isset($compiler->smarty->security_policy) || $compiler->smarty->security_policy->isTrustedSpecialSmartyVar($variable, $compiler)) { - switch ($variable) { + } + if (!isset($compiler->smarty->security_policy) || + $compiler->smarty->security_policy->isTrustedSpecialSmartyVar($variable, $compiler) + ) { + switch ($variable) { case 'foreach': - return Smarty_Internal_Compile_Foreach::compileSpecialVariable(array(), $compiler, $_index); case 'section': - return Smarty_Internal_Compile_Section::compileSpecialVariable(array(), $compiler, $_index); - case 'capture': + return Smarty_Internal_Compile_Private_ForeachSection::compileSpecialVariable(array(), $compiler, $_index); + case 'capture': return "Smarty::\$_smarty_vars$parameter"; case 'now': return 'time()'; case 'cookies': - if (isset($compiler->smarty->security_policy) && !$compiler->smarty->security_policy->allow_super_globals) { + if (isset($compiler->smarty->security_policy) && + !$compiler->smarty->security_policy->allow_super_globals + ) { $compiler->trigger_template_error("(secure mode) super globals not permitted"); break; } @@ -57,7 +60,9 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C case 'server': case 'session': case 'request': - if (isset($compiler->smarty->security_policy) && !$compiler->smarty->security_policy->allow_super_globals) { + if (isset($compiler->smarty->security_policy) && + !$compiler->smarty->security_policy->allow_super_globals + ) { $compiler->trigger_template_error("(secure mode) super globals not permitted"); break; } @@ -79,11 +84,13 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C return "'$_version'"; case 'const': - if (isset($compiler->smarty->security_policy) && !$compiler->smarty->security_policy->allow_constants) { + if (isset($compiler->smarty->security_policy) && + !$compiler->smarty->security_policy->allow_constants + ) { $compiler->trigger_template_error("(secure mode) constants not permitted"); break; } - if (strpos($_index[1], '$') === false && strpos($_index[1], '\'') === false ) { + if (strpos($_index[1], '$') === false && strpos($_index[1], '\'') === false) { return "@constant('{$_index[1]}')"; } else { return "@constant({$_index[1]})"; diff --git a/libs/sysplugins/smarty_internal_compile_section.php b/libs/sysplugins/smarty_internal_compile_section.php index c2ec19fa..6f099a79 100644 --- a/libs/sysplugins/smarty_internal_compile_section.php +++ b/libs/sysplugins/smarty_internal_compile_section.php @@ -14,7 +14,7 @@ * @package Smarty * @subpackage Compiler */ -class Smarty_Internal_Compile_Section extends Smarty_Internal_CompileBase +class Smarty_Internal_Compile_Section extends Smarty_Internal_Compile_Private_ForeachSection { /** * Attribute definition: Overwrites base class. @@ -47,6 +47,35 @@ class Smarty_Internal_Compile_Section extends Smarty_Internal_CompileBase */ public $counter = 0; + /** + * Name of this tag + * + * @var string + */ + public $tagName = 'section'; + + /** + * Valid properties of $smarty.section.name.xxx variable + * + * @var array + */ + public static $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total', 'rownum', + 'index_prev', 'index_next'); + + /** + * {section} tag has no item properties + * + * @var array + */ + public $itemProperties = null; + + /** + * {section} tag has always name attribute + * + * @var bool + */ + public $isNamed = true; + /** * Compiles code for the {section} tag * @@ -73,76 +102,22 @@ class Smarty_Internal_Compile_Section extends Smarty_Internal_CompileBase $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; $sectionVar = "\$_smarty_tpl->tpl_vars['__section_{$attributes['name']}']->value"; $local = "\$section_{$attributes['no']}_"; + $initLocal = array('saved' => "isset(\$_smarty_tpl->tpl_vars['__section_{$attributes['name']}']) ? \$_smarty_tpl->tpl_vars['__section_{$attributes['name']}'] : false",); + $initNamedProperty = array(); + $initFor = array(); + $incFor = array(); + $cmpFor = array(); + $propValue = array('index' => "{$sectionVar}['index']", 'show' => 'true', 'step' => 1, + 'iteration' => "{$local}iteration", - // prepare preg - $smartyPreg = "|([\$]smarty[.]section[.]{$attributes['name']}[.]((first)|(last)|(index)|(iteration)|(show)|(total)|(rownum)|(index_prev)|(index_next)))"; - $itemPreg = "(\[{$attributes['name']}[.]((first)|(last)|(index)|(iteration)|(show)|(total)|(rownum)|(index_prev)|(index_next))\])"; - $preg = '~(' . $itemPreg . $smartyPreg . ')\W~i'; - $smartyAttr = array('initLocal' => array('s_name' => "isset(\$_smarty_tpl->tpl_vars['__section_{$attributes['name']}']) ? \$_smarty_tpl->tpl_vars['__section_{$attributes['name']}'] : false",), - 'isSmarty' => array('index' => true,), 'initSmarty' => array(), 'initFor' => array(), - 'incFor' => array(), - 'value' => array('index' => "{$sectionVar}['index']", 'show' => 'true', 'step' => 1, - 'iteration' => "{$local}iteration", - - ), 'type' => array('index' => 2, 'iteration' => 2, 'show' => 0, 'step' => 0,), - 'cmpFor' => array(), 'before' => array(), 'after' => array(),); - - // search template source - preg_match_all($preg, $compiler->lex->data, $match, PREG_SET_ORDER); - foreach ($match as $m) { - if (isset($m[3]) && !empty($m[3])) { - $smartyAttr['isSmarty'][strtolower($m[3])] = true; - } - if (isset($m[14]) && !empty($m[14])) { - $smartyAttr['isSmarty'][strtolower($m[14])] = true; - } + ); + $propType = array('index' => 2, 'iteration' => 2, 'show' => 0, 'step' => 0,); + // search for used tag attributes + $this->scanForProperties($attributes, $compiler); + if (!empty($this->matchResults['named'])) { + $namedAttr = $this->matchResults['named']; } - - // search {block} sources - foreach ($compiler->template->block_data as $b) { - if (isset($b['source'])) { - preg_match_all($preg, $b['source'], $match, PREG_SET_ORDER); - foreach ($match as $m) { - if (isset($m[3]) && !empty($m[3])) { - $smartyAttr['isSmarty'][strtolower($m[3])] = true; - } - if (isset($m[14]) && !empty($m[14])) { - $smartyAttr['isSmarty'][strtolower($m[14])] = true; - } - } - } - } - if (class_exists('Smarty_Internal_Compile_Block', false)) { - foreach (Smarty_Internal_Compile_Block::$block_data as $b) { - if (isset($b['source'])) { - preg_match_all($preg, $b['source'], $match, PREG_SET_ORDER); - foreach ($match as $m) { - if (isset($m[3]) && !empty($m[3])) { - $smartyAttr['isSmarty'][strtolower($m[3])] = true; - } - if (isset($m[14]) && !empty($m[14])) { - $smartyAttr['isSmarty'][strtolower($m[14])] = true; - } - } - } - } - } - - // search parent compiler template source - $nextCompiler = $compiler; - while ($nextCompiler !== $nextCompiler->parent_compiler) { - $nextCompiler = $nextCompiler->parent_compiler; - preg_match_all($preg, $nextCompiler->template->source->getContent(), $match, PREG_SET_ORDER); - foreach ($match as $m) { - if (isset($m[3]) && !empty($m[3])) { - $smartyAttr['isSmarty'][strtolower($m[3])] = true; - } - if (isset($m[14]) && !empty($m[14])) { - $smartyAttr['isSmarty'][strtolower($m[14])] = true; - } - } - } - + $namedAttr['index'] = true; $output = " $attr_value) { switch ($attr_name) { @@ -154,13 +129,13 @@ class Smarty_Internal_Compile_Section extends Smarty_Internal_CompileBase $v = "(is_array(@\$_loop=$attr_value) ? count(\$_loop) : max(0, (int) \$_loop))"; $t = 1; } - if (isset($smartyAttr['isSmarty']['loop'])) { - $smartyAttr['initSmarty']['loop'] = "'loop' => {$v}"; + if (isset($namedAttr['loop'])) { + $initNamedProperty['loop'] = "'loop' => {$v}"; if ($t == 1) { $v = "{$sectionVar}['loop']"; } } elseif ($t == 1) { - $smartyAttr['initLocal']['loop'] = $v; + $initLocal['loop'] = $v; $v = "{$local}loop"; } break; @@ -180,7 +155,7 @@ class Smarty_Internal_Compile_Section extends Smarty_Internal_CompileBase $t = 0; break; } - $smartyAttr['initLocal']['step'] = "((int)@$attr_value) == 0 ? 1 : (int)@$attr_value"; + $initLocal['step'] = "((int)@$attr_value) == 0 ? 1 : (int)@$attr_value"; $v = "{$local}step"; $t = 2; break; @@ -199,213 +174,207 @@ class Smarty_Internal_Compile_Section extends Smarty_Internal_CompileBase if ($t == 3 && $compiler->getId($attr_value)) { $t = 1; } - $smartyAttr['value'][$attr_name] = $v; - $smartyAttr['type'][$attr_name] = $t; + $propValue[$attr_name] = $v; + $propType[$attr_name] = $t; } - if (isset($smartyAttr['isSmarty']['step'])) { - $smartyAttr['initSmarty']['step'] = $smartyAttr['value']['step']; + if (isset($namedAttr['step'])) { + $initNamedProperty['step'] = $propValue['step']; } - if (isset($smartyAttr['isSmarty']['iteration'])) { - $smartyAttr['value']['iteration'] = "{$sectionVar}['iteration']"; + if (isset($namedAttr['iteration'])) { + $propValue['iteration'] = "{$sectionVar}['iteration']"; } - $smartyAttr['incFor']['iteration'] = "{$smartyAttr['value']['iteration']}++"; - $smartyAttr['initFor']['iteration'] = "{$smartyAttr['value']['iteration']} = 1"; + $incFor['iteration'] = "{$propValue['iteration']}++"; + $initFor['iteration'] = "{$propValue['iteration']} = 1"; - if ($smartyAttr['type']['step'] == 0) { - if ($smartyAttr['value']['step'] == 1) { - $smartyAttr['incFor']['index'] = "{$sectionVar}['index']++"; - } elseif ($smartyAttr['value']['step'] > 1) { - $smartyAttr['incFor']['index'] = "{$sectionVar}['index'] += {$smartyAttr['value']['step']}"; + if ($propType['step'] == 0) { + if ($propValue['step'] == 1) { + $incFor['index'] = "{$sectionVar}['index']++"; + } elseif ($propValue['step'] > 1) { + $incFor['index'] = "{$sectionVar}['index'] += {$propValue['step']}"; } else { - $smartyAttr['incFor']['index'] = "{$sectionVar}['index'] -= " . - $smartyAttr['value']['step']; + $incFor['index'] = "{$sectionVar}['index'] -= " . - $propValue['step']; } } else { - $smartyAttr['incFor']['index'] = "{$sectionVar}['index'] += {$smartyAttr['value']['step']}"; + $incFor['index'] = "{$sectionVar}['index'] += {$propValue['step']}"; } - if (!isset($smartyAttr['value']['max'])) { - $smartyAttr['value']['max'] = $smartyAttr['value']['loop']; - $smartyAttr['type']['max'] = $smartyAttr['type']['loop']; - } elseif ($smartyAttr['type']['max'] != 0) { - $smartyAttr['value']['max'] = "{$smartyAttr['value']['max']} < 0 ? {$smartyAttr['value']['loop']} : {$smartyAttr['value']['max']}"; - $smartyAttr['type']['max'] = 1; + if (!isset($propValue['max'])) { + $propValue['max'] = $propValue['loop']; + $propType['max'] = $propType['loop']; + } elseif ($propType['max'] != 0) { + $propValue['max'] = "{$propValue['max']} < 0 ? {$propValue['loop']} : {$propValue['max']}"; + $propType['max'] = 1; } else { - if ($smartyAttr['value']['max'] < 0) { - $smartyAttr['value']['max'] = $smartyAttr['value']['loop']; - $smartyAttr['type']['max'] = $smartyAttr['type']['loop']; + if ($propValue['max'] < 0) { + $propValue['max'] = $propValue['loop']; + $propType['max'] = $propType['loop']; } } - if (!isset($smartyAttr['value']['start'])) { - $start_code = array(1 => "{$smartyAttr['value']['step']} > 0 ? ", 2 => '0', 3 => ' : ', - 4 => $smartyAttr['value']['loop'], 5 => ' - 1'); - if ($smartyAttr['type']['loop'] == 0) { + if (!isset($propValue['start'])) { + $start_code = array(1 => "{$propValue['step']} > 0 ? ", 2 => '0', 3 => ' : ', 4 => $propValue['loop'], + 5 => ' - 1'); + if ($propType['loop'] == 0) { $start_code[5] = ''; - $start_code[4] = $smartyAttr['value']['loop'] - 1; + $start_code[4] = $propValue['loop'] - 1; } - if ($smartyAttr['type']['step'] == 0) { - if ($smartyAttr['value']['step'] > 0) { + if ($propType['step'] == 0) { + if ($propValue['step'] > 0) { $start_code = array(1 => '0'); - $smartyAttr['type']['start'] = 0; + $propType['start'] = 0; } else { $start_code[1] = $start_code[2] = $start_code[3] = ''; - $smartyAttr['type']['start'] = $smartyAttr['type']['loop']; + $propType['start'] = $propType['loop']; } } else { - $smartyAttr['type']['start'] = 1; + $propType['start'] = 1; } - $smartyAttr['value']['start'] = join('', $start_code); + $propValue['start'] = join('', $start_code); } else { - $start_code = array(1 => "{$smartyAttr['value']['start']} < 0 ? ", 2 => 'max(', - 3 => "{$smartyAttr['value']['step']} > 0 ? ", 4 => '0', 5 => ' : ', 6 => '-1', - 7 => ', ', 8 => "{$smartyAttr['value']['start']} + {$smartyAttr['value']['loop']}", - 10 => ')', 11 => ' : ', 12 => 'min(', 13 => $smartyAttr['value']['start'], 14 => ', ', - 15 => "{$smartyAttr['value']['step']} > 0 ? ", 16 => $smartyAttr['value']['loop'], - 17 => ' : ', 18 => $smartyAttr['type']['loop'] == 0 ? $smartyAttr['value']['loop'] - - 1 : "{$smartyAttr['value']['loop']} - 1", 19 => ')'); - if ($smartyAttr['type']['step'] == 0) { + $start_code = array(1 => "{$propValue['start']} < 0 ? ", 2 => 'max(', 3 => "{$propValue['step']} > 0 ? ", + 4 => '0', 5 => ' : ', 6 => '-1', 7 => ', ', + 8 => "{$propValue['start']} + {$propValue['loop']}", 10 => ')', 11 => ' : ', + 12 => 'min(', 13 => $propValue['start'], 14 => ', ', + 15 => "{$propValue['step']} > 0 ? ", 16 => $propValue['loop'], 17 => ' : ', + 18 => $propType['loop'] == 0 ? $propValue['loop'] - 1 : "{$propValue['loop']} - 1", + 19 => ')'); + if ($propType['step'] == 0) { $start_code[3] = $start_code[5] = $start_code[15] = $start_code[17] = ''; - if ($smartyAttr['value']['step'] > 0) { + if ($propValue['step'] > 0) { $start_code[6] = $start_code[18] = ''; } else { $start_code[4] = $start_code[16] = ''; } } - if ($smartyAttr['type']['start'] == 0) { - if ($smartyAttr['type']['loop'] == 0) { - $start_code[8] = $smartyAttr['value']['start'] + $smartyAttr['value']['loop']; + if ($propType['start'] == 0) { + if ($propType['loop'] == 0) { + $start_code[8] = $propValue['start'] + $propValue['loop']; } - $smartyAttr['type']['start'] = $smartyAttr['type']['step'] + $smartyAttr['type']['loop']; + $propType['start'] = $propType['step'] + $propType['loop']; $start_code[1] = ''; - if ($smartyAttr['value']['start'] < 0) { + if ($propValue['start'] < 0) { for ($i = 11; $i <= 19; $i ++) { $start_code[$i] = ''; } - if ($smartyAttr['type']['start'] == 0) { - $start_code = array(max($smartyAttr['value']['step'] > - 0 ? 0 : - 1, $smartyAttr['value']['start'] + - $smartyAttr['value']['loop'])); + if ($propType['start'] == 0) { + $start_code = array(max($propValue['step'] > 0 ? 0 : - 1, $propValue['start'] + + $propValue['loop'])); } } else { for ($i = 1; $i <= 11; $i ++) { $start_code[$i] = ''; } - if ($smartyAttr['type']['start'] == 0) { - $start_code = array(min($smartyAttr['value']['step'] > - 0 ? $smartyAttr['value']['loop'] : $smartyAttr['value']['loop'] - - 1, $smartyAttr['value']['start'])); + if ($propType['start'] == 0) { + $start_code = array(min($propValue['step'] > 0 ? $propValue['loop'] : $propValue['loop'] - + 1, $propValue['start'])); } } } - $smartyAttr['value']['start'] = join('', $start_code); + $propValue['start'] = join('', $start_code); } - if ($smartyAttr['type']['start'] != 0) { - $smartyAttr['initLocal']['start'] = $smartyAttr['value']['start']; - $smartyAttr['value']['start'] = "{$local}start"; + if ($propType['start'] != 0) { + $initLocal['start'] = $propValue['start']; + $propValue['start'] = "{$local}start"; } - $smartyAttr['initFor']['index'] = "{$sectionVar}['index'] = {$smartyAttr['value']['start']}"; + $initFor['index'] = "{$sectionVar}['index'] = {$propValue['start']}"; if (!isset($_attr['start']) && !isset($_attr['step']) && !isset($_attr['max'])) { - $smartyAttr['value']['total'] = $smartyAttr['value']['loop']; - $smartyAttr['type']['total'] = $smartyAttr['type']['loop']; + $propValue['total'] = $propValue['loop']; + $propType['total'] = $propType['loop']; } else { - $smartyAttr['type']['total'] = $smartyAttr['type']['start'] + $smartyAttr['type']['loop'] + - $smartyAttr['type']['step'] + $smartyAttr['type']['max']; - if ($smartyAttr['type']['total'] == 0) { - $smartyAttr['value']['total'] = min(ceil(($smartyAttr['value']['step'] > - 0 ? $smartyAttr['value']['loop'] - - $smartyAttr['value']['start'] : $smartyAttr['value']['start'] + - 1) / - abs($smartyAttr['value']['step'])), $smartyAttr['value']['max']); + $propType['total'] = $propType['start'] + $propType['loop'] + $propType['step'] + $propType['max']; + if ($propType['total'] == 0) { + $propValue['total'] = min(ceil(($propValue['step'] > 0 ? $propValue['loop'] - + $propValue['start'] : $propValue['start'] + 1) / + abs($propValue['step'])), $propValue['max']); } else { - $total_code = array(1 => 'min(', 2 => 'ceil(', 3 => '(', 4 => "{$smartyAttr['value']['step']} > 0 ? ", - 5 => $smartyAttr['value']['loop'], 6 => ' - ', 7 => $smartyAttr['value']['start'], - 8 => ' : ', 9 => $smartyAttr['value']['start'], 10 => '+ 1', 11 => ')', 12 => '/ ', - 13 => 'abs(', 14 => $smartyAttr['value']['step'], 15 => ')', 16 => ')', - 17 => ", {$smartyAttr['value']['max']})",); - if (!isset($smartyAttr['value']['max'])) { + $total_code = array(1 => 'min(', 2 => 'ceil(', 3 => '(', 4 => "{$propValue['step']} > 0 ? ", + 5 => $propValue['loop'], 6 => ' - ', 7 => $propValue['start'], 8 => ' : ', + 9 => $propValue['start'], 10 => '+ 1', 11 => ')', 12 => '/ ', 13 => 'abs(', + 14 => $propValue['step'], 15 => ')', 16 => ')', 17 => ", {$propValue['max']})",); + if (!isset($propValue['max'])) { $total_code[1] = $total_code[17] = ''; } - if ($smartyAttr['type']['loop'] + $smartyAttr['type']['start'] == 0) { - $total_code[5] = $smartyAttr['value']['loop'] - $smartyAttr['value']['start']; + if ($propType['loop'] + $propType['start'] == 0) { + $total_code[5] = $propValue['loop'] - $propValue['start']; $total_code[6] = $total_code[7] = ''; } - if ($smartyAttr['type']['start'] == 0) { - $total_code[9] = $smartyAttr['value']['start'] + 1; + if ($propType['start'] == 0) { + $total_code[9] = $propValue['start'] + 1; $total_code[10] = ''; } - if ($smartyAttr['type']['step'] == 0) { + if ($propType['step'] == 0) { $total_code[13] = $total_code[15] = ''; - if ($smartyAttr['value']['step'] == 1 || $smartyAttr['value']['step'] == - 1) { + if ($propValue['step'] == 1 || $propValue['step'] == - 1) { $total_code[2] = $total_code[12] = $total_code[14] = $total_code[16] = ''; - } elseif ($smartyAttr['value']['step'] < 0) { - $total_code[14] = - $smartyAttr['value']['step']; + } elseif ($propValue['step'] < 0) { + $total_code[14] = - $propValue['step']; } $total_code[4] = ''; - if ($smartyAttr['value']['step'] > 0) { + if ($propValue['step'] > 0) { $total_code[8] = $total_code[9] = $total_code[10] = ''; } else { $total_code[5] = $total_code[6] = $total_code[7] = $total_code[8] = ''; } } - $smartyAttr['value']['total'] = join('', $total_code); + $propValue['total'] = join('', $total_code); } } - if (isset($smartyAttr['isSmarty']['total'])) { - $smartyAttr['initSmarty']['total'] = "'total' => {$smartyAttr['value']['total']}"; - if ($smartyAttr['type']['total'] > 0) { - $smartyAttr['value']['total'] = "{$sectionVar}['total']"; + if (isset($namedAttr['total'])) { + $initNamedProperty['total'] = "'total' => {$propValue['total']}"; + if ($propType['total'] > 0) { + $propValue['total'] = "{$sectionVar}['total']"; } - } elseif ($smartyAttr['type']['total'] > 0) { - $smartyAttr['initLocal']['total'] = $smartyAttr['value']['total']; - $smartyAttr['value']['total'] = "{$local}total"; + } elseif ($propType['total'] > 0) { + $initLocal['total'] = $propValue['total']; + $propValue['total'] = "{$local}total"; } - $smartyAttr['cmpFor']['iteration'] = "{$smartyAttr['value']['iteration']} <= {$smartyAttr['value']['total']}"; + $cmpFor['iteration'] = "{$propValue['iteration']} <= {$propValue['total']}"; - foreach ($smartyAttr['initLocal'] as $key => $code) { + foreach ($initLocal as $key => $code) { $output .= "{$local}{$key} = {$code};\n"; } - $_vars = 'array(' . join(', ', $smartyAttr['initSmarty']) . ')'; + $_vars = 'array(' . join(', ', $initNamedProperty) . ')'; $output .= "\$_smarty_tpl->tpl_vars['__section_{$attributes['name']}'] = new Smarty_Variable({$_vars});\n"; - $cond_code = "{$smartyAttr['value']['total']} != 0"; - if ($smartyAttr['type']['total'] == 0) { - if ($smartyAttr['value']['total'] == 0) { + $cond_code = "{$propValue['total']} != 0"; + if ($propType['total'] == 0) { + if ($propValue['total'] == 0) { $cond_code = 'false'; } else { $cond_code = 'true'; } } - if ($smartyAttr['type']['show'] > 0) { - $output .= "{$local}show = {$smartyAttr['value']['show']} ? {$cond_code} : false;\n"; + if ($propType['show'] > 0) { + $output .= "{$local}show = {$propValue['show']} ? {$cond_code} : false;\n"; $output .= "if ({$local}show) {\n"; - } elseif ($smartyAttr['value']['show'] == 'true') { + } elseif ($propValue['show'] == 'true') { $output .= "if ({$cond_code}) {\n"; } else { $output .= "if (false) {\n"; } - $jinit = join(', ', $smartyAttr['initFor']); - $jcmp = join(', ', $smartyAttr['cmpFor']); - $jinc = join(', ', $smartyAttr['incFor']); + $jinit = join(', ', $initFor); + $jcmp = join(', ', $cmpFor); + $jinc = join(', ', $incFor); $output .= "for ({$jinit}; {$jcmp}; {$jinc}){\n"; - if (isset($smartyAttr['rownum'])) { - $output .= "{$sectionVar}['rownum'] = {$smartyAttr['value']['iteration']};\n"; + if (isset($namedAttr['rownum'])) { + $output .= "{$sectionVar}['rownum'] = {$propValue['iteration']};\n"; } - if (isset($smartyAttr['index_prev'])) { - $output .= "{$sectionVar}['index_prev'] = {$smartyAttr['value']['index']} - {$smartyAttr['value']['step']};\n"; + if (isset($namedAttr['index_prev'])) { + $output .= "{$sectionVar}['index_prev'] = {$propValue['index']} - {$propValue['step']};\n"; } - if (isset($smartyAttr['index_next'])) { - $output .= "{$sectionVar}['index_next'] = {$smartyAttr['value']['index']} + {$smartyAttr['value']['step']};\n"; + if (isset($namedAttr['index_next'])) { + $output .= "{$sectionVar}['index_next'] = {$propValue['index']} + {$propValue['step']};\n"; } - if (isset($smartyAttr['first'])) { - $output .= "{$sectionVar}['first'] = ({$smartyAttr['value']['iteration']} == 1);\n"; + if (isset($namedAttr['first'])) { + $output .= "{$sectionVar}['first'] = ({$propValue['iteration']} == 1);\n"; } - if (isset($smartyAttr['last'])) { - $output .= "{$sectionVar}['last'] = ({$smartyAttr['value']['iteration']} == {$smartyAttr['value']['total']});\n"; + if (isset($namedAttr['last'])) { + $output .= "{$sectionVar}['last'] = ({$propValue['iteration']} == {$propValue['total']});\n"; } $output .= "?>"; @@ -500,8 +469,8 @@ class Smarty_Internal_Compile_Sectionclose extends Smarty_Internal_CompileBase } else { $output .= "}\n}\n"; } - $output .= "if (\$section_{$attributes['no']}_s_name) {\n"; - $output .= "\$_smarty_tpl->tpl_vars['__section_{$attributes['name']}'] = \$section_{$attributes['no']}_s_name;\n"; + $output .= "if (\$section_{$attributes['no']}_saved) {\n"; + $output .= "\$_smarty_tpl->tpl_vars['__section_{$attributes['name']}'] = \$section_{$attributes['no']}_saved;\n"; $output .= "}\n"; $output .= "?>";