smarty_internal_runtime_foreach.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. <?php
  2. /**
  3. * Foreach Runtime Methods count(), init(), restore()
  4. *
  5. * @package Smarty
  6. * @subpackage PluginsInternal
  7. * @author Uwe Tews
  8. *
  9. */
  10. class Smarty_Internal_Runtime_Foreach
  11. {
  12. /**
  13. * Stack of saved variables
  14. *
  15. * @var array
  16. */
  17. private $stack = array();
  18. /**
  19. * Init foreach loop
  20. * - save item and key variables, named foreach property data if defined
  21. * - init item and key variables, named foreach property data if required
  22. * - count total if required
  23. *
  24. * @param \Smarty_Internal_Template $tpl
  25. * @param mixed $from values to loop over
  26. * @param string $item variable name
  27. * @param bool $needTotal flag if we need to count values
  28. * @param null|string $key variable name
  29. * @param null|string $name of named foreach
  30. * @param array $properties of named foreach
  31. *
  32. * @return mixed $from
  33. */
  34. public function init(Smarty_Internal_Template $tpl, $from, $item, $needTotal = false, $key = null, $name = null,
  35. $properties = array())
  36. {
  37. $saveVars = array();
  38. if (!is_array($from) && !is_object($from)) {
  39. settype($from, 'array');
  40. }
  41. $total = ($needTotal || isset($properties[ 'total' ])) ? $this->count($from) : 1;
  42. if (isset($tpl->tpl_vars[ $item ])) {
  43. $saveVars[ $item ] = $tpl->tpl_vars[ $item ];
  44. }
  45. $tpl->tpl_vars[ $item ] = new Smarty_Variable(null, $tpl->isRenderingCache);
  46. if (empty($from)) {
  47. $from = null;
  48. $total = 0;
  49. if ($needTotal) {
  50. $tpl->tpl_vars[ $item ]->total = 0;
  51. }
  52. } else {
  53. if ($key) {
  54. if (isset($tpl->tpl_vars[ $key ])) {
  55. $saveVars[ $key ] = $tpl->tpl_vars[ $key ];
  56. }
  57. $tpl->tpl_vars[ $key ] = new Smarty_Variable(null, $tpl->isRenderingCache);
  58. }
  59. if ($needTotal) {
  60. $tpl->tpl_vars[ $item ]->total = $total;
  61. }
  62. }
  63. if ($name) {
  64. $namedVar = "__smarty_foreach_{$name}";
  65. if (isset($tpl->tpl_vars[ $namedVar ])) {
  66. $saveVars[ $namedVar ] = $tpl->tpl_vars[ $namedVar ];
  67. }
  68. $namedProp = array();
  69. if (isset($properties[ 'total' ])) {
  70. $namedProp[ 'total' ] = $total;
  71. }
  72. if (isset($properties[ 'iteration' ])) {
  73. $namedProp[ 'iteration' ] = 0;
  74. }
  75. if (isset($properties[ 'index' ])) {
  76. $namedProp[ 'index' ] = - 1;
  77. }
  78. if (isset($properties[ 'show' ])) {
  79. $namedProp[ 'show' ] = ($total > 0);
  80. }
  81. $tpl->tpl_vars[ $namedVar ] = new Smarty_Variable($namedProp);
  82. }
  83. $this->stack[] = $saveVars;
  84. return $from;
  85. }
  86. /**
  87. * Restore saved variables
  88. *
  89. * @param \Smarty_Internal_Template $tpl
  90. */
  91. public function restore(Smarty_Internal_Template $tpl)
  92. {
  93. foreach (array_pop($this->stack) as $k => $v) {
  94. $tpl->tpl_vars[ $k ] = $v;
  95. }
  96. }
  97. /*
  98. *
  99. * [util function] counts an array, arrayAccess/traversable or PDOStatement object
  100. *
  101. * @param mixed $value
  102. *
  103. * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0
  104. * for empty elements
  105. */
  106. public function count($value)
  107. {
  108. if (is_array($value) === true || $value instanceof Countable) {
  109. return count($value);
  110. } elseif ($value instanceof IteratorAggregate) {
  111. // Note: getIterator() returns a Traversable, not an Iterator
  112. // thus rewind() and valid() methods may not be present
  113. return iterator_count($value->getIterator());
  114. } elseif ($value instanceof Iterator) {
  115. if ($value instanceof Generator) {
  116. return 1;
  117. }
  118. return iterator_count($value);
  119. } elseif ($value instanceof PDOStatement) {
  120. return $value->rowCount();
  121. } elseif ($value instanceof Traversable) {
  122. return iterator_count($value);
  123. } elseif ($value instanceof ArrayAccess) {
  124. if ($value->offsetExists(0)) {
  125. return 1;
  126. }
  127. } elseif (is_object($value)) {
  128. return count($value);
  129. }
  130. return 0;
  131. }
  132. }