PageRenderTime 45ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/core/model/smarty/sysplugins/smarty_internal_compile_section.php

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