PageRenderTime 63ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/php/extlib/smarty/libs/sysplugins/smarty_internal_compile_foreach.php

https://github.com/usualoma/movabletype
PHP | 343 lines | 219 code | 12 blank | 112 comment | 50 complexity | e6e57170021ccd494a6c38f008844075 MD5 | raw file
  1. <?php
  2. /**
  3. * Smarty Internal Plugin Compile Foreach
  4. * Compiles the {foreach} {foreachelse} {/foreach} tags
  5. *
  6. * @package Smarty
  7. * @subpackage Compiler
  8. * @author Uwe Tews
  9. */
  10. /**
  11. * Smarty Internal Plugin Compile Foreach Class
  12. *
  13. * @package Smarty
  14. * @subpackage Compiler
  15. */
  16. class Smarty_Internal_Compile_Foreach 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('from', 'item');
  25. /**
  26. * Attribute definition: Overwrites base class.
  27. *
  28. * @var array
  29. * @see Smarty_Internal_CompileBase
  30. */
  31. public $optional_attributes = array('name', 'key', 'properties');
  32. /**
  33. * Attribute definition: Overwrites base class.
  34. *
  35. * @var array
  36. * @see Smarty_Internal_CompileBase
  37. */
  38. public $shorttag_order = array('from', 'item', 'key', 'name');
  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 = 'foreach';
  51. /**
  52. * Valid properties of $smarty.foreach.name.xxx variable
  53. *
  54. * @var array
  55. */
  56. public $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total');
  57. /**
  58. * Valid properties of $item@xxx variable
  59. *
  60. * @var array
  61. */
  62. public $itemProperties = array('first', 'last', 'index', 'iteration', 'show', 'total', 'key');
  63. /**
  64. * Flag if tag had name attribute
  65. *
  66. * @var bool
  67. */
  68. public $isNamed = false;
  69. /**
  70. * Compiles code for the {foreach} tag
  71. *
  72. * @param array $args array with attributes from parser
  73. * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
  74. *
  75. * @return string compiled code
  76. * @throws \SmartyCompilerException
  77. * @throws \SmartyException
  78. */
  79. public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
  80. {
  81. $compiler->loopNesting++;
  82. // init
  83. $this->isNamed = false;
  84. // check and get attributes
  85. $_attr = $this->getAttributes($compiler, $args);
  86. $from = $_attr[ 'from' ];
  87. $item = $compiler->getId($_attr[ 'item' ]);
  88. if ($item === false) {
  89. $item = $compiler->getVariableName($_attr[ 'item' ]);
  90. }
  91. $key = $name = null;
  92. $attributes = array('item' => $item);
  93. if (isset($_attr[ 'key' ])) {
  94. $key = $compiler->getId($_attr[ 'key' ]);
  95. if ($key === false) {
  96. $key = $compiler->getVariableName($_attr[ 'key' ]);
  97. }
  98. $attributes[ 'key' ] = $key;
  99. }
  100. if (isset($_attr[ 'name' ])) {
  101. $this->isNamed = true;
  102. $name = $attributes[ 'name' ] = $compiler->getId($_attr[ 'name' ]);
  103. }
  104. foreach ($attributes as $a => $v) {
  105. if ($v === false) {
  106. $compiler->trigger_template_error("'{$a}' attribute/variable has illegal value", null, true);
  107. }
  108. }
  109. $fromName = $compiler->getVariableName($_attr[ 'from' ]);
  110. if ($fromName) {
  111. foreach (array('item', 'key') as $a) {
  112. if (isset($attributes[ $a ]) && $attributes[ $a ] === $fromName) {
  113. $compiler->trigger_template_error(
  114. "'{$a}' and 'from' may not have same variable name '{$fromName}'",
  115. null,
  116. true
  117. );
  118. }
  119. }
  120. }
  121. $itemVar = "\$_smarty_tpl->tpl_vars['{$item}']";
  122. $local = '$__foreach_' . $attributes[ 'item' ] . '_' . $this->counter++ . '_';
  123. // search for used tag attributes
  124. $itemAttr = array();
  125. $namedAttr = array();
  126. $this->scanForProperties($attributes, $compiler);
  127. if (!empty($this->matchResults[ 'item' ])) {
  128. $itemAttr = $this->matchResults[ 'item' ];
  129. }
  130. if (!empty($this->matchResults[ 'named' ])) {
  131. $namedAttr = $this->matchResults[ 'named' ];
  132. }
  133. if (isset($_attr[ 'properties' ]) && preg_match_all('/[\'](.*?)[\']/', $_attr[ 'properties' ], $match)) {
  134. foreach ($match[ 1 ] as $prop) {
  135. if (in_array($prop, $this->itemProperties)) {
  136. $itemAttr[ $prop ] = true;
  137. } else {
  138. $compiler->trigger_template_error("Invalid property '{$prop}'", null, true);
  139. }
  140. }
  141. if ($this->isNamed) {
  142. foreach ($match[ 1 ] as $prop) {
  143. if (in_array($prop, $this->nameProperties)) {
  144. $nameAttr[ $prop ] = true;
  145. } else {
  146. $compiler->trigger_template_error("Invalid property '{$prop}'", null, true);
  147. }
  148. }
  149. }
  150. }
  151. if (isset($itemAttr[ 'first' ])) {
  152. $itemAttr[ 'index' ] = true;
  153. }
  154. if (isset($namedAttr[ 'first' ])) {
  155. $namedAttr[ 'index' ] = true;
  156. }
  157. if (isset($namedAttr[ 'last' ])) {
  158. $namedAttr[ 'iteration' ] = true;
  159. $namedAttr[ 'total' ] = true;
  160. }
  161. if (isset($itemAttr[ 'last' ])) {
  162. $itemAttr[ 'iteration' ] = true;
  163. $itemAttr[ 'total' ] = true;
  164. }
  165. if (isset($namedAttr[ 'show' ])) {
  166. $namedAttr[ 'total' ] = true;
  167. }
  168. if (isset($itemAttr[ 'show' ])) {
  169. $itemAttr[ 'total' ] = true;
  170. }
  171. $keyTerm = '';
  172. if (isset($attributes[ 'key' ])) {
  173. $keyTerm = "\$_smarty_tpl->tpl_vars['{$key}']->value => ";
  174. }
  175. if (isset($itemAttr[ 'key' ])) {
  176. $keyTerm = "{$itemVar}->key => ";
  177. }
  178. if ($this->isNamed) {
  179. $foreachVar = "\$_smarty_tpl->tpl_vars['__smarty_foreach_{$attributes['name']}']";
  180. }
  181. $needTotal = isset($itemAttr[ 'total' ]);
  182. // Register tag
  183. $this->openTag(
  184. $compiler,
  185. 'foreach',
  186. array('foreach', $compiler->nocache, $local, $itemVar, empty($itemAttr) ? 1 : 2)
  187. );
  188. // maybe nocache because of nocache variables
  189. $compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
  190. // generate output code
  191. $output = "<?php\n";
  192. $output .= "\$_from = \$_smarty_tpl->smarty->ext->_foreach->init(\$_smarty_tpl, $from, " .
  193. var_export($item, true);
  194. if ($name || $needTotal || $key) {
  195. $output .= ', ' . var_export($needTotal, true);
  196. }
  197. if ($name || $key) {
  198. $output .= ', ' . var_export($key, true);
  199. }
  200. if ($name) {
  201. $output .= ', ' . var_export($name, true) . ', ' . var_export($namedAttr, true);
  202. }
  203. $output .= ");\n";
  204. if (isset($itemAttr[ 'show' ])) {
  205. $output .= "{$itemVar}->show = ({$itemVar}->total > 0);\n";
  206. }
  207. if (isset($itemAttr[ 'iteration' ])) {
  208. $output .= "{$itemVar}->iteration = 0;\n";
  209. }
  210. if (isset($itemAttr[ 'index' ])) {
  211. $output .= "{$itemVar}->index = -1;\n";
  212. }
  213. $output .= "{$itemVar}->do_else = true;\n";
  214. $output .= "if (\$_from !== null) foreach (\$_from as {$keyTerm}{$itemVar}->value) {\n";
  215. $output .= "{$itemVar}->do_else = false;\n";
  216. if (isset($attributes[ 'key' ]) && isset($itemAttr[ 'key' ])) {
  217. $output .= "\$_smarty_tpl->tpl_vars['{$key}']->value = {$itemVar}->key;\n";
  218. }
  219. if (isset($itemAttr[ 'iteration' ])) {
  220. $output .= "{$itemVar}->iteration++;\n";
  221. }
  222. if (isset($itemAttr[ 'index' ])) {
  223. $output .= "{$itemVar}->index++;\n";
  224. }
  225. if (isset($itemAttr[ 'first' ])) {
  226. $output .= "{$itemVar}->first = !{$itemVar}->index;\n";
  227. }
  228. if (isset($itemAttr[ 'last' ])) {
  229. $output .= "{$itemVar}->last = {$itemVar}->iteration === {$itemVar}->total;\n";
  230. }
  231. if (isset($foreachVar)) {
  232. if (isset($namedAttr[ 'iteration' ])) {
  233. $output .= "{$foreachVar}->value['iteration']++;\n";
  234. }
  235. if (isset($namedAttr[ 'index' ])) {
  236. $output .= "{$foreachVar}->value['index']++;\n";
  237. }
  238. if (isset($namedAttr[ 'first' ])) {
  239. $output .= "{$foreachVar}->value['first'] = !{$foreachVar}->value['index'];\n";
  240. }
  241. if (isset($namedAttr[ 'last' ])) {
  242. $output .= "{$foreachVar}->value['last'] = {$foreachVar}->value['iteration'] === {$foreachVar}->value['total'];\n";
  243. }
  244. }
  245. if (!empty($itemAttr)) {
  246. $output .= "{$local}saved = {$itemVar};\n";
  247. }
  248. $output .= '?>';
  249. return $output;
  250. }
  251. /**
  252. * Compiles code for to restore saved template variables
  253. *
  254. * @param int $levels number of levels to restore
  255. *
  256. * @return string compiled code
  257. */
  258. public function compileRestore($levels)
  259. {
  260. return "\$_smarty_tpl->smarty->ext->_foreach->restore(\$_smarty_tpl, {$levels});";
  261. }
  262. }
  263. /**
  264. * Smarty Internal Plugin Compile Foreachelse Class
  265. *
  266. * @package Smarty
  267. * @subpackage Compiler
  268. */
  269. class Smarty_Internal_Compile_Foreachelse extends Smarty_Internal_CompileBase
  270. {
  271. /**
  272. * Compiles code for the {foreachelse} tag
  273. *
  274. * @param array $args array with attributes from parser
  275. * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
  276. *
  277. * @return string compiled code
  278. */
  279. public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
  280. {
  281. // check and get attributes
  282. $_attr = $this->getAttributes($compiler, $args);
  283. list($openTag, $nocache, $local, $itemVar, $restore) = $this->closeTag($compiler, array('foreach'));
  284. $this->openTag($compiler, 'foreachelse', array('foreachelse', $nocache, $local, $itemVar, 0));
  285. $output = "<?php\n";
  286. if ($restore === 2) {
  287. $output .= "{$itemVar} = {$local}saved;\n";
  288. }
  289. $output .= "}\nif ({$itemVar}->do_else) {\n?>";
  290. return $output;
  291. }
  292. }
  293. /**
  294. * Smarty Internal Plugin Compile Foreachclose Class
  295. *
  296. * @package Smarty
  297. * @subpackage Compiler
  298. */
  299. class Smarty_Internal_Compile_Foreachclose extends Smarty_Internal_CompileBase
  300. {
  301. /**
  302. * Compiles code for the {/foreach} tag
  303. *
  304. * @param array $args array with attributes from parser
  305. * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
  306. *
  307. * @return string compiled code
  308. * @throws \SmartyCompilerException
  309. */
  310. public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
  311. {
  312. $compiler->loopNesting--;
  313. // must endblock be nocache?
  314. if ($compiler->nocache) {
  315. $compiler->tag_nocache = true;
  316. }
  317. list(
  318. $openTag, $compiler->nocache, $local, $itemVar, $restore
  319. ) = $this->closeTag($compiler, array('foreach', 'foreachelse'));
  320. $output = "<?php\n";
  321. if ($restore === 2) {
  322. $output .= "{$itemVar} = {$local}saved;\n";
  323. }
  324. $output .= "}\n";
  325. /* @var Smarty_Internal_Compile_Foreach $foreachCompiler */
  326. $foreachCompiler = $compiler->getTagCompiler('foreach');
  327. $output .= $foreachCompiler->compileRestore(1);
  328. $output .= "?>";
  329. return $output;
  330. }
  331. }