1<?php 2 3/** 4 * Foreach Runtime Methods count(), init(), restore() 5 * 6 * @package Smarty 7 * @subpackage PluginsInternal 8 * @author Uwe Tews 9 */ 10class 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