1<?php
2/**
3 * Smarty Internal Plugin Compile Break
4 * Compiles the {break} tag
5 *
6 * @package    Smarty
7 * @subpackage Compiler
8 * @author     Uwe Tews
9 */
10
11/**
12 * Smarty Internal Plugin Compile Break Class
13 *
14 * @package    Smarty
15 * @subpackage Compiler
16 */
17class Smarty_Internal_Compile_Break extends Smarty_Internal_CompileBase
18{
19    /**
20     * Attribute definition: Overwrites base class.
21     *
22     * @var array
23     * @see Smarty_Internal_CompileBase
24     */
25    public $optional_attributes = array('levels');
26
27    /**
28     * Attribute definition: Overwrites base class.
29     *
30     * @var array
31     * @see Smarty_Internal_CompileBase
32     */
33    public $shorttag_order = array('levels');
34
35    /**
36     * Tag name may be overloaded by Smarty_Internal_Compile_Continue
37     *
38     * @var string
39     */
40    public $tag = 'break';
41
42    /**
43     * Compiles code for the {break} tag
44     *
45     * @param array                                 $args     array with attributes from parser
46     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
47     *
48     * @return string compiled code
49     * @throws \SmartyCompilerException
50     */
51    public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
52    {
53        list($levels, $foreachLevels) = $this->checkLevels($args, $compiler);
54        $output = "<?php ";
55        if ($foreachLevels > 0 && $this->tag === 'continue') {
56            $foreachLevels--;
57        }
58        if ($foreachLevels > 0) {
59            /* @var Smarty_Internal_Compile_Foreach $foreachCompiler */
60            $foreachCompiler = $compiler->getTagCompiler('foreach');
61            $output .= $foreachCompiler->compileRestore($foreachLevels);
62        }
63        $output .= "{$this->tag} {$levels};?>";
64        return $output;
65    }
66
67    /**
68     * check attributes and return array of break and foreach levels
69     *
70     * @param array                                 $args     array with attributes from parser
71     * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
72     *
73     * @return array
74     * @throws \SmartyCompilerException
75     */
76    public function checkLevels($args, Smarty_Internal_TemplateCompilerBase $compiler)
77    {
78        static $_is_loopy = array('for' => true, 'foreach' => true, 'while' => true, 'section' => true);
79        // check and get attributes
80        $_attr = $this->getAttributes($compiler, $args);
81        if ($_attr[ 'nocache' ] === true) {
82            $compiler->trigger_template_error('nocache option not allowed', null, true);
83        }
84        if (isset($_attr[ 'levels' ])) {
85            if (!is_numeric($_attr[ 'levels' ])) {
86                $compiler->trigger_template_error('level attribute must be a numeric constant', null, true);
87            }
88            $levels = $_attr[ 'levels' ];
89        } else {
90            $levels = 1;
91        }
92        $level_count = $levels;
93        $stack_count = count($compiler->_tag_stack) - 1;
94        $foreachLevels = 0;
95        $lastTag = '';
96        while ($level_count > 0 && $stack_count >= 0) {
97            if (isset($_is_loopy[ $compiler->_tag_stack[ $stack_count ][ 0 ] ])) {
98                $lastTag = $compiler->_tag_stack[ $stack_count ][ 0 ];
99                if ($level_count === 0) {
100                    break;
101                }
102                $level_count--;
103                if ($compiler->_tag_stack[ $stack_count ][ 0 ] === 'foreach') {
104                    $foreachLevels++;
105                }
106            }
107            $stack_count--;
108        }
109        if ($level_count !== 0) {
110            $compiler->trigger_template_error("cannot {$this->tag} {$levels} level(s)", null, true);
111        }
112        if ($lastTag === 'foreach' && $this->tag === 'break' && $foreachLevels > 0) {
113            $foreachLevels--;
114        }
115        return array($levels, $foreachLevels);
116    }
117}
118