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_section.php 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. <?php
  2. /**
  3. * Smarty Internal Plugin Compile Section
  4. * Compiles the {section} {sectionelse} {/section} tags
  5. *
  6. * @package Smarty
  7. * @subpackage Compiler
  8. * @author Uwe Tews
  9. */
  10. /**
  11. * Smarty Internal Plugin Compile Section Class
  12. *
  13. * @package Smarty
  14. * @subpackage Compiler
  15. */
  16. class Smarty_Internal_Compile_Section extends Smarty_Internal_Compile_Private_ForeachSection
  17. {
  18. /**
  19. * Attribute definition: Overwrites base class.
  20. *
  21. * @var array
  22. * @see Smarty_Internal_CompileBase
  23. */
  24. public $required_attributes = array('name', 'loop');
  25. /**
  26. * Attribute definition: Overwrites base class.
  27. *
  28. * @var array
  29. * @see Smarty_Internal_CompileBase
  30. */
  31. public $shorttag_order = array('name', 'loop');
  32. /**
  33. * Attribute definition: Overwrites base class.
  34. *
  35. * @var array
  36. * @see Smarty_Internal_CompileBase
  37. */
  38. public $optional_attributes = array('start', 'step', 'max', 'show');
  39. /**
  40. * counter
  41. *
  42. * @var int
  43. */
  44. public $counter = 0;
  45. /**
  46. * Name of this tag
  47. *
  48. * @var string
  49. */
  50. public $tagName = 'section';
  51. /**
  52. * Valid properties of $smarty.section.name.xxx variable
  53. *
  54. * @var array
  55. */
  56. public $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total', 'rownum',
  57. 'index_prev', 'index_next');
  58. /**
  59. * {section} tag has no item properties
  60. *
  61. * @var array
  62. */
  63. public $itemProperties = null;
  64. /**
  65. * {section} tag has always name attribute
  66. *
  67. * @var bool
  68. */
  69. public $isNamed = true;
  70. /**
  71. * Compiles code for the {section} tag
  72. *
  73. * @param array $args array with attributes from parser
  74. * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
  75. *
  76. * @return string compiled code
  77. * @throws \SmartyCompilerException
  78. */
  79. public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
  80. {
  81. $compiler->loopNesting++;
  82. // check and get attributes
  83. $_attr = $this->getAttributes($compiler, $args);
  84. $attributes = array('name' => $compiler->getId($_attr['name']));
  85. unset($_attr['name']);
  86. foreach ($attributes as $a => $v) {
  87. if ($v === false) {
  88. $compiler->trigger_template_error("'{$a}' attribute/variable has illegal value", null, true);
  89. }
  90. }
  91. $local = "\$__section_{$attributes['name']}_" . $this->counter ++ . '_';
  92. $sectionVar = "\$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}']";
  93. $this->openTag($compiler, 'section', array('section', $compiler->nocache, $local, $sectionVar));
  94. // maybe nocache because of nocache variables
  95. $compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
  96. $initLocal = array('saved' => "isset(\$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}']) ? \$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}'] : false",);
  97. $initNamedProperty = array();
  98. $initFor = array();
  99. $incFor = array();
  100. $cmpFor = array();
  101. $propValue = array('index' => "{$sectionVar}->value['index']", 'show' => 'true', 'step' => 1,
  102. 'iteration' => "{$local}iteration",
  103. );
  104. $propType = array('index' => 2, 'iteration' => 2, 'show' => 0, 'step' => 0,);
  105. // search for used tag attributes
  106. $this->scanForProperties($attributes, $compiler);
  107. if (!empty($this->matchResults['named'])) {
  108. $namedAttr = $this->matchResults['named'];
  109. }
  110. $namedAttr['index'] = true;
  111. $output = "<?php\n";
  112. foreach ($_attr as $attr_name => $attr_value) {
  113. switch ($attr_name) {
  114. case 'loop':
  115. if (is_numeric($attr_value)) {
  116. $v = (int) $attr_value;
  117. $t = 0;
  118. } else {
  119. $v = "(is_array(@\$_loop=$attr_value) ? count(\$_loop) : max(0, (int) \$_loop))";
  120. $t = 1;
  121. }
  122. if (isset($namedAttr['loop'])) {
  123. $initNamedProperty['loop'] = "'loop' => {$v}";
  124. if ($t == 1) {
  125. $v = "{$sectionVar}->value['loop']";
  126. }
  127. } elseif ($t == 1) {
  128. $initLocal['loop'] = $v;
  129. $v = "{$local}loop";
  130. }
  131. break;
  132. case 'show':
  133. if (is_bool($attr_value)) {
  134. $v = $attr_value ? 'true' : 'false';
  135. $t = 0;
  136. } else {
  137. $v = "(bool) $attr_value";
  138. $t = 3;
  139. }
  140. break;
  141. case 'step':
  142. if (is_numeric($attr_value)) {
  143. $v = (int) $attr_value;
  144. $v = ($v == 0) ? 1 : $v;
  145. $t = 0;
  146. break;
  147. }
  148. $initLocal['step'] = "((int)@$attr_value) == 0 ? 1 : (int)@$attr_value";
  149. $v = "{$local}step";
  150. $t = 2;
  151. break;
  152. case 'max':
  153. case 'start':
  154. if (is_numeric($attr_value)) {
  155. $v = (int) $attr_value;
  156. $t = 0;
  157. break;
  158. }
  159. $v = "(int)@$attr_value";
  160. $t = 3;
  161. break;
  162. }
  163. if ($t == 3 && $compiler->getId($attr_value)) {
  164. $t = 1;
  165. }
  166. $propValue[$attr_name] = $v;
  167. $propType[$attr_name] = $t;
  168. }
  169. if (isset($namedAttr['step'])) {
  170. $initNamedProperty['step'] = $propValue['step'];
  171. }
  172. if (isset($namedAttr['iteration'])) {
  173. $propValue['iteration'] = "{$sectionVar}->value['iteration']";
  174. }
  175. $incFor['iteration'] = "{$propValue['iteration']}++";
  176. $initFor['iteration'] = "{$propValue['iteration']} = 1";
  177. if ($propType['step'] == 0) {
  178. if ($propValue['step'] == 1) {
  179. $incFor['index'] = "{$sectionVar}->value['index']++";
  180. } elseif ($propValue['step'] > 1) {
  181. $incFor['index'] = "{$sectionVar}->value['index'] += {$propValue['step']}";
  182. } else {
  183. $incFor['index'] = "{$sectionVar}->value['index'] -= " . - $propValue['step'];
  184. }
  185. } else {
  186. $incFor['index'] = "{$sectionVar}->value['index'] += {$propValue['step']}";
  187. }
  188. if (!isset($propValue['max'])) {
  189. $propValue['max'] = $propValue['loop'];
  190. $propType['max'] = $propType['loop'];
  191. } elseif ($propType['max'] != 0) {
  192. $propValue['max'] = "{$propValue['max']} < 0 ? {$propValue['loop']} : {$propValue['max']}";
  193. $propType['max'] = 1;
  194. } else {
  195. if ($propValue['max'] < 0) {
  196. $propValue['max'] = $propValue['loop'];
  197. $propType['max'] = $propType['loop'];
  198. }
  199. }
  200. if (!isset($propValue['start'])) {
  201. $start_code = array(1 => "{$propValue['step']} > 0 ? ", 2 => '0', 3 => ' : ', 4 => $propValue['loop'],
  202. 5 => ' - 1');
  203. if ($propType['loop'] == 0) {
  204. $start_code[5] = '';
  205. $start_code[4] = $propValue['loop'] - 1;
  206. }
  207. if ($propType['step'] == 0) {
  208. if ($propValue['step'] > 0) {
  209. $start_code = array(1 => '0');
  210. $propType['start'] = 0;
  211. } else {
  212. $start_code[1] = $start_code[2] = $start_code[3] = '';
  213. $propType['start'] = $propType['loop'];
  214. }
  215. } else {
  216. $propType['start'] = 1;
  217. }
  218. $propValue['start'] = join('', $start_code);
  219. } else {
  220. $start_code = array(1 => "{$propValue['start']} < 0 ? ", 2 => 'max(', 3 => "{$propValue['step']} > 0 ? ",
  221. 4 => '0', 5 => ' : ', 6 => '-1', 7 => ', ',
  222. 8 => "{$propValue['start']} + {$propValue['loop']}", 10 => ')', 11 => ' : ',
  223. 12 => 'min(', 13 => $propValue['start'], 14 => ', ',
  224. 15 => "{$propValue['step']} > 0 ? ", 16 => $propValue['loop'], 17 => ' : ',
  225. 18 => $propType['loop'] == 0 ? $propValue['loop'] - 1 : "{$propValue['loop']} - 1",
  226. 19 => ')');
  227. if ($propType['step'] == 0) {
  228. $start_code[3] = $start_code[5] = $start_code[15] = $start_code[17] = '';
  229. if ($propValue['step'] > 0) {
  230. $start_code[6] = $start_code[18] = '';
  231. } else {
  232. $start_code[4] = $start_code[16] = '';
  233. }
  234. }
  235. if ($propType['start'] == 0) {
  236. if ($propType['loop'] == 0) {
  237. $start_code[8] = $propValue['start'] + $propValue['loop'];
  238. }
  239. $propType['start'] = $propType['step'] + $propType['loop'];
  240. $start_code[1] = '';
  241. if ($propValue['start'] < 0) {
  242. for ($i = 11; $i <= 19; $i ++) {
  243. $start_code[$i] = '';
  244. }
  245. if ($propType['start'] == 0) {
  246. $start_code = array(max($propValue['step'] > 0 ? 0 : - 1, $propValue['start'] +
  247. $propValue['loop']));
  248. }
  249. } else {
  250. for ($i = 1; $i <= 11; $i ++) {
  251. $start_code[$i] = '';
  252. }
  253. if ($propType['start'] == 0) {
  254. $start_code = array(min($propValue['step'] > 0 ? $propValue['loop'] : $propValue['loop'] -
  255. 1, $propValue['start']));
  256. }
  257. }
  258. }
  259. $propValue['start'] = join('', $start_code);
  260. }
  261. if ($propType['start'] != 0) {
  262. $initLocal['start'] = $propValue['start'];
  263. $propValue['start'] = "{$local}start";
  264. }
  265. $initFor['index'] = "{$sectionVar}->value['index'] = {$propValue['start']}";
  266. if (!isset($_attr['start']) && !isset($_attr['step']) && !isset($_attr['max'])) {
  267. $propValue['total'] = $propValue['loop'];
  268. $propType['total'] = $propType['loop'];
  269. } else {
  270. $propType['total'] = $propType['start'] + $propType['loop'] + $propType['step'] + $propType['max'];
  271. if ($propType['total'] == 0) {
  272. $propValue['total'] = min(ceil(($propValue['step'] > 0 ? $propValue['loop'] -
  273. $propValue['start'] : (int) $propValue['start'] + 1) /
  274. abs($propValue['step'])), $propValue['max']);
  275. } else {
  276. $total_code = array(1 => 'min(', 2 => 'ceil(', 3 => '(', 4 => "{$propValue['step']} > 0 ? ",
  277. 5 => $propValue['loop'], 6 => ' - ', 7 => $propValue['start'], 8 => ' : ',
  278. 9 => $propValue['start'], 10 => '+ 1', 11 => ')', 12 => '/ ', 13 => 'abs(',
  279. 14 => $propValue['step'], 15 => ')', 16 => ')', 17 => ", {$propValue['max']})",);
  280. if (!isset($propValue['max'])) {
  281. $total_code[1] = $total_code[17] = '';
  282. }
  283. if ($propType['loop'] + $propType['start'] == 0) {
  284. $total_code[5] = $propValue['loop'] - $propValue['start'];
  285. $total_code[6] = $total_code[7] = '';
  286. }
  287. if ($propType['start'] == 0) {
  288. $total_code[9] = (int) $propValue['start'] + 1;
  289. $total_code[10] = '';
  290. }
  291. if ($propType['step'] == 0) {
  292. $total_code[13] = $total_code[15] = '';
  293. if ($propValue['step'] == 1 || $propValue['step'] == - 1) {
  294. $total_code[2] = $total_code[12] = $total_code[14] = $total_code[16] = '';
  295. } elseif ($propValue['step'] < 0) {
  296. $total_code[14] = - $propValue['step'];
  297. }
  298. $total_code[4] = '';
  299. if ($propValue['step'] > 0) {
  300. $total_code[8] = $total_code[9] = $total_code[10] = '';
  301. } else {
  302. $total_code[5] = $total_code[6] = $total_code[7] = $total_code[8] = '';
  303. }
  304. }
  305. $propValue['total'] = join('', $total_code);
  306. }
  307. }
  308. if (isset($namedAttr['total'])) {
  309. $initNamedProperty['total'] = "'total' => {$propValue['total']}";
  310. if ($propType['total'] > 0) {
  311. $propValue['total'] = "{$sectionVar}->value['total']";
  312. }
  313. } elseif ($propType['total'] > 0) {
  314. $initLocal['total'] = $propValue['total'];
  315. $propValue['total'] = "{$local}total";
  316. }
  317. $cmpFor['iteration'] = "{$propValue['iteration']} <= {$propValue['total']}";
  318. foreach ($initLocal as $key => $code) {
  319. $output .= "{$local}{$key} = {$code};\n";
  320. }
  321. $_vars = 'array(' . join(', ', $initNamedProperty) . ')';
  322. $output .= "{$sectionVar} = new Smarty_Variable({$_vars});\n";
  323. $cond_code = "{$propValue['total']} != 0";
  324. if ($propType['total'] == 0) {
  325. if ($propValue['total'] == 0) {
  326. $cond_code = 'false';
  327. } else {
  328. $cond_code = 'true';
  329. }
  330. }
  331. if ($propType['show'] > 0) {
  332. $output .= "{$local}show = {$propValue['show']} ? {$cond_code} : false;\n";
  333. $output .= "if ({$local}show) {\n";
  334. } elseif ($propValue['show'] == 'true') {
  335. $output .= "if ({$cond_code}) {\n";
  336. } else {
  337. $output .= "if (false) {\n";
  338. }
  339. $jinit = join(', ', $initFor);
  340. $jcmp = join(', ', $cmpFor);
  341. $jinc = join(', ', $incFor);
  342. $output .= "for ({$jinit}; {$jcmp}; {$jinc}){\n";
  343. if (isset($namedAttr['rownum'])) {
  344. $output .= "{$sectionVar}->value['rownum'] = {$propValue['iteration']};\n";
  345. }
  346. if (isset($namedAttr['index_prev'])) {
  347. $output .= "{$sectionVar}->value['index_prev'] = {$propValue['index']} - {$propValue['step']};\n";
  348. }
  349. if (isset($namedAttr['index_next'])) {
  350. $output .= "{$sectionVar}->value['index_next'] = {$propValue['index']} + {$propValue['step']};\n";
  351. }
  352. if (isset($namedAttr['first'])) {
  353. $output .= "{$sectionVar}->value['first'] = ({$propValue['iteration']} == 1);\n";
  354. }
  355. if (isset($namedAttr['last'])) {
  356. $output .= "{$sectionVar}->value['last'] = ({$propValue['iteration']} == {$propValue['total']});\n";
  357. }
  358. $output .= "?>";
  359. return $output;
  360. }
  361. }
  362. /**
  363. * Smarty Internal Plugin Compile Sectionelse Class
  364. *
  365. * @package Smarty
  366. * @subpackage Compiler
  367. */
  368. class Smarty_Internal_Compile_Sectionelse extends Smarty_Internal_CompileBase
  369. {
  370. /**
  371. * Compiles code for the {sectionelse} tag
  372. *
  373. * @param array $args array with attributes from parser
  374. * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
  375. *
  376. * @return string compiled code
  377. */
  378. public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
  379. {
  380. // check and get attributes
  381. $_attr = $this->getAttributes($compiler, $args);
  382. list($openTag, $nocache, $local, $sectionVar) = $this->closeTag($compiler, array('section'));
  383. $this->openTag($compiler, 'sectionelse', array('sectionelse', $nocache, $local, $sectionVar));
  384. return "<?php }} else {\n ?>";
  385. }
  386. }
  387. /**
  388. * Smarty Internal Plugin Compile Sectionclose Class
  389. *
  390. * @package Smarty
  391. * @subpackage Compiler
  392. */
  393. class Smarty_Internal_Compile_Sectionclose extends Smarty_Internal_CompileBase
  394. {
  395. /**
  396. * Compiles code for the {/section} tag
  397. *
  398. * @param array $args array with attributes from parser
  399. * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
  400. *
  401. * @return string compiled code
  402. */
  403. public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
  404. {
  405. $compiler->loopNesting--;
  406. // must endblock be nocache?
  407. if ($compiler->nocache) {
  408. $compiler->tag_nocache = true;
  409. }
  410. list($openTag, $compiler->nocache, $local, $sectionVar) = $this->closeTag($compiler, array('section',
  411. 'sectionelse'));
  412. $output = "<?php\n";
  413. if ($openTag == 'sectionelse') {
  414. $output .= "}\n";
  415. } else {
  416. $output .= "}\n}\n";
  417. }
  418. $output .= "if ({$local}saved) {\n";
  419. $output .= "{$sectionVar} = {$local}saved;\n";
  420. $output .= "}\n";
  421. $output .= "?>";
  422. return $output;
  423. }
  424. }