1<?php
2/**
3 * Smarty Internal Plugin Compile For
4 * Compiles the {for} {forelse} {/for} tags
5 *
6 * @package    Smarty
7 * @subpackage Compiler
8 * @author     Uwe Tews
9 */
10
11/**
12 * Smarty Internal Plugin Compile For Class
13 *
14 * @package    Smarty
15 * @subpackage Compiler
16 */
17class Smarty_Internal_Compile_For extends Smarty_Internal_CompileBase
18{
19    /**
20     * Compiles code for the {for} tag
21     * Smarty 3 does implement two different syntax's:
22     * - {for $var in $array}
23     * For looping over arrays or iterators
24     * - {for $x=0; $x<$y; $x++}
25     * For general loops
26     * The parser is generating different sets of attribute by which this compiler can
27     * determine which syntax is used.
28     *
29     * @param array  $args      array with attributes from parser
30     * @param object $compiler  compiler object
31     * @param array  $parameter array with compilation parameter
32     *
33     * @return string compiled code
34     */
35    public function compile($args, $compiler, $parameter)
36    {
37        $compiler->loopNesting++;
38        if ($parameter === 0) {
39            $this->required_attributes = array('start', 'to');
40            $this->optional_attributes = array('max', 'step');
41        } else {
42            $this->required_attributes = array('start', 'ifexp', 'var', 'step');
43            $this->optional_attributes = array();
44        }
45        $this->mapCache = array();
46        // check and get attributes
47        $_attr = $this->getAttributes($compiler, $args);
48        $output = "<?php\n";
49        if ($parameter === 1) {
50            foreach ($_attr[ 'start' ] as $_statement) {
51                if (is_array($_statement[ 'var' ])) {
52                    $var = $_statement[ 'var' ][ 'var' ];
53                    $index = $_statement[ 'var' ][ 'smarty_internal_index' ];
54                } else {
55                    $var = $_statement[ 'var' ];
56                    $index = '';
57                }
58                $output .= "\$_smarty_tpl->tpl_vars[$var] = new Smarty_Variable(null, \$_smarty_tpl->isRenderingCache);\n";
59                $output .= "\$_smarty_tpl->tpl_vars[$var]->value{$index} = {$_statement['value']};\n";
60            }
61            if (is_array($_attr[ 'var' ])) {
62                $var = $_attr[ 'var' ][ 'var' ];
63                $index = $_attr[ 'var' ][ 'smarty_internal_index' ];
64            } else {
65                $var = $_attr[ 'var' ];
66                $index = '';
67            }
68            $output .= "if ($_attr[ifexp]) {\nfor (\$_foo=true;$_attr[ifexp]; \$_smarty_tpl->tpl_vars[$var]->value{$index}$_attr[step]) {\n";
69        } else {
70            $_statement = $_attr[ 'start' ];
71            if (is_array($_statement[ 'var' ])) {
72                $var = $_statement[ 'var' ][ 'var' ];
73                $index = $_statement[ 'var' ][ 'smarty_internal_index' ];
74            } else {
75                $var = $_statement[ 'var' ];
76                $index = '';
77            }
78            $output .= "\$_smarty_tpl->tpl_vars[$var] = new Smarty_Variable(null, \$_smarty_tpl->isRenderingCache);";
79            if (isset($_attr[ 'step' ])) {
80                $output .= "\$_smarty_tpl->tpl_vars[$var]->step = $_attr[step];";
81            } else {
82                $output .= "\$_smarty_tpl->tpl_vars[$var]->step = 1;";
83            }
84            if (isset($_attr[ 'max' ])) {
85                $output .= "\$_smarty_tpl->tpl_vars[$var]->total = (int) min(ceil((\$_smarty_tpl->tpl_vars[$var]->step > 0 ? $_attr[to]+1 - ($_statement[value]) : $_statement[value]-($_attr[to])+1)/abs(\$_smarty_tpl->tpl_vars[$var]->step)),$_attr[max]);\n";
86            } else {
87                $output .= "\$_smarty_tpl->tpl_vars[$var]->total = (int) ceil((\$_smarty_tpl->tpl_vars[$var]->step > 0 ? $_attr[to]+1 - ($_statement[value]) : $_statement[value]-($_attr[to])+1)/abs(\$_smarty_tpl->tpl_vars[$var]->step));\n";
88            }
89            $output .= "if (\$_smarty_tpl->tpl_vars[$var]->total > 0) {\n";
90            $output .= "for (\$_smarty_tpl->tpl_vars[$var]->value{$index} = $_statement[value], \$_smarty_tpl->tpl_vars[$var]->iteration = 1;\$_smarty_tpl->tpl_vars[$var]->iteration <= \$_smarty_tpl->tpl_vars[$var]->total;\$_smarty_tpl->tpl_vars[$var]->value{$index} += \$_smarty_tpl->tpl_vars[$var]->step, \$_smarty_tpl->tpl_vars[$var]->iteration++) {\n";
91            $output .= "\$_smarty_tpl->tpl_vars[$var]->first = \$_smarty_tpl->tpl_vars[$var]->iteration === 1;";
92            $output .= "\$_smarty_tpl->tpl_vars[$var]->last = \$_smarty_tpl->tpl_vars[$var]->iteration === \$_smarty_tpl->tpl_vars[$var]->total;";
93        }
94        $output .= '?>';
95        $this->openTag($compiler, 'for', array('for', $compiler->nocache));
96        // maybe nocache because of nocache variables
97        $compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
98        // return compiled code
99        return $output;
100    }
101}
102
103/**
104 * Smarty Internal Plugin Compile Forelse Class
105 *
106 * @package    Smarty
107 * @subpackage Compiler
108 */
109class Smarty_Internal_Compile_Forelse extends Smarty_Internal_CompileBase
110{
111    /**
112     * Compiles code for the {forelse} tag
113     *
114     * @param array  $args      array with attributes from parser
115     * @param object $compiler  compiler object
116     * @param array  $parameter array with compilation parameter
117     *
118     * @return string compiled code
119     */
120    public function compile($args, $compiler, $parameter)
121    {
122        // check and get attributes
123        $_attr = $this->getAttributes($compiler, $args);
124        list($openTag, $nocache) = $this->closeTag($compiler, array('for'));
125        $this->openTag($compiler, 'forelse', array('forelse', $nocache));
126        return "<?php }} else { ?>";
127    }
128}
129
130/**
131 * Smarty Internal Plugin Compile Forclose Class
132 *
133 * @package    Smarty
134 * @subpackage Compiler
135 */
136class Smarty_Internal_Compile_Forclose extends Smarty_Internal_CompileBase
137{
138    /**
139     * Compiles code for the {/for} tag
140     *
141     * @param array  $args      array with attributes from parser
142     * @param object $compiler  compiler object
143     * @param array  $parameter array with compilation parameter
144     *
145     * @return string compiled code
146     */
147    public function compile($args, $compiler, $parameter)
148    {
149        $compiler->loopNesting--;
150        // check and get attributes
151        $_attr = $this->getAttributes($compiler, $args);
152        // must endblock be nocache?
153        if ($compiler->nocache) {
154            $compiler->tag_nocache = true;
155        }
156        list($openTag, $compiler->nocache) = $this->closeTag($compiler, array('for', 'forelse'));
157        $output = "<?php }\n";
158        if ($openTag !== 'forelse') {
159            $output .= "}\n";
160        }
161        $output .= "?>";
162        return $output;
163    }
164}
165