1<?php 2/* 3 * This file is part of Smarty. 4 * 5 * (c) 2015 Uwe Tews 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11/** 12 * Smarty Internal Plugin Compile Block Class 13 * 14 * @author Uwe Tews <uwe.tews@googlemail.com> 15 */ 16class Smarty_Internal_Compile_Block extends Smarty_Internal_Compile_Shared_Inheritance 17{ 18 /** 19 * Attribute definition: Overwrites base class. 20 * 21 * @var array 22 * @see Smarty_Internal_CompileBase 23 */ 24 public $required_attributes = array('name'); 25 26 /** 27 * Attribute definition: Overwrites base class. 28 * 29 * @var array 30 * @see Smarty_Internal_CompileBase 31 */ 32 public $shorttag_order = array('name'); 33 34 /** 35 * Attribute definition: Overwrites base class. 36 * 37 * @var array 38 * @see Smarty_Internal_CompileBase 39 */ 40 public $option_flags = array('hide', 'nocache'); 41 42 /** 43 * Attribute definition: Overwrites base class. 44 * 45 * @var array 46 * @see Smarty_Internal_CompileBase 47 */ 48 public $optional_attributes = array('assign'); 49 50 /** 51 * nesting level of block tags 52 * 53 * @var int 54 */ 55 public static $blockTagNestingLevel = 0; 56 57 /** 58 * Saved compiler object 59 * 60 * @var Smarty_Internal_TemplateCompilerBase 61 */ 62 public $compiler = null; 63 64 /** 65 * Compiles code for the {block} tag 66 * 67 * @param array $args array with attributes from parser 68 * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object 69 * @param array $parameter array with compilation parameter 70 * 71 * @return bool true 72 */ 73 public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) 74 { 75 if (!isset($compiler->_cache['blockNesting'])) { 76 $compiler->_cache['blockNesting'] = 0; 77 } 78 if ($compiler->_cache['blockNesting'] == 0) { 79 // make sure that inheritance gets initialized in template code 80 $this->registerInit($compiler); 81 $this->option_flags = array('hide', 'nocache', 'append', 'prepend'); 82 } else { 83 $this->option_flags = array('hide', 'nocache'); 84 } 85 // check and get attributes 86 $_attr = $this->getAttributes($compiler, $args); 87 $compiler->_cache['blockNesting'] ++; 88 $compiler->_cache['blockName'][$compiler->_cache['blockNesting']] = $_attr['name']; 89 $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][0] = 'block_' . preg_replace('![^\w]+!', '_', uniqid(rand(), true)); 90 $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][1] = false; 91 $this->openTag($compiler, 'block', array($_attr, $compiler->nocache, $compiler->parser->current_buffer, 92 $compiler->template->compiled->has_nocache_code, 93 $compiler->template->caching)); 94 // must whole block be nocache ? 95 if ($compiler->tag_nocache) { 96 $i = 0; 97 } 98 $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; 99 // $compiler->suppressNocacheProcessing = true; 100 if ($_attr['nocache'] === true) { 101 //$compiler->trigger_template_error('nocache option not allowed', $compiler->parser->lex->taglineno); 102 } 103 $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); 104 $compiler->template->compiled->has_nocache_code = false; 105 $compiler->suppressNocacheProcessing = true; 106 } 107 108 /** 109 * Compile saved child block source 110 * 111 * @param \Smarty_Internal_TemplateCompilerBase compiler object 112 * @param string $_name optional name of child block 113 * 114 * @return string compiled code of child block 115 */ 116 static function compileChildBlock(Smarty_Internal_TemplateCompilerBase $compiler, $_name = null) 117 { 118 if (!isset($compiler->_cache['blockNesting'])) { 119 $compiler->trigger_template_error(' tag {$smarty.block.child} used outside {block} tags ', 120 $compiler->parser->lex->taglineno); 121 } 122 $compiler->has_code = true; 123 $compiler->suppressNocacheProcessing = true; 124 $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][1] = true; 125 $output = "<?php \n\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 2, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, null, \$_blockParentStack);\n?>\n"; 126 return $output; 127 } 128 129 /** 130 * Compile $smarty.block.parent 131 * 132 * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object 133 * @param string $_name optional name of child block 134 * 135 * @return string compiled code of child block 136 */ 137 static function compileParentBlock(Smarty_Internal_TemplateCompilerBase $compiler, $_name = null) 138 { 139 if (!isset($compiler->_cache['blockNesting'])) { 140 $compiler->trigger_template_error(' tag {$smarty.block.parent} used outside {block} tags ', 141 $compiler->parser->lex->taglineno); 142 } 143 $compiler->suppressNocacheProcessing = true; 144 $compiler->has_code = true; 145 $output = "<?php \n\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 4, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, null, \$_blockParentStack);\n?>\n"; 146 return $output; 147 } 148} 149 150/** 151 * Smarty Internal Plugin Compile BlockClose Class 152 * 153 */ 154class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_Inheritance 155{ 156 /** 157 * Compiles code for the {/block} tag 158 * 159 * @param array $args array with attributes from parser 160 * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object 161 * @param array $parameter array with compilation parameter 162 * 163 * @return bool true 164 */ 165 public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) 166 { 167 list($_attr, $_nocache, $_buffer, $_has_nocache_code, $_caching) = $this->closeTag($compiler, array('block')); 168 // init block parameter 169 $_block = $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']]; 170 unset($compiler->_cache['blockParams'][$compiler->_cache['blockNesting']]); 171 $_block[2] = $_block[3] = 0; 172 $_name = trim($_attr['name'], "'\""); 173 $_assign = isset($_attr['assign']) ? $_attr['assign'] : null; 174 unset($_attr['assign'], $_attr['name']); 175 foreach ($_attr as $name => $stat) { 176 if ((is_bool($stat) && $stat !== false) || (!is_bool($stat) && $stat != 'false')) { 177 $_block[$name] = is_string($stat) ? trim($stat, "'\"") : $stat; 178 } 179 } 180 $_funcName = $_block[0]; 181 // get compiled block code 182 $_functionCode = $compiler->parser->current_buffer; 183 // setup buffer for template function code 184 $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); 185 186 if ($compiler->template->compiled->has_nocache_code) { 187 // $compiler->parent_compiler->template->tpl_function[$_name]['call_name_caching'] = $_funcNameCaching; 188 $_block[6] = $_funcNameCaching = $_funcName . '_nocache'; 189 $output = "<?php\n"; 190 $output .= "/* {block '{$_name}'} {$compiler->template->source->type}:{$compiler->template->source->name} */\n"; 191 $output .= "function {$_funcNameCaching} (\$_smarty_tpl, \$_blockParentStack) {\n"; 192 $output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n"; 193 $output .= "\$_smarty_tpl->cached->hashes['{$compiler->template->compiled->nocache_hash}'] = true;\n"; 194 if (isset($_assign)) { 195 $output .= "ob_start();\n"; 196 } 197 $output .= "?>\n"; 198 $compiler->parser->current_buffer->append_subtree($compiler->parser, 199 new Smarty_Internal_ParseTree_Tag($compiler->parser, 200 $output)); 201 $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); 202 $output = "<?php\n"; 203 if (isset($_assign)) { 204 $output .= "\$_smarty_tpl->tpl_vars[{$_assign}] = new Smarty_Variable(ob_get_clean());\n"; 205 } 206 $output .= "/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n"; 207 $output .= "}\n"; 208 $output .= "/* {/block '{$_name}'} */\n\n"; 209 $output .= "?>\n"; 210 $compiler->parser->current_buffer->append_subtree($compiler->parser, 211 new Smarty_Internal_ParseTree_Tag($compiler->parser, 212 $output)); 213 $compiler->blockOrFunctionCode .= $f = $compiler->parser->current_buffer->to_smarty_php($compiler->parser); 214 $compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template(); 215 $this->compiler = $compiler; 216 $_functionCode = new Smarty_Internal_ParseTree_Tag($compiler->parser, 217 preg_replace_callback("/((<\?php )?echo '\/\*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/([\S\s]*?)\/\*\/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/", 218 array($this, 'removeNocache'), 219 $_functionCode->to_smarty_php($compiler->parser))); 220 $this->compiler = null; 221 } 222 $output = "<?php\n"; 223 $output .= "/* {block '{$_name}'} {$compiler->template->source->type}:{$compiler->template->source->name} */\n"; 224 $output .= "function {$_funcName}(\$_smarty_tpl, \$_blockParentStack) {\n"; 225 if (isset($_assign)) { 226 $output .= "ob_start();\n"; 227 } 228 $output .= "?>\n"; 229 $compiler->parser->current_buffer->append_subtree($compiler->parser, 230 new Smarty_Internal_ParseTree_Tag($compiler->parser, 231 $output)); 232 $compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode); 233 $output = "<?php\n"; 234 if (isset($_assign)) { 235 $output .= "\$_smarty_tpl->tpl_vars[{$_assign}] = new Smarty_Variable(ob_get_clean());\n"; 236 } 237 $output .= "}\n"; 238 $output .= "/* {/block '{$_name}'} */\n\n"; 239 $output .= "?>\n"; 240 $compiler->parser->current_buffer->append_subtree($compiler->parser, 241 new Smarty_Internal_ParseTree_Tag($compiler->parser, 242 $output)); 243 $compiler->blockOrFunctionCode .= $compiler->parser->current_buffer->to_smarty_php($compiler->parser); 244 // nocache plugins must be copied 245 if (!empty($compiler->template->compiled->required_plugins['nocache'])) { 246 foreach ($compiler->template->compiled->required_plugins['nocache'] as $plugin => $tmp) { 247 foreach ($tmp as $type => $data) { 248 $compiler->parent_compiler->template->compiled->required_plugins['compiled'][$plugin][$type] = 249 $data; 250 } 251 } 252 } 253 254 255 // restore old status 256 $compiler->template->compiled->has_nocache_code = $_has_nocache_code; 257 $compiler->tag_nocache = $compiler->nocache; 258 $compiler->nocache = $_nocache; 259 $compiler->parser->current_buffer = $_buffer; 260 $output = "<?php \n"; 261 if ($compiler->_cache['blockNesting'] == 1) { 262 $output .= "\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 0, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, " . 263 var_export($_block, true) . ");\n"; 264 } else { 265 $output .= "\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 0, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, " . 266 var_export($_block, true) . ", \$_blockParentStack);\n"; 267 268 } 269 $output .= "?>\n"; 270 $compiler->_cache['blockNesting'] --; 271 if ($compiler->_cache['blockNesting'] == 0) { 272 unset($compiler->_cache['blockNesting']); 273 } 274 $compiler->has_code = true; 275 $compiler->suppressNocacheProcessing = true; 276 return $output; 277 } 278 279 /** 280 * @param $match 281 * 282 * @return mixed 283 */ 284 function removeNocache($match) 285 { 286 $code = 287 preg_replace("/((<\?php )?echo '\/\*%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/)|(\/\*\/%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/", 288 '', $match[0]); 289 $code = str_replace(array('\\\'', '\\\\\''), array('\'', '\\\''), $code); 290 return $code; 291 } 292} 293