smarty_internal_compile_block.php (18942B)
1 <?php 2 3 /** 4 * Smarty Internal Plugin Compile Block 5 * Compiles the {block}{/block} tags 6 * 7 * @package Smarty 8 * @subpackage Compiler 9 * @author Uwe Tews 10 */ 11 12 /** 13 * Smarty Internal Plugin Compile Block Class 14 * 15 * @package Smarty 16 * @subpackage Compiler 17 */ 18 class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase 19 { 20 21 const parent = '____SMARTY_BLOCK_PARENT____'; 22 /** 23 * Attribute definition: Overwrites base class. 24 * 25 * @var array 26 * @see Smarty_Internal_CompileBase 27 */ 28 public $required_attributes = array('name'); 29 30 /** 31 * Attribute definition: Overwrites base class. 32 * 33 * @var array 34 * @see Smarty_Internal_CompileBase 35 */ 36 public $shorttag_order = array('name'); 37 38 /** 39 * Attribute definition: Overwrites base class. 40 * 41 * @var array 42 * @see Smarty_Internal_CompileBase 43 */ 44 public $option_flags = array('hide', 'append', 'prepend', 'nocache'); 45 46 /** 47 * Attribute definition: Overwrites base class. 48 * 49 * @var array 50 * @see Smarty_Internal_CompileBase 51 */ 52 public $optional_attributes = array('internal_file', 'internal_uid', 'internal_line'); 53 /** 54 * nested child block names 55 * 56 * @var array 57 */ 58 public static $nested_block_names = array(); 59 60 /** 61 * child block source buffer 62 * 63 * @var array 64 */ 65 public static $block_data = array(); 66 67 /** 68 * Compiles code for the {block} tag 69 * 70 * @param array $args array with attributes from parser 71 * @param object $compiler compiler object 72 * 73 * @return boolean true 74 */ 75 public function compile($args, $compiler) 76 { 77 // check and get attributes 78 $_attr = $this->getAttributes($compiler, $args); 79 $_name = trim($_attr['name'], "\"'"); 80 81 // existing child must override parent settings 82 if (isset($compiler->template->block_data[$_name]) && $compiler->template->block_data[$_name]['mode'] == 'replace') { 83 $_attr['append'] = false; 84 $_attr['prepend'] = false; 85 } 86 87 // check if we process an inheritance child template 88 if ($compiler->inheritance_child) { 89 array_unshift(self::$nested_block_names, $_name); 90 // build {block} for child block 91 self::$block_data[$_name]['source'] = 92 "{$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}'" . 93 " uid='{$compiler->template->source->uid}' line={$compiler->lex->line}"; 94 if ($_attr['nocache']) { 95 self::$block_data[$_name]['source'] .= ' nocache'; 96 } 97 self::$block_data[$_name]['source'] .= $compiler->smarty->right_delimiter; 98 99 $save = array($_attr, $compiler->inheritance); 100 $this->openTag($compiler, 'block', $save); 101 // set flag for {block} tag 102 $compiler->inheritance = true; 103 $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK); 104 $compiler->has_code = false; 105 return; 106 } 107 // must merge includes 108 if ($_attr['nocache'] == true) { 109 $compiler->tag_nocache = true; 110 } 111 $save = array($_attr, $compiler->inheritance, $compiler->parser->current_buffer, $compiler->nocache); 112 $this->openTag($compiler, 'block', $save); 113 $compiler->inheritance = true; 114 $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; 115 116 $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template($compiler->parser); 117 $compiler->has_code = false; 118 119 return true; 120 } 121 122 /** 123 * Compile saved child block source 124 * 125 * @param object $compiler compiler object 126 * @param string $_name optional name of child block 127 * 128 * @return string compiled code of child block 129 */ 130 static function compileChildBlock($compiler, $_name = null) 131 { 132 if ($compiler->inheritance_child) { 133 $name1 = Smarty_Internal_Compile_Block::$nested_block_names[0]; 134 if (isset($compiler->template->block_data[$name1])) { 135 // replace inner block name with generic 136 Smarty_Internal_Compile_Block::$block_data[$name1]['source'] .= $compiler->template->block_data[$name1]['source']; 137 Smarty_Internal_Compile_Block::$block_data[$name1]['child'] = true; 138 } 139 $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK); 140 $compiler->has_code = false; 141 return; 142 } 143 // if called by {$smarty.block.child} we must search the name of enclosing {block} 144 if ($_name == null) { 145 $stack_count = count($compiler->_tag_stack); 146 while (-- $stack_count >= 0) { 147 if ($compiler->_tag_stack[$stack_count][0] == 'block') { 148 $_name = trim($compiler->_tag_stack[$stack_count][1][0]['name'], "\"'"); 149 break; 150 } 151 } 152 } 153 if ($_name == null) { 154 $compiler->trigger_template_error(' tag {$smarty.block.child} used outside {block} tags ', $compiler->lex->taglineno); 155 } 156 // undefined child? 157 if (!isset($compiler->template->block_data[$_name]['source'])) { 158 $compiler->popTrace(); 159 return ''; 160 } 161 // flag that child is already compile by {$smarty.block.child} inclusion 162 $compiler->template->block_data[$_name]['compiled'] = true; 163 $_tpl = new Smarty_Internal_template('string:' . $compiler->template->block_data[$_name]['source'], $compiler->smarty, $compiler->template, $compiler->template->cache_id, 164 $compiler->template->compile_id, $compiler->template->caching, $compiler->template->cache_lifetime); 165 if ($compiler->smarty->debugging) { 166 Smarty_Internal_Debug::ignore($_tpl); 167 } 168 $_tpl->tpl_vars = $compiler->template->tpl_vars; 169 $_tpl->variable_filters = $compiler->template->variable_filters; 170 $_tpl->properties['nocache_hash'] = $compiler->template->properties['nocache_hash']; 171 $_tpl->allow_relative_path = true; 172 $_tpl->compiler->inheritance = true; 173 $_tpl->compiler->suppressHeader = true; 174 $_tpl->compiler->suppressFilter = true; 175 $_tpl->compiler->suppressTemplatePropertyHeader = true; 176 $nocache = $compiler->nocache || $compiler->tag_nocache; 177 if (strpos($compiler->template->block_data[$_name]['source'], self::parent) !== false) { 178 $_output = str_replace(self::parent, $compiler->parser->current_buffer->to_smarty_php(), $_tpl->compiler->compileTemplate($_tpl, $nocache, $compiler->parent_compiler)); 179 } elseif ($compiler->template->block_data[$_name]['mode'] == 'prepend') { 180 $_output = $_tpl->compiler->compileTemplate($_tpl, $nocache, $compiler->parent_compiler) . $compiler->parser->current_buffer->to_smarty_php(); 181 } elseif ($compiler->template->block_data[$_name]['mode'] == 'append') { 182 $_output = $compiler->parser->current_buffer->to_smarty_php() . $_tpl->compiler->compileTemplate($_tpl, $nocache, $compiler->parent_compiler); 183 } elseif (!empty($compiler->template->block_data[$_name])) { 184 $_output = $_tpl->compiler->compileTemplate($_tpl, $nocache, $compiler->parent_compiler); 185 } 186 $compiler->template->properties['file_dependency'] = array_merge($compiler->template->properties['file_dependency'], $_tpl->properties['file_dependency']); 187 $compiler->template->properties['tpl_function'] = array_merge($compiler->template->properties['tpl_function'], $_tpl->properties['tpl_function']); 188 $compiler->template->variable_filters = $_tpl->variable_filters; 189 if ($_tpl->has_nocache_code) { 190 $compiler->template->has_nocache_code = true; 191 } 192 foreach ($_tpl->required_plugins as $key => $tmp1) { 193 if ($compiler->nocache && $compiler->template->caching) { 194 $code = 'nocache'; 195 } else { 196 $code = $key; 197 } 198 foreach ($tmp1 as $name => $tmp) { 199 foreach ($tmp as $type => $data) { 200 $compiler->template->required_plugins[$code][$name][$type] = $data; 201 } 202 } 203 } 204 unset($_tpl); 205 $compiler->has_code = true; 206 return $_output; 207 } 208 209 /** 210 * Compile $smarty.block.parent 211 * 212 * @param object $compiler compiler object 213 * @param string $_name optional name of child block 214 * 215 * @return string compiled code of child block 216 */ 217 static function compileParentBlock($compiler, $_name = null) 218 { 219 // if called by {$smarty.block.parent} we must search the name of enclosing {block} 220 if ($_name == null) { 221 $stack_count = count($compiler->_tag_stack); 222 while (-- $stack_count >= 0) { 223 if ($compiler->_tag_stack[$stack_count][0] == 'block') { 224 $_name = trim($compiler->_tag_stack[$stack_count][1][0]['name'], "\"'"); 225 break; 226 } 227 } 228 } 229 if ($_name == null) { 230 $compiler->trigger_template_error(' tag {$smarty.block.parent} used outside {block} tags ', $compiler->lex->taglineno); 231 } 232 if (empty(Smarty_Internal_Compile_Block::$nested_block_names)) { 233 $compiler->trigger_template_error(' illegal {$smarty.block.parent} in parent template ', $compiler->lex->taglineno); 234 } 235 Smarty_Internal_Compile_Block::$block_data[Smarty_Internal_Compile_Block::$nested_block_names[0]]['source'] .= Smarty_Internal_Compile_Block::parent; 236 $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK); 237 $compiler->has_code = false; 238 return; 239 } 240 241 /** 242 * Process block source 243 * 244 * @param $compiler 245 * @param string $source source text 246 */ 247 static function blockSource($compiler, $source) 248 { 249 Smarty_Internal_Compile_Block::$block_data[Smarty_Internal_Compile_Block::$nested_block_names[0]]['source'] .= $source; 250 } 251 } 252 253 /** 254 * Smarty Internal Plugin Compile BlockClose Class 255 * 256 * @package Smarty 257 * @subpackage Compiler 258 */ 259 class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_CompileBase 260 { 261 /** 262 * Compiles code for the {/block} tag 263 * 264 * @param array $args array with attributes from parser 265 * @param object $compiler compiler object 266 * 267 * @return string compiled code 268 */ 269 public function compile($args, $compiler) 270 { 271 $compiler->has_code = true; 272 // check and get attributes 273 $_attr = $this->getAttributes($compiler, $args); 274 $saved_data = $this->closeTag($compiler, array('block')); 275 $_name = trim($saved_data[0]['name'], "\"'"); 276 // reset flag for {block} tag 277 $compiler->inheritance = $saved_data[1]; 278 // check if we process an inheritance child template 279 if ($compiler->inheritance_child) { 280 $name1 = Smarty_Internal_Compile_Block::$nested_block_names[0]; 281 Smarty_Internal_Compile_Block::$block_data[$name1]['source'] .= "{$compiler->smarty->left_delimiter}/private_child_block{$compiler->smarty->right_delimiter}"; 282 array_shift(Smarty_Internal_Compile_Block::$nested_block_names); 283 if (!empty(Smarty_Internal_Compile_Block::$nested_block_names)) { 284 $name2 = Smarty_Internal_Compile_Block::$nested_block_names[0]; 285 if (isset($compiler->template->block_data[$name1]) || !$saved_data[0]['hide']) { 286 if (isset(Smarty_Internal_Compile_Block::$block_data[$name1]['child']) || !isset($compiler->template->block_data[$name1])) { 287 Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= Smarty_Internal_Compile_Block::$block_data[$name1]['source']; 288 } else { 289 if ($compiler->template->block_data[$name1]['mode'] == 'append') { 290 Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= Smarty_Internal_Compile_Block::$block_data[$name1]['source'] . $compiler->template->block_data[$name1]['source']; 291 } elseif ($compiler->template->block_data[$name1]['mode'] == 'prepend') { 292 Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= $compiler->template->block_data[$name1]['source'] . Smarty_Internal_Compile_Block::$block_data[$name1]['source']; 293 } else { 294 Smarty_Internal_Compile_Block::$block_data[$name2]['source'] .= $compiler->template->block_data[$name1]['source']; 295 } 296 } 297 } 298 unset(Smarty_Internal_Compile_Block::$block_data[$name1]); 299 $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBLOCK); 300 } else { 301 if (isset($compiler->template->block_data[$name1]) || !$saved_data[0]['hide']) { 302 if (isset($compiler->template->block_data[$name1]) && !isset(Smarty_Internal_Compile_Block::$block_data[$name1]['child'])) { 303 if (strpos($compiler->template->block_data[$name1]['source'], Smarty_Internal_Compile_Block::parent) !== false) { 304 $compiler->template->block_data[$name1]['source'] = 305 str_replace(Smarty_Internal_Compile_Block::parent, Smarty_Internal_Compile_Block::$block_data[$name1]['source'], $compiler->template->block_data[$name1]['source']); 306 } elseif ($compiler->template->block_data[$name1]['mode'] == 'prepend') { 307 $compiler->template->block_data[$name1]['source'] .= Smarty_Internal_Compile_Block::$block_data[$name1]['source']; 308 } elseif ($compiler->template->block_data[$name1]['mode'] == 'append') { 309 $compiler->template->block_data[$name1]['source'] = Smarty_Internal_Compile_Block::$block_data[$name1]['source'] . $compiler->template->block_data[$name1]['source']; 310 } 311 } else { 312 $compiler->template->block_data[$name1]['source'] = Smarty_Internal_Compile_Block::$block_data[$name1]['source']; 313 } 314 $compiler->template->block_data[$name1]['mode'] = 'replace'; 315 if ($saved_data[0]['append']) { 316 $compiler->template->block_data[$name1]['mode'] = 'append'; 317 } 318 if ($saved_data[0]['prepend']) { 319 $compiler->template->block_data[$name1]['mode'] = 'prepend'; 320 } 321 } 322 unset(Smarty_Internal_Compile_Block::$block_data[$name1]); 323 $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBODY); 324 } 325 $compiler->has_code = false; 326 return; 327 } 328 if (isset($compiler->template->block_data[$_name]) && !isset($compiler->template->block_data[$_name]['compiled'])) { 329 $_output = Smarty_Internal_Compile_Block::compileChildBlock($compiler, $_name); 330 } else { 331 if ($saved_data[0]['hide'] && !isset($compiler->template->block_data[$_name]['source'])) { 332 $_output = ''; 333 } else { 334 $_output = $compiler->parser->current_buffer->to_smarty_php(); 335 } 336 } 337 if (isset($compiler->template->block_data[$_name]['compiled'])) { 338 unset($compiler->template->block_data[$_name]['compiled']); 339 } 340 // reset flags 341 $compiler->parser->current_buffer = $saved_data[2]; 342 if ($compiler->nocache) { 343 $compiler->tag_nocache = true; 344 } 345 $compiler->nocache = $saved_data[3]; 346 // $_output content has already nocache code processed 347 $compiler->suppressNocacheProcessing = true; 348 349 return $_output; 350 } 351 } 352 353 /** 354 * Smarty Internal Plugin Compile Child Block Class 355 * 356 * @package Smarty 357 * @subpackage Compiler 358 */ 359 class Smarty_Internal_Compile_Private_Child_Block extends Smarty_Internal_CompileBase 360 { 361 362 /** 363 * Attribute definition: Overwrites base class. 364 * 365 * @var array 366 * @see Smarty_Internal_CompileBase 367 */ 368 public $required_attributes = array('name', 'file', 'uid', 'line', 'type', 'resource'); 369 370 /** 371 * Compiles code for the {private_child_block} tag 372 * 373 * @param array $args array with attributes from parser 374 * @param object $compiler compiler object 375 * 376 * @return boolean true 377 */ 378 public function compile($args, $compiler) 379 { 380 // check and get attributes 381 $_attr = $this->getAttributes($compiler, $args); 382 383 // update template with original template resource of {block} 384 if (trim($_attr['type'], "'") == 'file') { 385 $compiler->template->template_resource = 'file:' . realpath(trim($_attr['file'], "'")); 386 } else { 387 $compiler->template->template_resource = trim($_attr['resource'], "'"); 388 } 389 // source object 390 unset ($compiler->template->source); 391 $exists = $compiler->template->source->exists; 392 393 // must merge includes 394 if ($_attr['nocache'] == true) { 395 $compiler->tag_nocache = true; 396 } 397 $save = array($_attr, $compiler->nocache); 398 399 // set trace back to child block 400 $compiler->pushTrace(trim($_attr['file'], "\"'"), trim($_attr['uid'], "\"'"), $_attr['line'] - $compiler->lex->line); 401 402 $this->openTag($compiler, 'private_child_block', $save); 403 404 $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; 405 $compiler->has_code = false; 406 407 return true; 408 } 409 } 410 411 /** 412 * Smarty Internal Plugin Compile Child Block Close Class 413 * 414 * @package Smarty 415 * @subpackage Compiler 416 */ 417 class Smarty_Internal_Compile_Private_Child_Blockclose extends Smarty_Internal_CompileBase 418 { 419 420 /** 421 * Compiles code for the {/private_child_block} tag 422 * 423 * @param array $args array with attributes from parser 424 * @param object $compiler compiler object 425 * 426 * @return boolean true 427 */ 428 public function compile($args, $compiler) 429 { 430 // check and get attributes 431 $_attr = $this->getAttributes($compiler, $args); 432 433 $saved_data = $this->closeTag($compiler, array('private_child_block')); 434 435 // end of child block 436 $compiler->popTrace(); 437 438 $compiler->nocache = $saved_data[1]; 439 $compiler->has_code = false; 440 441 return true; 442 } 443 }