1: <?php
2:
3: /**
4: * Foreach Runtime Methods count(), init(), restore()
5: *
6: * @package Smarty
7: * @subpackage PluginsInternal
8: * @author Uwe Tews
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: /**
20: * Init foreach loop
21: * - save item and key variables, named foreach property data if defined
22: * - init item and key variables, named foreach property data if required
23: * - count total if required
24: *
25: * @param \Smarty_Internal_Template $tpl
26: * @param mixed $from values to loop over
27: * @param string $item variable name
28: * @param bool $needTotal flag if we need to count values
29: * @param null|string $key variable name
30: * @param null|string $name of named foreach
31: * @param array $properties of named foreach
32: *
33: * @return mixed $from
34: */
35: public function init(
36: Smarty_Internal_Template $tpl,
37: $from,
38: $item,
39: $needTotal = false,
40: $key = null,
41: $name = null,
42: $properties = array()
43: ) {
44: $needTotal = $needTotal || isset($properties[ 'total' ]);
45: $saveVars = array();
46: $total = null;
47: if (!is_array($from)) {
48: if (is_object($from)) {
49: if ($needTotal) {
50: $total = $this->count($from);
51: }
52: } else {
53: settype($from, 'array');
54: }
55: }
56: if (!isset($total)) {
57: $total = empty($from) ? 0 : ($needTotal ? count($from) : 1);
58: }
59: if (isset($tpl->tpl_vars[ $item ])) {
60: $saveVars[ 'item' ] = array(
61: $item,
62: $tpl->tpl_vars[ $item ]
63: );
64: }
65: $tpl->tpl_vars[ $item ] = new Smarty_Variable(null, $tpl->isRenderingCache);
66: if ($total === 0) {
67: $from = null;
68: } else {
69: if ($key) {
70: if (isset($tpl->tpl_vars[ $key ])) {
71: $saveVars[ 'key' ] = array(
72: $key,
73: $tpl->tpl_vars[ $key ]
74: );
75: }
76: $tpl->tpl_vars[ $key ] = new Smarty_Variable(null, $tpl->isRenderingCache);
77: }
78: }
79: if ($needTotal) {
80: $tpl->tpl_vars[ $item ]->total = $total;
81: }
82: if ($name) {
83: $namedVar = "__smarty_foreach_{$name}";
84: if (isset($tpl->tpl_vars[ $namedVar ])) {
85: $saveVars[ 'named' ] = array(
86: $namedVar,
87: $tpl->tpl_vars[ $namedVar ]
88: );
89: }
90: $namedProp = array();
91: if (isset($properties[ 'total' ])) {
92: $namedProp[ 'total' ] = $total;
93: }
94: if (isset($properties[ 'iteration' ])) {
95: $namedProp[ 'iteration' ] = 0;
96: }
97: if (isset($properties[ 'index' ])) {
98: $namedProp[ 'index' ] = -1;
99: }
100: if (isset($properties[ 'show' ])) {
101: $namedProp[ 'show' ] = ($total > 0);
102: }
103: $tpl->tpl_vars[ $namedVar ] = new Smarty_Variable($namedProp);
104: }
105: $this->stack[] = $saveVars;
106: return $from;
107: }
108:
109: /**
110: * [util function] counts an array, arrayAccess/traversable or PDOStatement object
111: *
112: * @param mixed $value
113: *
114: * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0
115: * for empty elements
116: */
117: public function count($value)
118: {
119: if ($value instanceof IteratorAggregate) {
120: // Note: getIterator() returns a Traversable, not an Iterator
121: // thus rewind() and valid() methods may not be present
122: return iterator_count($value->getIterator());
123: } elseif ($value instanceof Iterator) {
124: return $value instanceof Generator ? 1 : iterator_count($value);
125: } elseif ($value instanceof Countable) {
126: return count($value);
127: } elseif ($value instanceof PDOStatement) {
128: return $value->rowCount();
129: } elseif ($value instanceof Traversable) {
130: return iterator_count($value);
131: }
132: return count((array)$value);
133: }
134:
135: /**
136: * Restore saved variables
137: *
138: * will be called by {break n} or {continue n} for the required number of levels
139: *
140: * @param \Smarty_Internal_Template $tpl
141: * @param int $levels number of levels
142: */
143: public function restore(Smarty_Internal_Template $tpl, $levels = 1)
144: {
145: while ($levels) {
146: $saveVars = array_pop($this->stack);
147: if (!empty($saveVars)) {
148: if (isset($saveVars[ 'item' ])) {
149: $item = &$saveVars[ 'item' ];
150: $tpl->tpl_vars[ $item[ 0 ] ]->value = $item[ 1 ]->value;
151: }
152: if (isset($saveVars[ 'key' ])) {
153: $tpl->tpl_vars[ $saveVars[ 'key' ][ 0 ] ] = $saveVars[ 'key' ][ 1 ];
154: }
155: if (isset($saveVars[ 'named' ])) {
156: $tpl->tpl_vars[ $saveVars[ 'named' ][ 0 ] ] = $saveVars[ 'named' ][ 1 ];
157: }
158: }
159: $levels--;
160: }
161: }
162: }
163: