Completed
Branch master (e379bd)
by Pierre-Henry
33:06
created

Smarty_Internal_Runtime_Foreach::count()   B

Complexity

Conditions 9
Paths 9

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 14
nc 9
nop 1
dl 0
loc 19
rs 7.756
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Foreach Runtime Methods count(), init(), restore()
5
 *
6
 * @package    Smarty
7
 * @subpackage PluginsInternal
8
 * @author     Uwe Tews
9
 *
10
 */
11
class Smarty_Internal_Runtime_Foreach
12
{
13
14
    /**
15
     * Stack of saved variables
16
     *
17
     * @var array
18
     */
19
    private $stack = array();
20
21
    /**
22
     * Init foreach loop
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
26
     *
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
34
     *
35
     * @return mixed $from
36
     */
37
    public function init(Smarty_Internal_Template $tpl, $from, $item, $needTotal = false, $key = null, $name = null,
38
                         $properties = array())
39
    {
40
        $saveVars = array();
41
        $total = null;
42
        if (!is_array($from)) {
43
            if (is_object($from)) {
44
                $total = $this->count($from);
45
            } else {
46
                settype($from, 'array');
47
            }
48
        }
49
        if (!isset($total)) {
50
            $total = empty($from) ? 0 : (($needTotal || isset($properties[ 'total' ])) ? count($from) : 1);
51
        }
52
        if (isset($tpl->tpl_vars[ $item ])) {
53
            $saveVars[ 'item' ] = array($item, $tpl->tpl_vars[ $item ]);
54
        }
55
        $tpl->tpl_vars[ $item ] = new Smarty_Variable(null, $tpl->isRenderingCache);
56
        if ($total === 0) {
57
            $from = null;
58
        } else {
59
            if ($key) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $key of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
60
                if (isset($tpl->tpl_vars[ $key ])) {
61
                    $saveVars[ 'key' ] = array($key, $tpl->tpl_vars[ $key ]);
62
                }
63
                $tpl->tpl_vars[ $key ] = new Smarty_Variable(null, $tpl->isRenderingCache);
64
            }
65
        }
66
        if ($needTotal) {
67
            $tpl->tpl_vars[ $item ]->total = $total;
0 ignored issues
show
Bug introduced by
The property total does not seem to exist in Smarty_Variable.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
68
        }
69
        if ($name) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $name of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
70
            $namedVar = "__smarty_foreach_{$name}";
71
            if (isset($tpl->tpl_vars[ $namedVar ])) {
72
                $saveVars[ 'named' ] = array($namedVar, $tpl->tpl_vars[ $namedVar ]);
73
            }
74
            $namedProp = array();
75
            if (isset($properties[ 'total' ])) {
76
                $namedProp[ 'total' ] = $total;
77
            }
78
            if (isset($properties[ 'iteration' ])) {
79
                $namedProp[ 'iteration' ] = 0;
80
            }
81
            if (isset($properties[ 'index' ])) {
82
                $namedProp[ 'index' ] = - 1;
83
            }
84
            if (isset($properties[ 'show' ])) {
85
                $namedProp[ 'show' ] = ($total > 0);
86
            }
87
            $tpl->tpl_vars[ $namedVar ] = new Smarty_Variable($namedProp);
88
        }
89
        $this->stack[] = $saveVars;
90
        return $from;
91
    }
92
93
    /**
94
     * Restore saved variables
95
     *
96
     * will be called by {break n} or {continue n} for the required number of levels
97
     *
98
     * @param \Smarty_Internal_Template $tpl
99
     * @param int                       $levels number of levels
100
     */
101
    public function restore(Smarty_Internal_Template $tpl, $levels = 1)
102
    {
103
        while ($levels) {
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;
109
                }
110
                if (isset($saveVars[ 'key' ])) {
111
                    $tpl->tpl_vars[ $saveVars[ 'key' ][ 0 ] ] = $saveVars[ 'key' ][ 1 ];
112
                }
113
                if (isset($saveVars[ 'named' ])) {
114
                    $tpl->tpl_vars[ $saveVars[ 'named' ][ 0 ] ] = $saveVars[ 'named' ][ 1 ];
115
                }
116
            }
117
            $levels--;
118
        }
119
    }
120
121
    /*
122
    *
123
     * [util function] counts an array, arrayAccess/traversable or PDOStatement object
124
     *
125
     * @param  mixed $value
126
     *
127
     * @return int   the count for arrays and objects that implement countable, 1 for other objects that don't, and 0
128
     *               for empty elements
129
     */
130
    public function count($value)
131
    {
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;
146
        }
147
        return count((array) $value);
148
    }
149
}
150