Subversion Repositories ALCASAR

Rev

Details | Last modification | View Log

Rev Author Line No. Line
2809 rexy 1
<?php
2
/**
3
 * Smarty Internal Plugin Compile Foreach
4
 * Compiles the {foreach} {foreachelse} {/foreach} tags
5
 *
6
 * @package    Smarty
7
 * @subpackage Compiler
8
 * @author     Uwe Tews
9
 */
10
 
11
/**
12
 * Smarty Internal Plugin Compile Foreach Class
13
 *
14
 * @package    Smarty
15
 * @subpackage Compiler
16
 */
17
class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_ForeachSection
18
{
19
    /**
20
     * Attribute definition: Overwrites base class.
21
     *
22
     * @var array
23
     * @see Smarty_Internal_CompileBase
24
     */
25
    public $required_attributes = array('from', 'item');
26
 
27
    /**
28
     * Attribute definition: Overwrites base class.
29
     *
30
     * @var array
31
     * @see Smarty_Internal_CompileBase
32
     */
33
    public $optional_attributes = array('name', 'key', 'properties');
34
 
35
    /**
36
     * Attribute definition: Overwrites base class.
37
     *
38
     * @var array
39
     * @see Smarty_Internal_CompileBase
40
     */
41
    public $shorttag_order = array('from', 'item', 'key', 'name');
42
 
43
    /**
44
     * counter
45
     *
46
     * @var int
47
     */
48
    public $counter = 0;
49
 
50
    /**
51
     * Name of this tag
52
     *
53
     * @var string
54
     */
55
    public $tagName = 'foreach';
56
 
57
    /**
58
     * Valid properties of $smarty.foreach.name.xxx variable
59
     *
60
     * @var array
61
     */
62
    public $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total');
63
 
64
    /**
65
     * Valid properties of $item@xxx variable
66
     *
67
     * @var array
68
     */
69
    public $itemProperties = array('first', 'last', 'index', 'iteration', 'show', 'total', 'key');
70
 
71
    /**
72
     * Flag if tag had name attribute
73
     *
74
     * @var bool
75
     */
76
    public $isNamed = false;
77
 
78
    /**
79
     * Compiles code for the {foreach} tag
80
     *
81
     * @param array                                 $args     array with attributes from parser
82
     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
83
     *
84
     * @return string compiled code
85
     * @throws \SmartyCompilerException
86
     * @throws \SmartyException
87
     */
88
    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
89
    {
90
        $compiler->loopNesting++;
91
        // init
92
        $this->isNamed = false;
93
        // check and get attributes
94
        $_attr = $this->getAttributes($compiler, $args);
95
        $from = $_attr[ 'from' ];
96
        $item = $compiler->getId($_attr[ 'item' ]);
97
        if ($item === false) {
98
            $item = $compiler->getVariableName($_attr[ 'item' ]);
99
        }
100
        $key = $name = null;
101
        $attributes = array('item' => $item);
102
        if (isset($_attr[ 'key' ])) {
103
            $key = $compiler->getId($_attr[ 'key' ]);
104
            if ($key === false) {
105
                $key = $compiler->getVariableName($_attr[ 'key' ]);
106
            }
107
            $attributes[ 'key' ] = $key;
108
        }
109
        if (isset($_attr[ 'name' ])) {
110
            $this->isNamed = true;
111
            $name = $attributes[ 'name' ] = $compiler->getId($_attr[ 'name' ]);
112
        }
113
        foreach ($attributes as $a => $v) {
114
            if ($v === false) {
115
                $compiler->trigger_template_error("'{$a}' attribute/variable has illegal value", null, true);
116
            }
117
        }
118
        $fromName = $compiler->getVariableName($_attr[ 'from' ]);
119
        if ($fromName) {
120
            foreach (array('item', 'key') as $a) {
121
                if (isset($attributes[ $a ]) && $attributes[ $a ] === $fromName) {
122
                    $compiler->trigger_template_error(
123
                        "'{$a}' and 'from' may not have same variable name '{$fromName}'",
124
                        null,
125
                        true
126
                    );
127
                }
128
            }
129
        }
130
        $itemVar = "\$_smarty_tpl->tpl_vars['{$item}']";
131
        $local = '$__foreach_' . $attributes[ 'item' ] . '_' . $this->counter++ . '_';
132
        // search for used tag attributes
133
        $itemAttr = array();
134
        $namedAttr = array();
135
        $this->scanForProperties($attributes, $compiler);
136
        if (!empty($this->matchResults[ 'item' ])) {
137
            $itemAttr = $this->matchResults[ 'item' ];
138
        }
139
        if (!empty($this->matchResults[ 'named' ])) {
140
            $namedAttr = $this->matchResults[ 'named' ];
141
        }
142
        if (isset($_attr[ 'properties' ]) && preg_match_all('/[\'](.*?)[\']/', $_attr[ 'properties' ], $match)) {
143
            foreach ($match[ 1 ] as $prop) {
144
                if (in_array($prop, $this->itemProperties)) {
145
                    $itemAttr[ $prop ] = true;
146
                } else {
147
                    $compiler->trigger_template_error("Invalid property '{$prop}'", null, true);
148
                }
149
            }
150
            if ($this->isNamed) {
151
                foreach ($match[ 1 ] as $prop) {
152
                    if (in_array($prop, $this->nameProperties)) {
153
                        $nameAttr[ $prop ] = true;
154
                    } else {
155
                        $compiler->trigger_template_error("Invalid property '{$prop}'", null, true);
156
                    }
157
                }
158
            }
159
        }
160
        if (isset($itemAttr[ 'first' ])) {
161
            $itemAttr[ 'index' ] = true;
162
        }
163
        if (isset($namedAttr[ 'first' ])) {
164
            $namedAttr[ 'index' ] = true;
165
        }
166
        if (isset($namedAttr[ 'last' ])) {
167
            $namedAttr[ 'iteration' ] = true;
168
            $namedAttr[ 'total' ] = true;
169
        }
170
        if (isset($itemAttr[ 'last' ])) {
171
            $itemAttr[ 'iteration' ] = true;
172
            $itemAttr[ 'total' ] = true;
173
        }
174
        if (isset($namedAttr[ 'show' ])) {
175
            $namedAttr[ 'total' ] = true;
176
        }
177
        if (isset($itemAttr[ 'show' ])) {
178
            $itemAttr[ 'total' ] = true;
179
        }
180
        $keyTerm = '';
181
        if (isset($attributes[ 'key' ])) {
182
            $keyTerm = "\$_smarty_tpl->tpl_vars['{$key}']->value => ";
183
        }
184
        if (isset($itemAttr[ 'key' ])) {
185
            $keyTerm = "{$itemVar}->key => ";
186
        }
187
        if ($this->isNamed) {
188
            $foreachVar = "\$_smarty_tpl->tpl_vars['__smarty_foreach_{$attributes['name']}']";
189
        }
190
        $needTotal = isset($itemAttr[ 'total' ]);
191
        // Register tag
192
        $this->openTag(
193
            $compiler,
194
            'foreach',
195
            array('foreach', $compiler->nocache, $local, $itemVar, empty($itemAttr) ? 1 : 2)
196
        );
197
        // maybe nocache because of nocache variables
198
        $compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
199
        // generate output code
200
        $output = "<?php\n";
201
        $output .= "\$_from = \$_smarty_tpl->smarty->ext->_foreach->init(\$_smarty_tpl, $from, " .
202
                   var_export($item, true);
203
        if ($name || $needTotal || $key) {
204
            $output .= ', ' . var_export($needTotal, true);
205
        }
206
        if ($name || $key) {
207
            $output .= ', ' . var_export($key, true);
208
        }
209
        if ($name) {
210
            $output .= ', ' . var_export($name, true) . ', ' . var_export($namedAttr, true);
211
        }
212
        $output .= ");\n";
213
        if (isset($itemAttr[ 'show' ])) {
214
            $output .= "{$itemVar}->show = ({$itemVar}->total > 0);\n";
215
        }
216
        if (isset($itemAttr[ 'iteration' ])) {
217
            $output .= "{$itemVar}->iteration = 0;\n";
218
        }
219
        if (isset($itemAttr[ 'index' ])) {
220
            $output .= "{$itemVar}->index = -1;\n";
221
        }
222
	    $output .= "{$itemVar}->do_else = true;\n";
223
        $output .= "if (\$_from !== null) foreach (\$_from as {$keyTerm}{$itemVar}->value) {\n";
224
	    $output .= "{$itemVar}->do_else = false;\n";
225
        if (isset($attributes[ 'key' ]) && isset($itemAttr[ 'key' ])) {
226
            $output .= "\$_smarty_tpl->tpl_vars['{$key}']->value = {$itemVar}->key;\n";
227
        }
228
        if (isset($itemAttr[ 'iteration' ])) {
229
            $output .= "{$itemVar}->iteration++;\n";
230
        }
231
        if (isset($itemAttr[ 'index' ])) {
232
            $output .= "{$itemVar}->index++;\n";
233
        }
234
        if (isset($itemAttr[ 'first' ])) {
235
            $output .= "{$itemVar}->first = !{$itemVar}->index;\n";
236
        }
237
        if (isset($itemAttr[ 'last' ])) {
238
            $output .= "{$itemVar}->last = {$itemVar}->iteration === {$itemVar}->total;\n";
239
        }
240
        if (isset($foreachVar)) {
241
            if (isset($namedAttr[ 'iteration' ])) {
242
                $output .= "{$foreachVar}->value['iteration']++;\n";
243
            }
244
            if (isset($namedAttr[ 'index' ])) {
245
                $output .= "{$foreachVar}->value['index']++;\n";
246
            }
247
            if (isset($namedAttr[ 'first' ])) {
248
                $output .= "{$foreachVar}->value['first'] = !{$foreachVar}->value['index'];\n";
249
            }
250
            if (isset($namedAttr[ 'last' ])) {
251
                $output .= "{$foreachVar}->value['last'] = {$foreachVar}->value['iteration'] === {$foreachVar}->value['total'];\n";
252
            }
253
        }
254
        if (!empty($itemAttr)) {
255
            $output .= "{$local}saved = {$itemVar};\n";
256
        }
257
        $output .= '?>';
258
        return $output;
259
    }
260
 
261
    /**
262
     * Compiles code for to restore saved template variables
263
     *
264
     * @param int $levels number of levels to restore
265
     *
266
     * @return string compiled code
267
     */
268
    public function compileRestore($levels)
269
    {
270
        return "\$_smarty_tpl->smarty->ext->_foreach->restore(\$_smarty_tpl, {$levels});";
271
    }
272
}
273
 
274
/**
275
 * Smarty Internal Plugin Compile Foreachelse Class
276
 *
277
 * @package    Smarty
278
 * @subpackage Compiler
279
 */
280
class Smarty_Internal_Compile_Foreachelse extends Smarty_Internal_CompileBase
281
{
282
    /**
283
     * Compiles code for the {foreachelse} tag
284
     *
285
     * @param array                                 $args     array with attributes from parser
286
     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
287
     *
288
     * @return string compiled code
289
     */
290
    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
291
    {
292
        // check and get attributes
293
        $_attr = $this->getAttributes($compiler, $args);
294
        list($openTag, $nocache, $local, $itemVar, $restore) = $this->closeTag($compiler, array('foreach'));
295
        $this->openTag($compiler, 'foreachelse', array('foreachelse', $nocache, $local, $itemVar, 0));
296
        $output = "<?php\n";
297
        if ($restore === 2) {
298
            $output .= "{$itemVar} = {$local}saved;\n";
299
        }
300
        $output .= "}\nif ({$itemVar}->do_else) {\n?>";
301
        return $output;
302
    }
303
}
304
 
305
/**
306
 * Smarty Internal Plugin Compile Foreachclose Class
307
 *
308
 * @package    Smarty
309
 * @subpackage Compiler
310
 */
311
class Smarty_Internal_Compile_Foreachclose extends Smarty_Internal_CompileBase
312
{
313
    /**
314
     * Compiles code for the {/foreach} tag
315
     *
316
     * @param array                                 $args     array with attributes from parser
317
     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
318
     *
319
     * @return string compiled code
320
     * @throws \SmartyCompilerException
321
     */
322
    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
323
    {
324
        $compiler->loopNesting--;
325
        // must endblock be nocache?
326
        if ($compiler->nocache) {
327
            $compiler->tag_nocache = true;
328
        }
329
        list(
330
            $openTag, $compiler->nocache, $local, $itemVar, $restore
331
            ) = $this->closeTag($compiler, array('foreach', 'foreachelse'));
332
        $output = "<?php\n";
333
        if ($restore === 2) {
334
            $output .= "{$itemVar} = {$local}saved;\n";
335
        }
336
        $output .= "}\n";
337
        /* @var Smarty_Internal_Compile_Foreach $foreachCompiler */
338
        $foreachCompiler = $compiler->getTagCompiler('foreach');
339
        $output .= $foreachCompiler->compileRestore(1);
340
        $output .= "?>";
341
        return $output;
342
    }
343
}