您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

smarty_internal_compile_foreach.php 11KB

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