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

DeleteStatement::build()   C

Complexity

Conditions 13
Paths 64

Size

Total Lines 25
Code Lines 15

Duplication

Lines 12
Ratio 48 %

Code Coverage

Tests 21
CRAP Score 13

Importance

Changes 0
Metric Value
cc 13
eloc 15
nc 64
nop 0
dl 12
loc 25
ccs 21
cts 21
cp 1
crap 13
rs 5.1234
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * `DELETE` statement.
5
 */
6
7
namespace PhpMyAdmin\SqlParser\Statements;
8
9
use PhpMyAdmin\SqlParser\Statement;
10
use PhpMyAdmin\SqlParser\Parser;
11
use PhpMyAdmin\SqlParser\Token;
12
use PhpMyAdmin\SqlParser\TokensList;
13
use PhpMyAdmin\SqlParser\Components\ArrayObj;
14
use PhpMyAdmin\SqlParser\Components\Expression;
15
use PhpMyAdmin\SqlParser\Components\ExpressionArray;
16
use PhpMyAdmin\SqlParser\Components\Limit;
17
use PhpMyAdmin\SqlParser\Components\OrderKeyword;
18
use PhpMyAdmin\SqlParser\Components\Condition;
19
use PhpMyAdmin\SqlParser\Components\OptionsArray;
20
21
/**
22
 * `DELETE` statement.
23
 *
24
 * DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
25
 *     [PARTITION (partition_name,...)]
26
 *     [WHERE where_condition]
27
 *     [ORDER BY ...]
28
 *     [LIMIT row_count]
29
 *
30
 * Multi-table syntax
31
 *
32
 * DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
33
 *   tbl_name[.*] [, tbl_name[.*]] ...
34
 *   FROM table_references
35
 *   [WHERE where_condition]
36
 *
37
 * OR
38
 *
39
 * DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
40
 *   FROM tbl_name[.*] [, tbl_name[.*]] ...
41
 *   USING table_references
42
 *   [WHERE where_condition]
43
 *
44
 *
45
 * @category   Statements
46
 *
47
 * @license    https://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
48
 */
49
class DeleteStatement extends Statement
50
{
51
    /**
52
     * Options for `DELETE` statements.
53
     *
54
     * @var array
55
     */
56
    public static $OPTIONS = array(
57
        'LOW_PRIORITY' => 1,
58
        'QUICK' => 2,
59
        'IGNORE' => 3,
60
    );
61
62
    /**
63
     * The clauses of this statement, in order.
64
     *
65
     * @see Statement::$CLAUSES
66
     *
67
     * @var array
68
     */
69
    public static $CLAUSES = array(
70
        'DELETE' => array('DELETE',      2),
71
        // Used for options.
72
        '_OPTIONS' => array('_OPTIONS',    1),
73
        'FROM' => array('FROM',        3),
74
        'PARTITION' => array('PARTITION',   3),
75
        'USING' => array('USING',       3),
76
        'WHERE' => array('WHERE',       3),
77
        'ORDER BY' => array('ORDER BY',    3),
78
        'LIMIT' => array('LIMIT',       3),
79
    );
80
81
    /**
82
     * Table(s) used as sources for this statement.
83
     *
84
     * @var Expression[]
85
     */
86
    public $from;
87
88
    /**
89
     * Tables used as sources for this statement.
90
     *
91
     * @var Expression[]
92
     */
93
    public $using;
94
95
    /**
96
     * Columns used in this statement.
97
     *
98
     * @var Expression[]
99
     */
100
    public $columns;
101
102
    /**
103
     * Partitions used as source for this statement.
104
     *
105
     * @var ArrayObj
106
     */
107
    public $partition;
108
109
    /**
110
     * Conditions used for filtering each row of the result set.
111
     *
112
     * @var Condition[]
113
     */
114
    public $where;
115
116
    /**
117
     * Specifies the order of the rows in the result set.
118
     *
119
     * @var OrderKeyword[]
120
     */
121
    public $order;
122
123
    /**
124
     * Conditions used for limiting the size of the result set.
125
     *
126
     * @var Limit
127
     */
128
    public $limit;
129
130
    /**
131
     * @return string
132
     */
133 2
    public function build()
134
    {
135 2
        $ret = 'DELETE ' . OptionsArray::build($this->options);
136
137 2 View Code Duplication
        if ($this->columns != null && count($this->columns) > 0) {
138 1
            $ret .= ' ' . ExpressionArray::build($this->columns);
139 1
        }
140 2 View Code Duplication
        if ($this->from != null && count($this->from) > 0) {
141 2
            $ret .= ' FROM ' . ExpressionArray::build($this->from);
142 2
        }
143 2 View Code Duplication
        if ($this->using != null && count($this->using) > 0) {
144 1
            $ret .= ' USING ' . ExpressionArray::build($this->using);
145 1
        }
146 2
        if ($this->where != null && count($this->where) > 0) {
147 2
            $ret .= ' WHERE ' . Condition::build($this->where);
148 2
        }
149 2 View Code Duplication
        if ($this->order != null && count($this->order) > 0) {
150 1
            $ret .= ' ORDER BY ' . ExpressionArray::build($this->order);
0 ignored issues
show
Documentation introduced by
$this->order is of type array<integer,object<Php...mponents\OrderKeyword>>, but the function expects a array<integer,object<Php...Components\Expression>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
151 1
        }
152 2
        if ($this->limit != null && strlen($this->limit) > 0) {
153 1
            $ret .= ' LIMIT ' . Limit::build($this->limit);
154 1
        }
155
156 2
        return $ret;
157
    }
158
159
    /**
160
     * @param Parser     $parser the instance that requests parsing
161
     * @param TokensList $list   the list of tokens to be parsed
162
     */
163 28
    public function parse(Parser $parser, TokensList $list)
164
    {
165 28
        ++$list->idx; // Skipping `DELETE`.
166
167
        // parse any options if provided
168 28
        $this->options = OptionsArray::parse(
169 28
            $parser,
170 28
            $list,
171
            static::$OPTIONS
172 28
        );
173 28
        ++$list->idx;
174
175
        /**
176
         * The state of the parser.
177
         *
178
         * Below are the states of the parser.
179
         *
180
         *      0 ---------------------------------[ FROM ]----------------------------------> 2
181
         *      0 ------------------------------[ table[.*] ]--------------------------------> 1
182
         *      1 ---------------------------------[ FROM ]----------------------------------> 2
183
         *      2 --------------------------------[ USING ]----------------------------------> 3
184
         *      2 --------------------------------[ WHERE ]----------------------------------> 4
185
         *      2 --------------------------------[ ORDER ]----------------------------------> 5
186
         *      2 --------------------------------[ LIMIT ]----------------------------------> 6
187
         *
188
         * @var int
189
         */
190 28
        $state = 0;
191
192
        /**
193
         * If the query is multi-table or not.
194
         *
195
         * @var bool
196
         */
197 28
        $multiTable = false;
198
199 28
        for (; $list->idx < $list->count; ++$list->idx) {
200
            /**
201
             * Token parsed at this moment.
202
             *
203
             * @var Token
204
             */
205 28
            $token = $list->tokens[$list->idx];
206
207
            // End of statement.
208 28
            if ($token->type === Token::TYPE_DELIMITER) {
209 16
                break;
210
            }
211
212 28
            if ($state === 0) {
213 28
                if ($token->type === Token::TYPE_KEYWORD
214 28
                    && $token->value !== 'FROM'
215 28
                ) {
216 1
                    $parser->error(__('Unexpected keyword.'), $token);
217 1
                    break;
218 27
                } elseif ($token->type === Token::TYPE_KEYWORD
219 27
                    && $token->value === 'FROM'
220 27
                ) {
221 23
                    ++$list->idx; // Skip 'FROM'
222 23
                    $this->from = ExpressionArray::parse($parser, $list);
223 23
                    $state = 2;
224 23
                } else {
225 5
                    $this->columns = ExpressionArray::parse($parser, $list);
226 5
                    $state = 1;
227
                }
228 27 View Code Duplication
            } elseif ($state === 1) {
229 5
                if ($token->type === Token::TYPE_KEYWORD
230 5
                    && $token->value !== 'FROM'
231 5
                ) {
232 1
                    $parser->error(__('Unexpected keyword.'), $token);
233 1
                    break;
234 4
                } elseif ($token->type === Token::TYPE_KEYWORD
235 4
                    && $token->value === 'FROM'
236 4
                ) {
237 3
                    ++$list->idx; // Skip 'FROM'
238 3
                    $this->from = ExpressionArray::parse($parser, $list);
239 3
                    $state = 2;
240 3
                } else {
241 1
                    $parser->error(__('Unexpected token.'), $token);
242 1
                    break;
243
                }
244 23
            } elseif ($state === 2) {
245 22
                if ($token->type === Token::TYPE_KEYWORD
246 22
                    && $token->value === 'USING'
247 22
                ) {
248 7
                    ++$list->idx; // Skip 'USING'
249 7
                    $this->using = ExpressionArray::parse($parser, $list);
250 7
                    $state = 3;
251
252 7
                    $multiTable = true;
253 22
                } elseif ($token->type === Token::TYPE_KEYWORD
254 16
                    && $token->value === 'WHERE'
255 16
                ) {
256 12
                    ++$list->idx; // Skip 'WHERE'
257 12
                    $this->where = Condition::parse($parser, $list);
258 12
                    $state = 4;
259 16
                } elseif ($token->type === Token::TYPE_KEYWORD
260 4
                    && $token->value === 'ORDER BY'
261 4
                ) {
262 2
                    ++$list->idx; // Skip 'ORDER BY'
263 2
                    $this->order = OrderKeyword::parse($parser, $list);
264 2
                    $state = 5;
265 4
                } elseif ($token->type === Token::TYPE_KEYWORD
266 2
                    && $token->value === 'LIMIT'
267 2
                ) {
268 1
                    ++$list->idx; // Skip 'LIMIT'
269 1
                    $this->limit = Limit::parse($parser, $list);
270 1
                    $state = 6;
271 2
                } elseif ($token->type === Token::TYPE_KEYWORD) {
272 1
                    $parser->error(__('Unexpected keyword.'), $token);
273 1
                    break;
274
                }
275 21 View Code Duplication
            } elseif ($state === 3) {
276 7
                if ($token->type === Token::TYPE_KEYWORD
277 7
                    && $token->value === 'WHERE'
278 7
                ) {
279 4
                    ++$list->idx; // Skip 'WHERE'
280 4
                    $this->where = Condition::parse($parser, $list);
281 4
                    $state = 4;
282 7
                } elseif ($token->type === Token::TYPE_KEYWORD) {
283 1
                    $parser->error(__('Unexpected keyword.'), $token);
284 1
                    break;
285
                } else {
286 2
                    $parser->error(__('Unexpected token.'), $token);
287 2
                    break;
288
                }
289 13
            } elseif ($state === 4) {
290
                if ($multiTable === true
291 10
                    && $token->type === Token::TYPE_KEYWORD
292 10
                ) {
293 2
                    $parser->error(
294 2
                        __('This type of clause is not valid in Multi-table queries.'),
295
                        $token
296 2
                    );
297 2
                    break;
298
                }
299
300 8
                if ($token->type === Token::TYPE_KEYWORD
301 8
                    && $token->value === 'ORDER BY'
302 8
                ) {
303 6
                    ++$list->idx; // Skip 'ORDER  BY'
304 6
                    $this->order = OrderKeyword::parse($parser, $list);
305 6
                    $state = 5;
306 8
                } elseif ($token->type === Token::TYPE_KEYWORD
307 2
                    && $token->value === 'LIMIT'
308 2
                ) {
309 1
                    ++$list->idx; // Skip 'LIMIT'
310 1
                    $this->limit = Limit::parse($parser, $list);
311 1
                    $state = 6;
312 2
                } elseif ($token->type === Token::TYPE_KEYWORD) {
313 1
                    $parser->error(__('Unexpected keyword.'), $token);
314 1
                    break;
315
                }
316 8
            } elseif ($state === 5) {
317 5
                if ($token->type === Token::TYPE_KEYWORD
318 5
                    && $token->value === 'LIMIT'
319 5
                ) {
320 3
                    ++$list->idx; // Skip 'LIMIT'
321 3
                    $this->limit = Limit::parse($parser, $list);
322 3
                    $state = 6;
323 5
                } elseif ($token->type === Token::TYPE_KEYWORD) {
324 2
                    $parser->error(__('Unexpected keyword.'), $token);
325 2
                    break;
326
                }
327 3
            }
328 27
        }
329
330 28
        if ($state >= 2) {
331 25
            foreach ($this->from as $from_expr) {
332 25
                $from_expr->database = $from_expr->table;
333 25
                $from_expr->table = $from_expr->column;
334 25
                $from_expr->column = null;
335 25
            }
336 25
        }
337
338 28
        --$list->idx;
339 28
    }
340
}
341