diff options
Diffstat (limited to 'library/Smarty/libs/sysplugins/smarty_internal_compile_block.php')
-rw-r--r-- | library/Smarty/libs/sysplugins/smarty_internal_compile_block.php | 433 |
1 files changed, 300 insertions, 133 deletions
diff --git a/library/Smarty/libs/sysplugins/smarty_internal_compile_block.php b/library/Smarty/libs/sysplugins/smarty_internal_compile_block.php index 03abf493e..8c2fb975f 100644 --- a/library/Smarty/libs/sysplugins/smarty_internal_compile_block.php +++ b/library/Smarty/libs/sysplugins/smarty_internal_compile_block.php @@ -2,22 +2,23 @@ /** * Smarty Internal Plugin Compile Block - * * Compiles the {block}{/block} tags * - * @package Smarty + * @package Smarty * @subpackage Compiler - * @author Uwe Tews + * @author Uwe Tews */ /** * Smarty Internal Plugin Compile Block Class * - * @package Smarty + * @package Smarty * @subpackage Compiler */ -class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase { +class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase +{ + const parent = '____SMARTY_BLOCK_PARENT____'; /** * Attribute definition: Overwrites base class. * @@ -32,7 +33,15 @@ 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. + * + * @var array + * @see Smarty_Internal_CompileBase + */ + public $option_flags = array('hide', 'append', 'prepend', 'nocache'); /** * Attribute definition: Overwrites base class. @@ -40,161 +49,140 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase { * @var array * @see Smarty_Internal_CompileBase */ - public $optional_attributes = array('hide'); + public $optional_attributes = array('internal_file', 'internal_uid', 'internal_line'); + /** + * nested child block names + * + * @var array + */ + public static $nested_block_names = array(); + + /** + * child block source buffer + * + * @var array + */ + public static $block_data = array(); /** * Compiles code for the {block} tag * * @param array $args array with attributes from parser * @param object $compiler compiler object + * * @return boolean true */ - public function compile($args, $compiler) { + 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); + $_name = trim($_attr['name'], "\"'"); + + // existing child must override parent settings + if (isset($compiler->template->block_data[$_name]) && $compiler->template->block_data[$_name]['mode'] == 'replace') { + $_attr['append'] = false; + $_attr['prepend'] = false; + } + + // check if we process an inheritance child template + if ($compiler->inheritance_child) { + array_unshift(self::$nested_block_names, $_name); + // build {block} for child block + self::$block_data[$_name]['source'] = + "{$compiler->smarty->left_delimiter}private_child_block name={$_attr['name']} file='{$compiler->template->source->filepath}' type='{$compiler->template->source->type}' resource='{$compiler->template->template_resource}'" . + " uid='{$compiler->template->source->uid}' line={$compiler->lex->line}"; + if ($_attr['nocache']) { + self::$block_data[$_name]['source'] .= ' nocache'; + } + self::$block_data[$_name]['source'] .= $compiler->smarty->right_delimiter; + + $save = array($_attr, $compiler->inheritance); + $this->openTag($compiler, 'block', $save); + // set flag for {block} tag + $compiler->inheritance = true; + $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK); + $compiler->has_code = false; + return; + } + // must merge includes if ($_attr['nocache'] == true) { - $compiler->nocache = true; + $compiler->tag_nocache = true; } - // set flag for {block} tag + $save = array($_attr, $compiler->inheritance, $compiler->parser->current_buffer, $compiler->nocache); + $this->openTag($compiler, 'block', $save); $compiler->inheritance = true; - // must merge includes - $compiler->smarty->merge_compiled_includes = true; + $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; $compiler->parser->current_buffer = new _smarty_template_buffer($compiler->parser); $compiler->has_code = false; + return true; } /** - * Save or replace child block source by block name during parsing + * Compile saved child block source * - * @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 + * @param object $compiler compiler object + * @param string $_name optional name of child block + * + * @return string compiled code of child block */ - 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} - // do we have {$smart.block.child} in nested {block} tags? - if (0 != preg_match_all("!({$_ldl}{$al}block\s+)(name=)?(\w+|'.*'|\".*\")([\s\S]*?)(hide)?(\s*{$_rdl})([\s\S]*?)({$_ldl}{$al}\\\$smarty\.block\.child{$_rdl})([\s\S]*?{$_ldl}{$al}/block{$_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 - $search = array("%({$_ldl}{$al}block[\s\S]*?{$name}[\s\S]*?{$_rdl})([\s\S]*?)({$_ldl}{$al}\\\$smarty\.block\.child{$_rdl})([\s\S]*?)({$_ldl}{$al}/block{$_rdl})%", "/§§§child§§§/"); - $replace = array('\2§§§child§§§\4', $replacement); - $block_content = preg_replace($search, $replace, $block_content); - } else { - // remove hidden blocks - $block_content = preg_replace("%({$_ldl}{$al}block[\s\S]*?{$name}[\s\S]*?{$_rdl}[\s\S]*?{$_ldl}{$al}/block{$_rdl})%", '', $block_content); - } - } - } - // do we have not nested {$smart.block.child} - if (0 != preg_match("/({$_ldl}{$al}\\\$smarty\.block\.child{$_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{$_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'; - } + static function compileChildBlock($compiler, $_name = null) + { + if ($compiler->inheritance_child) { + $name1 = Smarty_Internal_Compile_Block::$nested_block_names[0]; + if (isset($compiler->template->block_data[$name1])) { + // replace inner block name with generic + Smarty_Internal_Compile_Block::$block_data[$name1]['source'] .= $compiler->template->block_data[$name1]['source']; + Smarty_Internal_Compile_Block::$block_data[$name1]['child'] = true; } + $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK); + $compiler->has_code = false; + return; } - } - - /** - * Compile saved child block source - * - * @param object $compiler compiler object - * @param string $_name optional name of child block - * @return string compiled code of schild block - */ - 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'], "'\""); + $_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); + $compiler->trigger_template_error(' tag {$smarty.block.child} used outside {block} tags ', $compiler->lex->taglineno); } // undefined child? if (!isset($compiler->template->block_data[$_name]['source'])) { + $compiler->popTrace(); return ''; } + // flag that child is already compile by {$smarty.block.child} inclusion + $compiler->template->block_data[$_name]['compiled'] = true; $_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); + $compiler->template->compile_id, $compiler->template->caching, $compiler->template->cache_lifetime); + if ($compiler->smarty->debugging) { + Smarty_Internal_Debug::ignore($_tpl); + } + $_tpl->tpl_vars = $compiler->template->tpl_vars; $_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; - } else { - $_tpl->compiler->forceNocache = 1; - } + $_tpl->compiler->inheritance = true; $_tpl->compiler->suppressHeader = true; + $_tpl->compiler->suppressFilter = 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)); + $nocache = $compiler->nocache || $compiler->tag_nocache; + if (strpos($compiler->template->block_data[$_name]['source'], self::parent) !== false) { + $_output = str_replace(self::parent, $compiler->parser->current_buffer->to_smarty_php(), $_tpl->compiler->compileTemplate($_tpl, $nocache)); } elseif ($compiler->template->block_data[$_name]['mode'] == 'prepend') { - $_output = $_tpl->compiler->compileTemplate($_tpl) . $compiler->parser->current_buffer->to_smarty_php(); + $_output = $_tpl->compiler->compileTemplate($_tpl, $nocache) . $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); + $_output = $compiler->parser->current_buffer->to_smarty_php() . $_tpl->compiler->compileTemplate($_tpl, $nocache); } elseif (!empty($compiler->template->block_data[$_name])) { - $_output = $_tpl->compiler->compileTemplate($_tpl); + $_output = $_tpl->compiler->compileTemplate($_tpl, $nocache); } $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']); @@ -216,62 +204,241 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase { } } unset($_tpl); + $compiler->has_code = true; return $_output; } + /** + * Compile $smarty.block.parent + * + * @param object $compiler compiler object + * @param string $_name optional name of child block + * + * @return string compiled code of child block + */ + static function compileParentBlock($compiler, $_name = null) + { + // if called by {$smarty.block.parent} 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; + } + } + } + if ($_name == null) { + $compiler->trigger_template_error(' tag {$smarty.block.parent} used outside {block} tags ', $compiler->lex->taglineno); + } + if (empty(Smarty_Internal_Compile_Block::$nested_block_names)) { + $compiler->trigger_template_error(' illegal {$smarty.block.parent} in parent template ', $compiler->lex->taglineno); + } + Smarty_Internal_Compile_Block::$block_data[Smarty_Internal_Compile_Block::$nested_block_names[0]]['source'] .= Smarty_Internal_Compile_Block::parent; + $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK); + $compiler->has_code = false; + return; + } + + /** + * Process block source + * + * @param $compiler + * @param string $source source text + * + */ + static function blockSource($compiler, $source) + { + Smarty_Internal_Compile_Block::$block_data[Smarty_Internal_Compile_Block::$nested_block_names[0]]['source'] .= $source; + } } /** * Smarty Internal Plugin Compile BlockClose Class * - * @package Smarty + * @package Smarty * @subpackage Compiler */ -class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_CompileBase { - +class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_CompileBase +{ /** * Compiles code for the {/block} tag * * @param array $args array with attributes from parser * @param object $compiler compiler object + * * @return string compiled code */ - public function compile($args, $compiler) { + 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'], "\"'"); + // reset flag for {block} tag + $compiler->inheritance = $saved_data[1]; + // check if we process an inheritance child template + if ($compiler->inheritance_child) { + $name1 = Smarty_Internal_Compile_Block::$nested_block_names[0]; + Smarty_Internal_Compile_Block::$block_data[$name1]['source'] .= "{$compiler->smarty->left_delimiter}/private_child_block{$compiler->smarty->right_delimiter}"; + array_shift(Smarty_Internal_Compile_Block::$nested_block_names); + if (!empty(Smarty_Internal_Compile_Block::$nested_block_names)) { + $name2 = Smarty_Internal_Compile_Block::$nested_block_names[0]; + if (isset($compiler->template->block_data[$name1]) || !$saved_data[0]['hide']) { + if (isset(Smarty_Internal_Compile_Block::$block_data[$name1]['child']) || !isset($compiler->template->block_data[$name1])) { + Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= Smarty_Internal_Compile_Block::$block_data[$name1]['source']; + } else { + if ($compiler->template->block_data[$name1]['mode'] == 'append') { + Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= Smarty_Internal_Compile_Block::$block_data[$name1]['source'] . $compiler->template->block_data[$name1]['source']; + } elseif ($compiler->template->block_data[$name1]['mode'] == 'prepend') { + Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= $compiler->template->block_data[$name1]['source'] . Smarty_Internal_Compile_Block::$block_data[$name1]['source']; + } else { + Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= $compiler->template->block_data[$name1]['source']; + } + } + } + unset(Smarty_Internal_Compile_Block::$block_data[$name1]); + $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK); + } else { + if (isset($compiler->template->block_data[$name1]) || !$saved_data[0]['hide']) { + if (isset($compiler->template->block_data[$name1]) && !isset(Smarty_Internal_Compile_Block::$block_data[$name1]['child'])) { + if (strpos($compiler->template->block_data[$name1]['source'], Smarty_Internal_Compile_Block::parent) !== false) { + $compiler->template->block_data[$name1]['source'] = + str_replace(Smarty_Internal_Compile_Block::parent, Smarty_Internal_Compile_Block::$block_data[$name1]['source'], $compiler->template->block_data[$name1]['source']); + } elseif ($compiler->template->block_data[$name1]['mode'] == 'prepend') { + $compiler->template->block_data[$name1]['source'] .= Smarty_Internal_Compile_Block::$block_data[$name1]['source']; + } elseif ($compiler->template->block_data[$name1]['mode'] == 'append') { + $compiler->template->block_data[$name1]['source'] = Smarty_Internal_Compile_Block::$block_data[$name1]['source'] . $compiler->template->block_data[$name1]['source']; + } + } else { + $compiler->template->block_data[$name1]['source'] = Smarty_Internal_Compile_Block::$block_data[$name1]['source']; + } + $compiler->template->block_data[$name1]['mode'] = 'replace'; + if ($saved_data[0]['append']) { + $compiler->template->block_data[$name1]['mode'] = 'append'; + } + if ($saved_data[0]['prepend']) { + $compiler->template->block_data[$name1]['mode'] = 'prepend'; + } + } + unset(Smarty_Internal_Compile_Block::$block_data[$name1]); + $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBODY); + } + $compiler->has_code = false; + return; + } 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'])) { + if ($saved_data[0]['hide'] && !isset($compiler->template->block_data[$_name]['source'])) { $_output = ''; } else { $_output = $compiler->parser->current_buffer->to_smarty_php(); } - unset($compiler->template->block_data[$_name]['compiled']); } + 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; + $compiler->parser->current_buffer = $saved_data[2]; + if ($compiler->nocache) { + $compiler->tag_nocache = true; + } + $compiler->nocache = $saved_data[3]; // $_output content has already nocache code processed $compiler->suppressNocacheProcessing = true; + return $_output; } +} + +/** + * Smarty Internal Plugin Compile Child Block Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Private_Child_Block extends Smarty_Internal_CompileBase +{ + + /** + * Attribute definition: Overwrites base class. + * + * @var array + * @see Smarty_Internal_CompileBase + */ + public $required_attributes = array('name', 'file', 'uid', 'line', 'type', 'resource'); + /** + * Compiles code for the {private_child_block} tag + * + * @param array $args array with attributes from parser + * @param object $compiler compiler object + * + * @return boolean true + */ + public function compile($args, $compiler) + { + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + + // update template with original template resource of {block} + if (trim($_attr['type'], "'") == 'file') { + $compiler->template->template_resource = 'file:' . realpath(trim($_attr['file'], "'")); + } else { + $compiler->template->template_resource = trim($_attr['resource'], "'"); + } + // source object + unset ($compiler->template->source); + $exists = $compiler->template->source->exists; + + // must merge includes + if ($_attr['nocache'] == true) { + $compiler->tag_nocache = true; + } + $save = array($_attr, $compiler->nocache); + + // set trace back to child block + $compiler->pushTrace(trim($_attr['file'], "\"'"), trim($_attr['uid'], "\"'"), $_attr['line'] - $compiler->lex->line); + + $this->openTag($compiler, 'private_child_block', $save); + + $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; + $compiler->has_code = false; + + return true; + } } -?>
\ No newline at end of file +/** + * Smarty Internal Plugin Compile Child Block Close Class + * + * @package Smarty + * @subpackage Compiler + */ +class Smarty_Internal_Compile_Private_Child_Blockclose extends Smarty_Internal_CompileBase +{ + + /** + * Compiles code for the {/private_child_block} tag + * + * @param array $args array with attributes from parser + * @param object $compiler compiler object + * + * @return boolean true + */ + public function compile($args, $compiler) + { + // check and get attributes + $_attr = $this->getAttributes($compiler, $args); + + $saved_data = $this->closeTag($compiler, array('private_child_block')); + + // end of child block + $compiler->popTrace(); + + $compiler->nocache = $saved_data[1]; + $compiler->has_code = false; + + return true; + } +} |