You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

smarty_internal_compile_block.php 13KB

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