Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

smarty_internal_compile_foreach.php 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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');
  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. * @param array $parameter array with compilation parameter
  75. *
  76. * @return string compiled code
  77. * @throws \SmartyCompilerException
  78. */
  79. public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
  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. $attributes = array('item' => $item);
  92. if (isset($_attr['key'])) {
  93. $key = $compiler->getId($_attr['key']);
  94. if ($key === false) {
  95. $key = $compiler->getVariableName($_attr['key']);
  96. }
  97. $attributes['key'] = $key;
  98. }
  99. if (isset($_attr['name'])) {
  100. $this->isNamed = true;
  101. $attributes['name'] = $compiler->getId($_attr['name']);
  102. }
  103. foreach ($attributes as $a => $v) {
  104. if ($v === false) {
  105. $compiler->trigger_template_error("'{$a}' attribute/variable has illegal value", null, true);
  106. }
  107. }
  108. $fromName = $compiler->getVariableName($_attr['from']);
  109. if ($fromName) {
  110. foreach (array('item', 'key') as $a) {
  111. if (isset($attributes[$a]) && $attributes[$a] == $fromName) {
  112. $compiler->trigger_template_error("'{$a}' and 'from' may not have same variable name '{$fromName}'",
  113. null, true);
  114. }
  115. }
  116. }
  117. $itemVar = "\$_smarty_tpl->tpl_vars['{$item}']";
  118. $local = '$__foreach_' . (isset($attributes['name']) ? $attributes['name'] : $attributes['item']) . '_' .
  119. $this->counter ++ . '_';
  120. $needIteration = false;
  121. // search for used tag attributes
  122. $itemAttr = array();
  123. $namedAttr = array();
  124. $this->scanForProperties($attributes, $compiler);
  125. if (!empty($this->matchResults['item'])) {
  126. $itemAttr = $this->matchResults['item'];
  127. }
  128. if (!empty($this->matchResults['named'])) {
  129. $namedAttr = $this->matchResults['named'];
  130. }
  131. if (isset($itemAttr['last'])) {
  132. $needIteration = true;
  133. }
  134. if (isset($namedAttr['last'])) {
  135. $needIteration = true;
  136. }
  137. $keyTerm = '';
  138. if (isset($itemAttr['key'])) {
  139. $keyTerm = "{$itemVar}->key => ";
  140. } elseif (isset($attributes['key'])) {
  141. $keyTerm = "\$_smarty_tpl->tpl_vars['{$key}']->value => ";
  142. }
  143. $saveVars = array();
  144. $restoreVars = array();
  145. if ($this->isNamed) {
  146. $foreachVar = "\$_smarty_tpl->tpl_vars['__smarty_foreach_{$attributes['name']}']";
  147. if (!empty($namedAttr)) {
  148. $saveVars['saved'] = "isset({$foreachVar}) ? {$foreachVar} : false;";
  149. $restoreVars[] = "if ({$local}saved) {\n{$foreachVar} = {$local}saved;\n}\n";
  150. }
  151. }
  152. foreach (array('item', 'key') as $a) {
  153. if (isset($attributes[$a])) {
  154. $saveVars['saved_' . $a] =
  155. "isset(\$_smarty_tpl->tpl_vars['{$attributes[$a]}']) ? \$_smarty_tpl->tpl_vars['{$attributes[$a]}'] : false;";
  156. $restoreVars[] =
  157. "if ({$local}saved_{$a}) {\n\$_smarty_tpl->tpl_vars['{$attributes[$a]}'] = {$local}saved_{$a};\n}\n";
  158. }
  159. }
  160. $this->openTag($compiler, 'foreach',
  161. array('foreach', $compiler->nocache, $local, $restoreVars, $itemVar, true));
  162. // maybe nocache because of nocache variables
  163. $compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
  164. // generate output code
  165. $output = "<?php\n";
  166. $output .= "\$_from = $from;\n";
  167. $output .= "if (!is_array(\$_from) && !is_object(\$_from)) {\n";
  168. $output .= "settype(\$_from, 'array');\n";
  169. $output .= "}\n";
  170. foreach ($saveVars as $k => $code) {
  171. $output .= "{$local}{$k} = {$code}\n";
  172. }
  173. if (isset($itemAttr['show']) || isset($itemAttr['total']) || isset($namedAttr['total']) || isset($namedAttr['show']) || isset($itemAttr['last']) || isset($namedAttr['last'])) {
  174. $output .= "{$local}total = \$_smarty_tpl->smarty->ext->_foreach->count(\$_from);\n";
  175. }
  176. $output .= "{$itemVar} = new Smarty_Variable();\n";
  177. if (isset($itemAttr['show'])) {
  178. $output .= "{$itemVar}->show = ({$local}total > 0);\n";
  179. }
  180. if (isset($itemAttr['total'])) {
  181. $output .= "{$itemVar}->total= {$local}total;\n";
  182. }
  183. if ($this->isNamed) {
  184. $prop = array();
  185. if (isset($namedAttr['total'])) {
  186. $prop['total'] = "'total' => {$local}total";
  187. }
  188. if (isset($namedAttr['iteration'])) {
  189. $prop['iteration'] = "'iteration' => 0";
  190. }
  191. if (isset($namedAttr['index'])) {
  192. $prop['index'] = "'index' => -1";
  193. }
  194. if (isset($namedAttr['show'])) {
  195. $prop['show'] = "'show' => ({$local}total > 0)";
  196. }
  197. if (!empty($namedAttr)) {
  198. $_vars = 'array(' . join(', ', $prop) . ')';
  199. $output .= "{$foreachVar} = new Smarty_Variable({$_vars});\n";
  200. }
  201. }
  202. if (isset($attributes['key'])) {
  203. $output .= "\$_smarty_tpl->tpl_vars['{$key}'] = new Smarty_Variable();\n";
  204. }
  205. if (isset($namedAttr['first']) || isset($itemAttr['first'])) {
  206. $output .= "{$local}first = true;\n";
  207. }
  208. if (isset($itemAttr['iteration'])) {
  209. $output .= "{$itemVar}->iteration=0;\n";
  210. }
  211. if (isset($itemAttr['index'])) {
  212. $output .= "{$itemVar}->index=-1;\n";
  213. }
  214. if ($needIteration) {
  215. $output .= "{$local}iteration=0;\n";
  216. }
  217. $output .= "{$itemVar}->_loop = false;\n";
  218. $output .= "foreach (\$_from as {$keyTerm}{$itemVar}->value) {\n";
  219. $output .= "{$itemVar}->_loop = true;\n";
  220. if (isset($attributes['key']) && isset($itemAttr['key'])) {
  221. $output .= "\$_smarty_tpl->tpl_vars['{$key}']->value = {$itemVar}->key;\n";
  222. }
  223. if (isset($itemAttr['iteration'])) {
  224. $output .= "{$itemVar}->iteration++;\n";
  225. }
  226. if (isset($itemAttr['index'])) {
  227. $output .= "{$itemVar}->index++;\n";
  228. }
  229. if ($needIteration) {
  230. $output .= "{$local}iteration++;\n";
  231. }
  232. if (isset($itemAttr['first'])) {
  233. $output .= "{$itemVar}->first = {$local}first;\n";
  234. }
  235. if (isset($itemAttr['last'])) {
  236. $output .= "{$itemVar}->last = {$local}iteration == {$local}total;\n";
  237. }
  238. if ($this->isNamed) {
  239. if (isset($namedAttr['iteration'])) {
  240. $output .= "{$foreachVar}->value['iteration']++;\n";
  241. }
  242. if (isset($namedAttr['index'])) {
  243. $output .= "{$foreachVar}->value['index']++;\n";
  244. }
  245. if (isset($namedAttr['first'])) {
  246. $output .= "{$foreachVar}->value['first'] = {$local}first;\n";
  247. }
  248. if (isset($namedAttr['last'])) {
  249. $output .= "{$foreachVar}->value['last'] = {$local}iteration == {$local}total;\n";
  250. }
  251. }
  252. if (isset($namedAttr['first']) || isset($itemAttr['first'])) {
  253. $output .= "{$local}first = false;\n";
  254. }
  255. $output .= "{$local}saved_local_item = {$itemVar};\n";
  256. $output .= "?>";
  257. return $output;
  258. }
  259. }
  260. /**
  261. * Smarty Internal Plugin Compile Foreachelse Class
  262. *
  263. * @package Smarty
  264. * @subpackage Compiler
  265. */
  266. class Smarty_Internal_Compile_Foreachelse extends Smarty_Internal_CompileBase
  267. {
  268. /**
  269. * Compiles code for the {foreachelse} tag
  270. *
  271. * @param array $args array with attributes from parser
  272. * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
  273. * @param array $parameter array with compilation parameter
  274. *
  275. * @return string compiled code
  276. */
  277. public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
  278. {
  279. // check and get attributes
  280. $_attr = $this->getAttributes($compiler, $args);
  281. list($openTag, $nocache, $local, $restoreVars, $itemVar, $foo) = $this->closeTag($compiler, array('foreach'));
  282. $this->openTag($compiler, 'foreachelse', array('foreachelse', $nocache, $local, $restoreVars, $itemVar, false));
  283. $output = "<?php\n";
  284. $output .= "{$itemVar} = {$local}saved_local_item;\n";
  285. $output .= "}\n";
  286. $output .= "if (!{$itemVar}->_loop) {\n?>";
  287. return $output;
  288. }
  289. }
  290. /**
  291. * Smarty Internal Plugin Compile Foreachclose Class
  292. *
  293. * @package Smarty
  294. * @subpackage Compiler
  295. */
  296. class Smarty_Internal_Compile_Foreachclose extends Smarty_Internal_CompileBase
  297. {
  298. /**
  299. * Compiles code for the {/foreach} tag
  300. *
  301. * @param array $args array with attributes from parser
  302. * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
  303. * @param array $parameter array with compilation parameter
  304. *
  305. * @return string compiled code
  306. */
  307. public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
  308. {
  309. $compiler->loopNesting --;
  310. // must endblock be nocache?
  311. if ($compiler->nocache) {
  312. $compiler->tag_nocache = true;
  313. }
  314. list($openTag, $compiler->nocache, $local, $restoreVars, $itemVar, $restore) =
  315. $this->closeTag($compiler, array('foreach', 'foreachelse'));
  316. $output = "<?php\n";
  317. if ($restore) {
  318. $output .= "{$itemVar} = {$local}saved_local_item;\n";
  319. }
  320. $output .= "}\n";
  321. foreach ($restoreVars as $restore) {
  322. $output .= $restore;
  323. }
  324. $output .= "?>";
  325. return $output;
  326. }
  327. }