4 * Foreach Runtime Methods count(), init(), restore()
7 * @subpackage PluginsInternal
11 class Smarty_Internal_Runtime_Foreach
15 * Stack of saved variables
19 private $stack = array();
23 * - save item and key variables, named foreach property data if defined
24 * - init item and key variables, named foreach property data if required
25 * - count total if required
27 * @param \Smarty_Internal_Template $tpl
28 * @param mixed $from values to loop over
29 * @param string $item variable name
30 * @param bool $needTotal flag if we need to count values
31 * @param null|string $key variable name
32 * @param null|string $name of named foreach
33 * @param array $properties of named foreach
37 public function init(Smarty_Internal_Template $tpl, $from, $item, $needTotal = false, $key = null, $name = null,
38 $properties = array())
42 if (!is_array($from)) {
43 if (is_object($from)) {
44 $total = $this->count($from);
46 settype($from, 'array');
50 $total = empty($from) ? 0 : (($needTotal || isset($properties[ 'total' ])) ? count($from) : 1);
52 if (isset($tpl->tpl_vars[ $item ])) {
53 $saveVars[ 'item' ] = array($item, $tpl->tpl_vars[ $item ]);
55 $tpl->tpl_vars[ $item ] = new Smarty_Variable(null, $tpl->isRenderingCache);
60 if (isset($tpl->tpl_vars[ $key ])) {
61 $saveVars[ 'key' ] = array($key, $tpl->tpl_vars[ $key ]);
63 $tpl->tpl_vars[ $key ] = new Smarty_Variable(null, $tpl->isRenderingCache);
67 $tpl->tpl_vars[ $item ]->total = $total;
70 $namedVar = "__smarty_foreach_{$name}";
71 if (isset($tpl->tpl_vars[ $namedVar ])) {
72 $saveVars[ 'named' ] = array($namedVar, $tpl->tpl_vars[ $namedVar ]);
75 if (isset($properties[ 'total' ])) {
76 $namedProp[ 'total' ] = $total;
78 if (isset($properties[ 'iteration' ])) {
79 $namedProp[ 'iteration' ] = 0;
81 if (isset($properties[ 'index' ])) {
82 $namedProp[ 'index' ] = - 1;
84 if (isset($properties[ 'show' ])) {
85 $namedProp[ 'show' ] = ($total > 0);
87 $tpl->tpl_vars[ $namedVar ] = new Smarty_Variable($namedProp);
89 $this->stack[] = $saveVars;
94 * Restore saved variables
96 * will be called by {break n} or {continue n} for the required number of levels
98 * @param \Smarty_Internal_Template $tpl
99 * @param int $levels number of levels
101 public function restore(Smarty_Internal_Template $tpl, $levels = 1)
104 $saveVars = array_pop($this->stack);
105 if (!empty($saveVars)) {
106 if (isset($saveVars[ 'item' ])) {
107 $item = &$saveVars[ 'item' ];
108 $tpl->tpl_vars[ $item[ 0 ] ]->value = $item[ 1 ]->value;
110 if (isset($saveVars[ 'key' ])) {
111 $tpl->tpl_vars[ $saveVars[ 'key' ][ 0 ] ] = $saveVars[ 'key' ][ 1 ];
113 if (isset($saveVars[ 'named' ])) {
114 $tpl->tpl_vars[ $saveVars[ 'named' ][ 0 ] ] = $saveVars[ 'named' ][ 1 ];
123 * [util function] counts an array, arrayAccess/traversable or PDOStatement object
125 * @param mixed $value
127 * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0
130 public function count($value)
132 if ($value instanceof Countable) {
133 return count($value);
134 } elseif ($value instanceof IteratorAggregate) {
135 // Note: getIterator() returns a Traversable, not an Iterator
136 // thus rewind() and valid() methods may not be present
137 return iterator_count($value->getIterator());
138 } elseif ($value instanceof Iterator) {
139 return $value instanceof Generator ? 1 : iterator_count($value);
140 } elseif ($value instanceof PDOStatement) {
141 return $value->rowCount();
142 } elseif ($value instanceof Traversable) {
143 return iterator_count($value);
144 } elseif ($value instanceof ArrayAccess) {
145 return $value->offsetExists(0) ? 1 : 0;
147 return count((array) $value);