diff options
Diffstat (limited to 'include/smarty/libs/sysplugins/smarty_internal_compile_block.php')
-rw-r--r-- | include/smarty/libs/sysplugins/smarty_internal_compile_block.php | 440 |
1 files changed, 225 insertions, 215 deletions
diff --git a/include/smarty/libs/sysplugins/smarty_internal_compile_block.php b/include/smarty/libs/sysplugins/smarty_internal_compile_block.php index f760e551d..52a541ebd 100644 --- a/include/smarty/libs/sysplugins/smarty_internal_compile_block.php +++ b/include/smarty/libs/sysplugins/smarty_internal_compile_block.php @@ -1,23 +1,20 @@ <?php - -/** - * Smarty Internal Plugin Compile Block +/* + * This file is part of Smarty. * - * Compiles the {block}{/block} tags + * (c) 2015 Uwe Tews * - * @package Smarty - * @subpackage Compiler - * @author Uwe Tews + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ /** * Smarty Internal Plugin Compile Block Class * - * @package Smarty - * @subpackage Compiler + * @author Uwe Tews <uwe.tews@googlemail.com> */ -class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase { - +class Smarty_Internal_Compile_Block extends Smarty_Internal_Compile_Shared_Inheritance +{ /** * Attribute definition: Overwrites base class. * @@ -32,7 +29,7 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase { * @var array * @see Smarty_Internal_CompileBase */ - public $shorttag_order = array('name', 'hide'); + public $shorttag_order = array('name'); /** * Attribute definition: Overwrites base class. @@ -40,243 +37,256 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase { * @var array * @see Smarty_Internal_CompileBase */ - public $optional_attributes = array('hide'); + public $option_flags = array('hide', 'nocache'); /** - * Compiles code for the {block} tag + * Attribute definition: Overwrites base class. * - * @param array $args array with attributes from parser - * @param object $compiler compiler object - * @return boolean true + * @var array + * @see Smarty_Internal_CompileBase */ - public function compile($args, $compiler) { - // check and get attributes - $_attr = $this->getAttributes($compiler, $args); - $save = array($_attr, $compiler->parser->current_buffer, $compiler->nocache, $compiler->smarty->merge_compiled_includes, $compiler->merged_templates, $compiler->smarty->merged_templates_func, $compiler->template->properties, $compiler->template->has_nocache_code); - $this->openTag($compiler, 'block', $save); - if ($_attr['nocache'] == true) { - $compiler->nocache = true; - } - // set flag for {block} tag - $compiler->inheritance = true; - // must merge includes - $compiler->smarty->merge_compiled_includes = true; + public $optional_attributes = array('assign'); - $compiler->parser->current_buffer = new _smarty_template_buffer($compiler->parser); - $compiler->has_code = false; - return true; - } + /** + * nesting level of block tags + * + * @var int + */ + public static $blockTagNestingLevel = 0; /** - * Save or replace child block source by block name during parsing + * Saved compiler object * - * @param string $block_content block source content - * @param string $block_tag opening block tag - * @param object $template template object - * @param string $filepath filepath of template source + * @var Smarty_Internal_TemplateCompilerBase */ - public static function saveBlockData($block_content, $block_tag, $template, $filepath) { - $_rdl = preg_quote($template->smarty->right_delimiter); - $_ldl = preg_quote($template->smarty->left_delimiter); - if (!$template->smarty->auto_literal) { - $al = '\s*'; - } else { - $al = ''; - } - if (0 == preg_match("!({$_ldl}{$al}block\s+)(name=)?(\w+|'.*'|\".*\")(\s*?)?((append|prepend|nocache)?(\s*)?(hide)?)?(\s*{$_rdl})!", $block_tag, $_match)) { - $error_text = 'Syntax Error in template "' . $template->source->filepath . '" "' . htmlspecialchars($block_tag) . '" illegal options'; - throw new SmartyCompilerException($error_text); - } else { - $_name = trim($_match[3], '\'"'); - if ($_match[8] != 'hide' || isset($template->block_data[$_name])) { // replace {$smarty.block.child} - // get nested block tags - if (0 != preg_match_all("!({$_ldl}{$al}block\s+)(name=)?(\w+|'.*'|\".*\")([\s\S]*?)(hide)?(\s*{$_rdl})([\s\S]*?)(.*)?({$_ldl}{$al}/block\s*{$_rdl})!", $block_content, $_match2)) { - foreach ($_match2[3] as $key => $name) { - // get it's replacement - $_name2 = trim($name, '\'"'); - if ($_match2[5][$key] != 'hide' || isset($template->block_data[$_name2])) { - if (isset($template->block_data[$_name2])) { - $replacement = $template->block_data[$_name2]['source']; - } else { - $replacement = ''; - } - // replace {$smarty.block.child} tag - if (preg_match("!{$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl}!",$_match2[7][$key])) { - $replacement = preg_replace("!({$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl})!", $replacement, $_match2[7][$key]); - $block_content = preg_replace("!(({$_ldl}{$al}block)(.*)?{$name}(.*)?({$_rdl}[\s\S]*?{$_ldl}{$al}/block\s*{$_rdl}))!", $replacement, $block_content); - } - if (preg_match("!{$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl}!",$_match2[8][$key])) { - $replacement = preg_replace("!{$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl}!", $replacement, $_match2[8][$key]); - $block_content = preg_replace("!(({$_ldl}{$al}block)(.*)?{$name}(.*)?({$_rdl})(.*)?({$_ldl}{$al}/block\s*{$_rdl}))!", $replacement, $block_content); - } - } else { - // remove hidden blocks - $block_content = preg_replace("!(({$_ldl}{$al}block)(.*)?{$name}(.*)?({$_rdl}[\s\S]*?{$_ldl}{$al}/block\s*{$_rdl}))!", '', $block_content); - } - } - } - // do we have not nested {$smart.block.child} - if (0 != preg_match("!({$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl})!", $block_content, $_match2)) { - // get child replacement for this block - if (isset($template->block_data[$_name])) { - $replacement = $template->block_data[$_name]['source']; - unset($template->block_data[$_name]); - } else { - $replacement = ''; - } - $block_content = preg_replace("!({$_ldl}{$al}\\\$smarty\.block\.child\s*{$_rdl})!", $replacement, $block_content); - } - if (isset($template->block_data[$_name])) { - if (strpos($template->block_data[$_name]['source'], '%%%%SMARTY_PARENT%%%%') !== false) { - $template->block_data[$_name]['source'] = - str_replace('%%%%SMARTY_PARENT%%%%', $block_content, $template->block_data[$_name]['source']); - } elseif ($template->block_data[$_name]['mode'] == 'prepend') { - $template->block_data[$_name]['source'] .= $block_content; - } elseif ($template->block_data[$_name]['mode'] == 'append') { - $template->block_data[$_name]['source'] = $block_content . $template->block_data[$_name]['source']; - } - } else { - $template->block_data[$_name]['source'] = $block_content; - $template->block_data[$_name]['file'] = $filepath; - } - if ($_match[6] == 'append') { - $template->block_data[$_name]['mode'] = 'append'; - } elseif ($_match[6] == 'prepend') { - $template->block_data[$_name]['mode'] = 'prepend'; - } else { - $template->block_data[$_name]['mode'] = 'replace'; - } - } - } - } + public $compiler = null; /** - * Compile saved child block source + * Compiles code for the {block} tag + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter * - * @param object $compiler compiler object - * @param string $_name optional name of child block - * @return string compiled code of schild block + * @return bool true */ - public static function compileChildBlock($compiler, $_name = null) { - $_output = ''; - // if called by {$smarty.block.child} we must search the name of enclosing {block} - if ($_name == null) { - $stack_count = count($compiler->_tag_stack); - while (--$stack_count >= 0) { - if ($compiler->_tag_stack[$stack_count][0] == 'block') { - $_name = trim($compiler->_tag_stack[$stack_count][1][0]['name'], "'\""); - break; - } - } - // flag that child is already compile by {$smarty.block.child} inclusion - $compiler->template->block_data[$_name]['compiled'] = true; - } - if ($_name == null) { - $compiler->trigger_template_error('{$smarty.block.child} used out of context', $compiler->lex->taglineno); + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + if (!isset($compiler->_cache['blockNesting'])) { + $compiler->_cache['blockNesting'] = 0; } - // undefined child? - if (!isset($compiler->template->block_data[$_name]['source'])) { - return ''; - } - $_tpl = new Smarty_Internal_template('string:' . $compiler->template->block_data[$_name]['source'], $compiler->smarty, $compiler->template, $compiler->template->cache_id, - $compiler->template->compile_id = null, $compiler->template->caching, $compiler->template->cache_lifetime); - $_tpl->variable_filters = $compiler->template->variable_filters; - $_tpl->properties['nocache_hash'] = $compiler->template->properties['nocache_hash']; - $_tpl->source->filepath = $compiler->template->block_data[$_name]['file']; - $_tpl->allow_relative_path = true; - if ($compiler->nocache) { - $_tpl->compiler->forceNocache = 2; + if ($compiler->_cache['blockNesting'] == 0) { + // make sure that inheritance gets initialized in template code + $this->registerInit($compiler); + $this->option_flags = array('hide', 'nocache', 'append', 'prepend'); } else { - $_tpl->compiler->forceNocache = 1; + $this->option_flags = array('hide', 'nocache'); } - $_tpl->compiler->suppressHeader = true; - $_tpl->compiler->suppressTemplatePropertyHeader = true; - $_tpl->compiler->suppressMergedTemplates = true; - if (strpos($compiler->template->block_data[$_name]['source'], '%%%%SMARTY_PARENT%%%%') !== false) { - $_output = str_replace('%%%%SMARTY_PARENT%%%%', $compiler->parser->current_buffer->to_smarty_php(), $_tpl->compiler->compileTemplate($_tpl)); - } elseif ($compiler->template->block_data[$_name]['mode'] == 'prepend') { - $_output = $_tpl->compiler->compileTemplate($_tpl) . $compiler->parser->current_buffer->to_smarty_php(); - } elseif ($compiler->template->block_data[$_name]['mode'] == 'append') { - $_output = $compiler->parser->current_buffer->to_smarty_php() . $_tpl->compiler->compileTemplate($_tpl); - } elseif (!empty($compiler->template->block_data[$_name])) { - $_output = $_tpl->compiler->compileTemplate($_tpl); + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + $compiler->_cache['blockNesting'] ++; + $compiler->_cache['blockName'][$compiler->_cache['blockNesting']] = $_attr['name']; + $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][0] = 'block_' . preg_replace('![^\w]+!', '_', uniqid(rand(), true)); + $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][1] = false; + $this->openTag($compiler, 'block', array($_attr, $compiler->nocache, $compiler->parser->current_buffer, + $compiler->template->compiled->has_nocache_code, + $compiler->template->caching)); + // must whole block be nocache ? + if ($compiler->tag_nocache) { + $i = 0; } - $compiler->template->properties['file_dependency'] = array_merge($compiler->template->properties['file_dependency'], $_tpl->properties['file_dependency']); - $compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $_tpl->properties['function']); - $compiler->merged_templates = array_merge($compiler->merged_templates, $_tpl->compiler->merged_templates); - $compiler->template->variable_filters = $_tpl->variable_filters; - if ($_tpl->has_nocache_code) { - $compiler->template->has_nocache_code = true; + $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; + // $compiler->suppressNocacheProcessing = true; + if ($_attr['nocache'] === true) { + //$compiler->trigger_template_error('nocache option not allowed', $compiler->parser->lex->taglineno); } - foreach ($_tpl->required_plugins as $key => $tmp1) { - if ($compiler->nocache && $compiler->template->caching) { - $code = 'nocache'; - } else { - $code = $key; - } - foreach ($tmp1 as $name => $tmp) { - foreach ($tmp as $type => $data) { - $compiler->template->required_plugins[$code][$name][$type] = $data; - } - } + $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); + $compiler->template->compiled->has_nocache_code = false; + $compiler->suppressNocacheProcessing = true; + } + + /** + * Compile saved child block source + * + * @param \Smarty_Internal_TemplateCompilerBase compiler object + * @param string $_name optional name of child block + * + * @return string compiled code of child block + */ + static function compileChildBlock(Smarty_Internal_TemplateCompilerBase $compiler, $_name = null) + { + if (!isset($compiler->_cache['blockNesting'])) { + $compiler->trigger_template_error(' tag {$smarty.block.child} used outside {block} tags ', + $compiler->parser->lex->taglineno); } - unset($_tpl); - return $_output; + $compiler->has_code = true; + $compiler->suppressNocacheProcessing = true; + $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][1] = true; + $output = "<?php \n\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 2, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, null, \$_blockParentStack);\n?>\n"; + return $output; } + /** + * Compile $smarty.block.parent + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param string $_name optional name of child block + * + * @return string compiled code of child block + */ + static function compileParentBlock(Smarty_Internal_TemplateCompilerBase $compiler, $_name = null) + { + if (!isset($compiler->_cache['blockNesting'])) { + $compiler->trigger_template_error(' tag {$smarty.block.parent} used outside {block} tags ', + $compiler->parser->lex->taglineno); + } + $compiler->suppressNocacheProcessing = true; + $compiler->has_code = true; + $output = "<?php \n\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 3, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, null, \$_blockParentStack);\n?>\n"; + return $output; + } } /** * Smarty Internal Plugin Compile BlockClose Class * - * @package Smarty - * @subpackage Compiler */ -class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_CompileBase { - +class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_Inheritance +{ /** * Compiles code for the {/block} tag * - * @param array $args array with attributes from parser - * @param object $compiler compiler object - * @return string compiled code + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return bool true */ - public function compile($args, $compiler) { - $compiler->has_code = true; - // check and get attributes - $_attr = $this->getAttributes($compiler, $args); - $saved_data = $this->closeTag($compiler, array('block')); - $_name = trim($saved_data[0]['name'], "\"'"); - if (isset($compiler->template->block_data[$_name]) && !isset($compiler->template->block_data[$_name]['compiled'])) { - // restore to status before {block} tag as new subtemplate code of parent {block} is not needed - // TODO: Below code was disabled in 3.1.8 because of problems with {include} in nested {block} tags in child templates - // combined with append/prepend or $smarty.block.parent - // For later versions it should be checked under which conditions it could run for optimisation - // - //$compiler->merged_templates = $saved_data[4]; - //$compiler->smarty->merged_templates_func = $saved_data[5]; - //$compiler->template->properties = $saved_data[6]; - //$compiler->template->has_nocache_code = $saved_data[7]; - $_output = Smarty_Internal_Compile_Block::compileChildBlock($compiler, $_name); - } else { - if (isset($saved_data[0]['hide']) && !isset($compiler->template->block_data[$_name]['source'])) { - $_output = ''; - } else { - $_output = $compiler->parser->current_buffer->to_smarty_php(); + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) + { + list($_attr, $_nocache, $_buffer, $_has_nocache_code, $_caching) = $this->closeTag($compiler, array('block')); + // init block parameter + $_block = $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']]; + unset($compiler->_cache['blockParams'][$compiler->_cache['blockNesting']]); + $_block[2] = $_block[3] = 0; + $_name = trim($_attr['name'], "'\""); + $_assign = isset($_attr['assign']) ? $_attr['assign'] : null; + unset($_attr['assign'], $_attr['name']); + foreach ($_attr as $name => $stat) { + if ((is_bool($stat) && $stat !== false) || (!is_bool($stat) && $stat != 'false')) { + $_block[$name] = is_string($stat) ? trim($stat, "'\"") : $stat; } - unset($compiler->template->block_data[$_name]['compiled']); } - // reset flags - $compiler->parser->current_buffer = $saved_data[1]; - $compiler->nocache = $saved_data[2]; - $compiler->smarty->merge_compiled_includes = $saved_data[3]; - // reset flag for {block} tag - $compiler->inheritance = false; - // $_output content has already nocache code processed + $_funcName = $_block[0]; + // get compiled block code + $_functionCode = $compiler->parser->current_buffer; + // setup buffer for template function code + $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); + + if ($compiler->template->compiled->has_nocache_code) { + // $compiler->parent_compiler->template->tpl_function[$_name]['call_name_caching'] = $_funcNameCaching; + $_block[6] = $_funcNameCaching = $_funcName . '_nocache'; + $output = "<?php\n"; + $output .= "/* {block '{$_name}'} {$compiler->template->source->type}:{$compiler->template->source->name} */\n"; + $output .= "function {$_funcNameCaching} (\$_smarty_tpl, \$_blockParentStack) {\n"; + $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n"; + $output .= "\$_smarty_tpl->cached->hashes['{$compiler->template->compiled->nocache_hash}'] = true;\n"; + if (isset($_assign)) { + $output .= "ob_start();\n"; + } + $output .= "?>\n"; + $compiler->parser->current_buffer->append_subtree($compiler->parser, + new Smarty_Internal_ParseTree_Tag($compiler->parser, + $output)); + $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); + $output = "<?php\n"; + if (isset($_assign)) { + $output .= "\$_smarty_tpl->tpl_vars[{$_assign}] = new Smarty_Variable(ob_get_clean());\n"; + } + $output .= "/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n"; + $output .= "}\n"; + $output .= "/* {/block '{$_name}'} */\n\n"; + $output .= "?>\n"; + $compiler->parser->current_buffer->append_subtree($compiler->parser, + new Smarty_Internal_ParseTree_Tag($compiler->parser, + $output)); + $compiler->blockOrFunctionCode .= $f = $compiler->parser->current_buffer->to_smarty_php($compiler->parser); + $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); + $this->compiler = $compiler; + $_functionCode = new Smarty_Internal_ParseTree_Tag($compiler->parser, + preg_replace_callback("/((<\?php )?echo '\/\*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/([\S\s]*?)\/\*\/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/", + array($this, 'removeNocache'), + $_functionCode->to_smarty_php($compiler->parser))); + $this->compiler = null; + } + $output = "<?php\n"; + $output .= "/* {block '{$_name}'} {$compiler->template->source->type}:{$compiler->template->source->name} */\n"; + $output .= "function {$_funcName}(\$_smarty_tpl, \$_blockParentStack) {\n"; + if (isset($_assign)) { + $output .= "ob_start();\n"; + } + $output .= "?>\n"; + $compiler->parser->current_buffer->append_subtree($compiler->parser, + new Smarty_Internal_ParseTree_Tag($compiler->parser, + $output)); + $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); + $output = "<?php\n"; + if (isset($_assign)) { + $output .= "\$_smarty_tpl->tpl_vars[{$_assign}] = new Smarty_Variable(ob_get_clean());\n"; + } + $output .= "}\n"; + $output .= "/* {/block '{$_name}'} */\n\n"; + $output .= "?>\n"; + $compiler->parser->current_buffer->append_subtree($compiler->parser, + new Smarty_Internal_ParseTree_Tag($compiler->parser, + $output)); + $compiler->blockOrFunctionCode .= $compiler->parser->current_buffer->to_smarty_php($compiler->parser); + // nocache plugins must be copied + if (!empty($compiler->template->compiled->required_plugins['nocache'])) { + foreach ($compiler->template->compiled->required_plugins['nocache'] as $plugin => $tmp) { + foreach ($tmp as $type => $data) { + $compiler->parent_compiler->template->compiled->required_plugins['compiled'][$plugin][$type] = + $data; + } + } + } + + + // restore old status + $compiler->template->compiled->has_nocache_code = $_has_nocache_code; + $compiler->tag_nocache = $compiler->nocache; + $compiler->nocache = $_nocache; + $compiler->parser->current_buffer = $_buffer; + $output = "<?php \n"; + if ($compiler->_cache['blockNesting'] == 1) { + $output .= "\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 0, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, " . + var_export($_block, true) . ");\n"; + } else { + $output .= "\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 0, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, " . + var_export($_block, true) . ", \$_blockParentStack);\n"; + + } + $output .= "?>\n"; + $compiler->_cache['blockNesting'] --; + if ($compiler->_cache['blockNesting'] == 0) { + unset($compiler->_cache['blockNesting']); + } + $compiler->has_code = true; $compiler->suppressNocacheProcessing = true; - return $_output; + return $output; } + /** + * @param $match + * + * @return mixed + */ + function removeNocache($match) + { + $code = + preg_replace("/((<\?php )?echo '\/\*%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/)|(\/\*\/%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/", + '', $match[0]); + $code = str_replace(array('\\\'', '\\\\\''), array('\'', '\\\''), $code); + return $code; + } } - -?>
\ No newline at end of file |