Completed
Push — master ( 65f66e...428edc )
by Michal
04:14
created

CaseExpression::build()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 32
Code Lines 21

Duplication

Lines 16
Ratio 50 %

Code Coverage

Tests 22
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 21
nc 8
nop 2
dl 16
loc 32
ccs 22
cts 22
cp 1
crap 7
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Parses a reference to a CASE expression.
5
 */
6
7
namespace PhpMyAdmin\SqlParser\Components;
8
9
use PhpMyAdmin\SqlParser\Component;
10
use PhpMyAdmin\SqlParser\Parser;
11
use PhpMyAdmin\SqlParser\Token;
12
use PhpMyAdmin\SqlParser\TokensList;
13
14
/**
15
 * Parses a reference to a CASE expression.
16
 *
17
 * @category   Components
18
 *
19
 * @license    https://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
20
 */
21
class CaseExpression extends Component
22
{
23
    /**
24
     * The value to be compared.
25
     *
26
     * @var Expression
27
     */
28
    public $value;
29
30
    /**
31
     * The conditions in WHEN clauses.
32
     *
33
     * @var array
34
     */
35
    public $conditions;
36
37
    /**
38
     * The results matching with the WHEN clauses.
39
     *
40
     * @var array
41
     */
42
    public $results;
43
44
    /**
45
     * The values to be compared against.
46
     *
47
     * @var array
48
     */
49
    public $compare_values;
50
51
    /**
52
     * The result in ELSE section of expr.
53
     *
54
     * @var array
55
     */
56
    public $else_result;
57
58
    /**
59
     * Constructor.
60
     */
61 16
    public function __construct()
62
    {
63 16
    }
64
65
    /**
66
     * @param Parser     $parser the parser that serves as context
67
     * @param TokensList $list   the list of tokens that are being parsed
68
     *
69
     * @return Expression
0 ignored issues
show
Documentation introduced by
Should the return type not be CaseExpression?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
70
     */
71 16
    public static function parse(Parser $parser, TokensList $list, array $options = array())
72
    {
73 16
        $ret = new self();
74
75
        /**
76
         * State of parser.
77
         *
78
         * @var int
79
         */
80 16
        $state = 0;
81
82
        /**
83
         * Syntax type (type 0 or type 1).
84
         *
85
         * @var int
86
         */
87 16
        $type = 0;
88
89 16
        ++$list->idx; // Skip 'CASE'
90
91 16
        for (; $list->idx < $list->count; ++$list->idx) {
92
            /**
93
             * Token parsed at this moment.
94
             *
95
             * @var Token
96
             */
97 16
            $token = $list->tokens[$list->idx];
98
99
            // Skipping whitespaces and comments.
100 16
            if (($token->type === Token::TYPE_WHITESPACE)
101 16
                || ($token->type === Token::TYPE_COMMENT)
102 16
            ) {
103 16
                continue;
104
            }
105
106 16
            if ($state === 0) {
107 16
                if ($token->type === Token::TYPE_KEYWORD
108 16
                    && $token->value === 'WHEN'
109 16
                ) {
110 6
                    ++$list->idx; // Skip 'WHEN'
111 6
                    $new_condition = Condition::parse($parser, $list);
112 6
                    $type = 1;
113 6
                    $state = 1;
114 6
                    $ret->conditions[] = $new_condition;
115 16
                } elseif ($token->type === Token::TYPE_KEYWORD
116 15
                    && $token->value === 'ELSE'
117 15
                ) {
118 3
                    ++$list->idx; // Skip 'ELSE'
119 3
                    $ret->else_result = Expression::parse($parser, $list);
0 ignored issues
show
Documentation Bug introduced by
It seems like \PhpMyAdmin\SqlParser\Co...::parse($parser, $list) of type object<PhpMyAdmin\SqlPar...\Components\Expression> or null is incompatible with the declared type array of property $else_result.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
120 3
                    $state = 0; // last clause of CASE expression
121 15
                } elseif ($token->type === Token::TYPE_KEYWORD
122 15
                    && ($token->value === 'END'
123 9
                    || $token->value === 'end')
124 15
                ) {
125 8
                    $state = 3; // end of CASE expression
126 8
                    ++$list->idx;
127 8
                    break;
128 10
                } elseif ($token->type === Token::TYPE_KEYWORD) {
129 1
                    $parser->error(__('Unexpected keyword.'), $token);
130 1
                    break;
131
                } else {
132 9
                    $ret->value = Expression::parse($parser, $list);
133 9
                    $type = 0;
134 9
                    $state = 1;
135
                }
136 15
            } elseif ($state === 1) {
137 15
                if ($type === 0) {
138 9
                    if ($token->type === Token::TYPE_KEYWORD
139 9
                        && $token->value === 'WHEN'
140 9
                    ) {
141 7
                        ++$list->idx; // Skip 'WHEN'
142 7
                        $new_value = Expression::parse($parser, $list);
143 7
                        $state = 2;
144 7
                        $ret->compare_values[] = $new_value;
145 9
                    } elseif ($token->type === Token::TYPE_KEYWORD
146 8
                        && $token->value === 'ELSE'
147 8
                    ) {
148 3
                        ++$list->idx; // Skip 'ELSE'
149 3
                        $ret->else_result = Expression::parse($parser, $list);
150 3
                        $state = 0; // last clause of CASE expression
151 8
                    } elseif ($token->type === Token::TYPE_KEYWORD
152 5
                        && ($token->value === 'END'
153 5
                        || $token->value === 'end')
154 5
                    ) {
155 3
                        $state = 3; // end of CASE expression
156 3
                        ++$list->idx;
157 3
                        break;
158 2
                    } elseif ($token->type === Token::TYPE_KEYWORD) {
159 2
                        $parser->error(__('Unexpected keyword.'), $token);
160 2
                        break;
161
                    }
162 7 View Code Duplication
                } else {
163 6
                    if ($token->type === Token::TYPE_KEYWORD
164 6
                        && $token->value === 'THEN'
165 6
                    ) {
166 5
                        ++$list->idx; // Skip 'THEN'
167 5
                        $new_result = Expression::parse($parser, $list);
168 5
                        $state = 0;
169 5
                        $ret->results[] = $new_result;
170 6
                    } elseif ($token->type === Token::TYPE_KEYWORD) {
171 1
                        $parser->error(__('Unexpected keyword.'), $token);
172 1
                        break;
173
                    }
174
                }
175 12
            } elseif ($state === 2) {
176 7 View Code Duplication
                if ($type === 0) {
177 7
                    if ($token->type === Token::TYPE_KEYWORD
178 7
                        && $token->value === 'THEN'
179 7
                    ) {
180 7
                        ++$list->idx; // Skip 'THEN'
181 7
                        $new_result = Expression::parse($parser, $list);
182 7
                        $ret->results[] = $new_result;
183 7
                        $state = 1;
184 7
                    } elseif ($token->type === Token::TYPE_KEYWORD) {
185 1
                        $parser->error(__('Unexpected keyword.'), $token);
186 1
                        break;
187
                    }
188 7
                }
189 7
            }
190 15
        }
191
192 16
        if ($state !== 3) {
193 5
            $parser->error(
194 5
                __('Unexpected end of CASE expression'),
195 5
                $list->tokens[$list->idx - 1]
196 5
            );
197 5
        }
198
199 16
        --$list->idx;
200
201 16
        return $ret;
202
    }
203
204
    /**
205
     * @param Expression $component the component to be built
206
     * @param array      $options   parameters for building
207
     *
208
     * @return string
209
     */
210 7
    public static function build($component, array $options = array())
211
    {
212 7
        $ret = 'CASE ';
213 7
        if (isset($component->value)) {
214
            // Syntax type 0
215 4
            $ret .= $component->value . ' ';
0 ignored issues
show
Bug introduced by
The property value does not seem to exist in PhpMyAdmin\SqlParser\Components\Expression.

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...
216 View Code Duplication
            for (
217 4
                $i = 0;
218 4
                $i < count($component->compare_values) && $i < count($component->results);
0 ignored issues
show
Bug introduced by
The property compare_values does not seem to exist in PhpMyAdmin\SqlParser\Components\Expression.

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...
Bug introduced by
The property results does not seem to exist in PhpMyAdmin\SqlParser\Components\Expression.

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...
219
                ++$i
220 4
            ) {
221 4
                $ret .= 'WHEN ' . $component->compare_values[$i] . ' ';
222 4
                $ret .= 'THEN ' . $component->results[$i] . ' ';
223 4
            }
224 4
        } else {
225
            // Syntax type 1
226 View Code Duplication
            for (
227 3
                $i = 0;
228 3
                $i < count($component->conditions) && $i < count($component->results);
0 ignored issues
show
Bug introduced by
The property conditions does not seem to exist in PhpMyAdmin\SqlParser\Components\Expression.

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...
229
                ++$i
230 3
            ) {
231 3
                $ret .= 'WHEN ' . Condition::build($component->conditions[$i]) . ' ';
232 3
                $ret .= 'THEN ' . $component->results[$i] . ' ';
233 3
            }
234
        }
235 7
        if (isset($component->else_result)) {
236 4
            $ret .= 'ELSE ' . $component->else_result . ' ';
0 ignored issues
show
Bug introduced by
The property else_result does not seem to exist in PhpMyAdmin\SqlParser\Components\Expression.

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...
237 4
        }
238 7
        $ret .= 'END';
239
240 7
        return $ret;
241
    }
242
}
243