Completed
Pull Request — master (#87)
by Deven
118:34 queued 53:37
created

DeleteStatement::parse()   D

Complexity

Conditions 45
Paths 24

Size

Total Lines 192
Code Lines 119

Duplication

Lines 50
Ratio 26.04 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 45
eloc 119
nc 24
nop 2
dl 50
loc 192
rs 4.1818
c 1
b 0
f 0

How to fix   Long Method    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
 * @package    SqlParser
7
 * @subpackage Statements
8
 */
9
namespace SqlParser\Statements;
10
11
use SqlParser\Statement;
12
use SqlParser\Parser;
13
use SqlParser\Token;
14
use SqlParser\TokensList;
15
use SqlParser\Components\ArrayObj;
16
use SqlParser\Components\Expression;
17
use SqlParser\Components\ExpressionArray;
18
use SqlParser\Components\Limit;
19
use SqlParser\Components\OrderKeyword;
20
use SqlParser\Components\Condition;
21
use SqlParser\Components\OptionsArray;
22
23
/**
24
 * `DELETE` statement.
25
 *
26
 * DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
27
 *     [PARTITION (partition_name,...)]
28
 *     [WHERE where_condition]
29
 *     [ORDER BY ...]
30
 *     [LIMIT row_count]
31
 *
32
 * Multi-table syntax
33
 *
34
 * DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
35
 *   tbl_name[.*] [, tbl_name[.*]] ...
36
 *   FROM table_references
37
 *   [WHERE where_condition]
38
 *
39
 * OR
40
 *
41
 * DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
42
 *   FROM tbl_name[.*] [, tbl_name[.*]] ...
43
 *   USING table_references
44
 *   [WHERE where_condition]
45
 *
46
 *
47
 * @category   Statements
48
 * @package    SqlParser
49
 * @subpackage Statements
50
 * @license    https://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
51
 */
52
class DeleteStatement extends Statement
53
{
54
55
    /**
56
     * Options for `DELETE` statements.
57
     *
58
     * @var array
59
     */
60
    public static $OPTIONS = array(
61
        'LOW_PRIORITY'                  => 1,
62
        'QUICK'                         => 2,
63
        'IGNORE'                        => 3,
64
    );
65
66
    /**
67
     * Table(s) used as sources for this statement.
68
     *
69
     * @var Expression[]
70
     */
71
    public $from;
72
73
    /**
74
     * Tables used as sources for this statement
75
     *
76
     * @var Expression[]
77
     */
78
    public $using;
79
80
    /**
81
     * Columns used in this statement
82
     *
83
     * @var Expression[]
84
     */
85
    public $columns;
86
87
    /**
88
     * Partitions used as source for this statement.
89
     *
90
     * @var ArrayObj
91
     */
92
    public $partition;
93
94
    /**
95
     * Conditions used for filtering each row of the result set.
96
     *
97
     * @var Condition[]
98
     */
99
    public $where;
100
101
    /**
102
     * Specifies the order of the rows in the result set.
103
     *
104
     * @var OrderKeyword[]
105
     */
106
    public $order;
107
108
    /**
109
     * Conditions used for limiting the size of the result set.
110
     *
111
     * @var Limit
112
     */
113
    public $limit;
114
115
116
    /**
117
     * @return string
118
     */
119
    public function build()
120
    {
121
        $ret = 'DELETE ' . OptionsArray::build($this->options);
122
123 View Code Duplication
        if ($this->columns != NULL && count($this->columns) > 0) {
124
            $ret .= ' ' . ExpressionArray::build($this->columns);
125
        }
126 View Code Duplication
        if ($this->from != NULL && count($this->from) > 0) {
127
            $ret .= ' FROM ' . ExpressionArray::build($this->from);
128
        }
129 View Code Duplication
        if ($this->using != NULL && count($this->using) > 0) {
130
            $ret .= ' USING ' . ExpressionArray::build($this->using);
131
        }
132
        if ($this->where != NULL && count($this->where) > 0) {
133
            $ret .= ' WHERE ' . Condition::build($this->where);
134
        }
135 View Code Duplication
        if ($this->order != NULL && count($this->order) > 0) {
136
            $ret .= ' ORDER BY ' . ExpressionArray::build($this->order);
0 ignored issues
show
Documentation introduced by
$this->order is of type array<integer,object<Sql...mponents\OrderKeyword>>, but the function expects a array<integer,object<Sql...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...
137
        }
138
        if ($this->limit != NULL && count($this->limit) > 0) {
139
            $ret .= ' LIMIT ' . Limit::build($this->limit);
140
        }
141
142
        return $ret;
143
144
    }
145
146
147
    /**
148
     * @param Parser     $parser The instance that requests parsing.
149
     * @param TokensList $list   The list of tokens to be parsed.
150
     *
151
     * @return void
152
     */
153
    public function parse(Parser $parser, TokensList $list)
154
    {
155
        ++$list->idx; // Skipping `DELETE`.
156
157
        // parse any options if provided
158
        $this->options = OptionsArray::parse(
159
            $parser,
160
            $list,
161
            static::$OPTIONS
162
        );
163
        ++$list->idx;
164
165
        /**
166
         * The state of the parser.
167
         *
168
         * Below are the states of the parser.
169
         *
170
         *      0 ---------------------------------[ FROM ]----------------------------------> 2
171
         *      0 ------------------------------[ table[.*] ]--------------------------------> 1
172
         *      1 ---------------------------------[ FROM ]----------------------------------> 2
173
         *      2 --------------------------------[ USING ]----------------------------------> 3
174
         *      2 --------------------------------[ WHERE ]----------------------------------> 4
175
         *      2 --------------------------------[ ORDER ]----------------------------------> 5
176
         *      2 --------------------------------[ LIMIT ]----------------------------------> 6
177
         *
178
         * @var int $state
179
         */
180
        $state = 0;
181
182
        /**
183
         * If the query is multi-table or not
184
         *
185
         * @var bool $multiTable
186
         */
187
        $multiTable = false;
188
189
        for (; $list->idx < $list->count; ++$list->idx) {
190
            /**
191
             * Token parsed at this moment.
192
             *
193
             * @var Token $token
194
             */
195
            $token = $list->tokens[$list->idx];
196
197
            // End of statement.
198
            if ($token->type === Token::TYPE_DELIMITER) {
199
                break;
200
            }
201
202
            // Skipping whitespaces and comments.
203
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
204
                continue;
205
            }
206
207
            if ($state === 0) {
208
                if ($token->type === Token::TYPE_KEYWORD
209
                    && $token->value !== 'FROM'
210
                ) {
211
                    $parser->error(__('Unexpected keyword.'), $token);
212
                    break;
213
                } elseif ($token->type === Token::TYPE_KEYWORD
214
                    && $token->value === 'FROM'
215
                ) {
216
                    ++$list->idx; // Skip 'FROM'
217
                    $this->from = ExpressionArray::parse($parser, $list);
218
                    $state = 2;
219
                } else {
220
                    $this->columns = ExpressionArray::parse($parser, $list);
221
                    $state = 1;
222
                }
223 View Code Duplication
            } elseif ($state === 1) {
224
                if ($token->type === Token::TYPE_KEYWORD
225
                    && $token->value !== 'FROM'
226
                ) {
227
                    $parser->error(__('Unexpected keyword.'), $token);
228
                    break;
229
                } elseif ($token->type === Token::TYPE_KEYWORD
230
                    && $token->value === 'FROM'
231
                ) {
232
                    ++$list->idx; // Skip 'FROM'
233
                    $this->from = ExpressionArray::parse($parser, $list);
234
                    $state = 2;
235
                } else {
236
                    $parser->error(__('Unexpected token.'), $token);
237
                    break;
238
                }
239
            } elseif ($state === 2) {
240
                if ($token->type === Token::TYPE_KEYWORD
241
                    && $token->value === 'USING'
242
                ) {
243
                    ++$list->idx; // Skip 'USING'
244
                    $this->using = ExpressionArray::parse($parser, $list);
245
                    $state = 3;
246
247
                    $multiTable = true;
248
                } elseif ($token->type === Token::TYPE_KEYWORD
249
                    && $token->value === 'WHERE'
250
                ) {
251
                    ++$list->idx; // Skip 'WHERE'
252
                    $this->where = Condition::parse($parser, $list);
253
                    $state = 4;
254
                } elseif ($token->type === Token::TYPE_KEYWORD
255
                    && $token->value === 'ORDER BY'
256
                ) {
257
                    ++$list->idx; // Skip 'ORDER BY'
258
                    $this->order = OrderKeyword::parse($parser, $list);
259
                    $state = 5;
260
                } elseif ($token->type === Token::TYPE_KEYWORD
261
                    && $token->value === 'LIMIT'
262
                ) {
263
                    ++$list->idx; // Skip 'LIMIT'
264
                    $this->limit = Limit::parse($parser, $list);
265
                    $state = 6;
266
                } elseif ($token->type === Token::TYPE_KEYWORD) {
267
                    $parser->error(__('Unexpected keyword.'), $token);
268
                    break;
269
                }
270 View Code Duplication
            } elseif ($state === 3) {
271
                if ($token->type === Token::TYPE_KEYWORD
272
                    && $token->value === 'WHERE'
273
                ) {
274
                    ++$list->idx; // Skip 'WHERE'
275
                    $this->where = Condition::parse($parser, $list);
276
                    $state = 4;
277
                } elseif ($token->type === Token::TYPE_KEYWORD) {
278
                    $parser->error(__('Unexpected keyword.'), $token);
279
                    break;
280
                } else {
281
                    $parser->error(__('Unexpected token.'), $token);
282
                    break;
283
                }
284
            } elseif ($state === 4) {
285 View Code Duplication
                if ($multiTable === true
286
                    && $token->type === Token::TYPE_KEYWORD
287
                ) {
288
                    $parser->error(
289
                        __('This type of clause is not valid in Multi-table queries.'),
290
                        $token
291
                    );
292
                    break;
293
                }
294
295
                if ($token->type === Token::TYPE_KEYWORD
296
                    && $token->value === 'ORDER BY'
297
                ) {
298
                    ++$list->idx; // Skip 'ORDER  BY'
299
                    $this->order = OrderKeyword::parse($parser, $list);
300
                    $state = 5;
301
                }  elseif ($token->type === Token::TYPE_KEYWORD
302
                    && $token->value === 'LIMIT'
303
                ) {
304
                    ++$list->idx; // Skip 'LIMIT'
305
                    $this->limit = Limit::parse($parser, $list);
306
                    $state = 6;
307
                } elseif ($token->type === Token::TYPE_KEYWORD) {
308
                    $parser->error(__('Unexpected keyword.'), $token);
309
                    break;
310
                }
311
            } elseif ($state === 5) {
312 View Code Duplication
                if ($multiTable === true
313
                    && $token->type === Token::TYPE_KEYWORD
314
                ) {
315
                    $parser->error(
316
                        __('This type of clause is not valid in Multi-table queries.'),
317
                        $token
318
                    );
319
                    break;
320
                }
321
322
                if ($token->type === Token::TYPE_KEYWORD
323
                    && $token->value === 'LIMIT'
324
                ) {
325
                    ++$list->idx; // Skip 'LIMIT'
326
                    $this->limit = Limit::parse($parser, $list);
327
                    $state = 6;
328
                } elseif ($token->type === Token::TYPE_KEYWORD) {
329
                    $parser->error(__('Unexpected keyword.'), $token);
330
                    break;
331
                }
332
            }
333
        }
334
335
        if ($state >= 2) {
336
            foreach ($this->from as $from_expr) {
337
                $from_expr->database = $from_expr->table;
338
                $from_expr->table = $from_expr->column;
339
                $from_expr->column = null;
340
            }
341
        }
342
343
        --$list->idx;
344
    }
345
}
346