Completed
Pull Request — master (#87)
by Deven
193:03 queued 128:11
created

DeleteStatement::parse()   D

Complexity

Conditions 41
Paths 22

Size

Total Lines 177
Code Lines 111

Duplication

Lines 32
Ratio 18.08 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 41
eloc 111
c 1
b 0
f 0
nc 22
nop 2
dl 32
loc 177
rs 4.1818

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
            if ($state === 0) {
203
                if ($token->type === Token::TYPE_KEYWORD
204
                    && $token->value !== 'FROM'
205
                ) {
206
                    $parser->error(__('Unexpected keyword.'), $token);
207
                    break;
208
                } elseif ($token->type === Token::TYPE_KEYWORD
209
                    && $token->value === 'FROM'
210
                ) {
211
                    ++$list->idx; // Skip 'FROM'
212
                    $this->from = ExpressionArray::parse($parser, $list);
213
                    $state = 2;
214
                } else {
215
                    $this->columns = ExpressionArray::parse($parser, $list);
216
                    $state = 1;
217
                }
218 View Code Duplication
            } elseif ($state === 1) {
219
                if ($token->type === Token::TYPE_KEYWORD
220
                    && $token->value !== 'FROM'
221
                ) {
222
                    $parser->error(__('Unexpected keyword.'), $token);
223
                    break;
224
                } elseif ($token->type === Token::TYPE_KEYWORD
225
                    && $token->value === 'FROM'
226
                ) {
227
                    ++$list->idx; // Skip 'FROM'
228
                    $this->from = ExpressionArray::parse($parser, $list);
229
                    $state = 2;
230
                } else {
231
                    $parser->error(__('Unexpected token.'), $token);
232
                    break;
233
                }
234
            } elseif ($state === 2) {
235
                if ($token->type === Token::TYPE_KEYWORD
236
                    && $token->value === 'USING'
237
                ) {
238
                    ++$list->idx; // Skip 'USING'
239
                    $this->using = ExpressionArray::parse($parser, $list);
240
                    $state = 3;
241
242
                    $multiTable = true;
243
                } elseif ($token->type === Token::TYPE_KEYWORD
244
                    && $token->value === 'WHERE'
245
                ) {
246
                    ++$list->idx; // Skip 'WHERE'
247
                    $this->where = Condition::parse($parser, $list);
248
                    $state = 4;
249
                } elseif ($token->type === Token::TYPE_KEYWORD
250
                    && $token->value === 'ORDER BY'
251
                ) {
252
                    ++$list->idx; // Skip 'ORDER BY'
253
                    $this->order = OrderKeyword::parse($parser, $list);
254
                    $state = 5;
255
                } elseif ($token->type === Token::TYPE_KEYWORD
256
                    && $token->value === 'LIMIT'
257
                ) {
258
                    ++$list->idx; // Skip 'LIMIT'
259
                    $this->limit = Limit::parse($parser, $list);
260
                    $state = 6;
261
                } elseif ($token->type === Token::TYPE_KEYWORD) {
262
                    $parser->error(__('Unexpected keyword.'), $token);
263
                    break;
264
                }
265 View Code Duplication
            } elseif ($state === 3) {
266
                if ($token->type === Token::TYPE_KEYWORD
267
                    && $token->value === 'WHERE'
268
                ) {
269
                    ++$list->idx; // Skip 'WHERE'
270
                    $this->where = Condition::parse($parser, $list);
271
                    $state = 4;
272
                } elseif ($token->type === Token::TYPE_KEYWORD) {
273
                    $parser->error(__('Unexpected keyword.'), $token);
274
                    break;
275
                } else {
276
                    $parser->error(__('Unexpected token.'), $token);
277
                    break;
278
                }
279
            } elseif ($state === 4) {
280
                if ($multiTable === true
281
                    && $token->type === Token::TYPE_KEYWORD
282
                ) {
283
                    $parser->error(
284
                        __('This type of clause is not valid in Multi-table queries.'),
285
                        $token
286
                    );
287
                    break;
288
                }
289
290
                if ($token->type === Token::TYPE_KEYWORD
291
                    && $token->value === 'ORDER BY'
292
                ) {
293
                    ++$list->idx; // Skip 'ORDER  BY'
294
                    $this->order = OrderKeyword::parse($parser, $list);
295
                    $state = 5;
296
                }  elseif ($token->type === Token::TYPE_KEYWORD
297
                    && $token->value === 'LIMIT'
298
                ) {
299
                    ++$list->idx; // Skip 'LIMIT'
300
                    $this->limit = Limit::parse($parser, $list);
301
                    $state = 6;
302
                } elseif ($token->type === Token::TYPE_KEYWORD) {
303
                    $parser->error(__('Unexpected keyword.'), $token);
304
                    break;
305
                }
306
            } elseif ($state === 5) {
307
                if ($token->type === Token::TYPE_KEYWORD
308
                    && $token->value === 'LIMIT'
309
                ) {
310
                    ++$list->idx; // Skip 'LIMIT'
311
                    $this->limit = Limit::parse($parser, $list);
312
                    $state = 6;
313
                } elseif ($token->type === Token::TYPE_KEYWORD) {
314
                    $parser->error(__('Unexpected keyword.'), $token);
315
                    break;
316
                }
317
            }
318
        }
319
320
        if ($state >= 2) {
321
            foreach ($this->from as $from_expr) {
322
                $from_expr->database = $from_expr->table;
323
                $from_expr->table = $from_expr->column;
324
                $from_expr->column = null;
325
            }
326
        }
327
328
        --$list->idx;
329
    }
330
}
331