Completed
Pull Request — master (#77)
by Deven
229:23 queued 164:06
created

ReplaceStatement::parse()   D

Complexity

Conditions 14
Paths 5

Size

Total Lines 91
Code Lines 47

Duplication

Lines 39
Ratio 42.86 %

Importance

Changes 0
Metric Value
cc 14
eloc 47
c 0
b 0
f 0
nc 5
nop 2
dl 39
loc 91
rs 4.9516

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
 * `REPLACE` statement.
5
 *
6
 * @package    SqlParser
7
 * @subpackage Statements
8
 */
9
namespace SqlParser\Statements;
10
11
use SqlParser\Parser;
12
use SqlParser\Token;
13
use SqlParser\TokensList;
14
use SqlParser\Statement;
15
use SqlParser\Statements\SelectStatement;
16
use SqlParser\Components\Array2d;
17
use SqlParser\Components\IntoKeyword;
18
use SqlParser\Components\OptionsArray;
19
use SqlParser\Components\SetOperation;
20
21
/**
22
 * `REPLACE` statement.
23
 *
24
 * REPLACE [LOW_PRIORITY | DELAYED]
25
 *     [INTO] tbl_name [(col_name,...)]
26
 *     {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
27
 *
28
 * or
29
 *
30
 * REPLACE [LOW_PRIORITY | DELAYED]
31
 *     [INTO] tbl_name
32
 *     SET col_name={expr | DEFAULT}, ...
33
 *
34
 * or
35
 *
36
 * REPLACE [LOW_PRIORITY | DELAYED]
37
 *   [INTO] tbl_name
38
 *   [PARTITION (partition_name,...)]
39
 *   [(col_name,...)]
40
 *   SELECT ...
41
 *
42
 * @category   Statements
43
 * @package    SqlParser
44
 * @subpackage Statements
45
 * @author     Dan Ungureanu <[email protected]>
46
 * @license    http://opensource.org/licenses/GPL-2.0 GNU Public License
47
 */
48
class ReplaceStatement extends Statement
49
{
50
51
    /**
52
     * Options for `REPLACE` statements and their slot ID.
53
     *
54
     * @var array
55
     */
56
    public static $OPTIONS = array(
57
        'LOW_PRIORITY'                  => 1,
58
        'DELAYED'                       => 1,
59
    );
60
61
    /**
62
     * Tables used as target for this statement.
63
     *
64
     * @var IntoKeyword
65
     */
66
    public $into;
67
68
    /**
69
     * Values to be replaced.
70
     *
71
     * @var Array2d
72
     */
73
    public $values;
74
75
    /**
76
     * If SET clause is present
77
     * holds the SetOperation
78
     *
79
     * @var SetOperation[]
80
     */
81
    public $set;
82
83
    /**
84
     * If SELECT clause is present
85
     * holds the SelectStatement
86
     *
87
     * @var SelectStatement
88
     */
89
    public $select;
90
91
    /**
92
     * @return string
93
     */
94
    public function build()
95
    {
96
        $ret = 'REPLACE ' . $this->options
97
            . ' INTO ' . $this->into;
98
99 View Code Duplication
        if ($this->values != NULL && count($this->values) > 0) {
100
            $ret .= ' VALUES ' . Array2d::build($this->values);
0 ignored issues
show
Documentation introduced by
$this->values is of type object<SqlParser\Components\Array2d>, but the function expects a array<integer,object<Sql...r\Components\ArrayObj>>.

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...
101
        } elseif ($this->set != NULL && count($this->set) > 0) {
102
            $ret .= ' SET ' . SetOperation::build($this->set);
103
        } elseif ($this->select != NULL && count($this->select) > 0) {
104
            $ret .= ' ' . $this->select->build();
105
        }
106
107
        return $ret;
108
    }
109
110
111
    /**
112
     * @param Parser     $parser The instance that requests parsing.
113
     * @param TokensList $list   The list of tokens to be parsed.
114
     *
115
     * @return void
116
     */
117
    public function parse(Parser $parser, TokensList $list)
118
    {
119
        ++$list->idx; // Skipping `REPLACE`.
120
121
        // parse any options if provided
122
        $this->options = OptionsArray::parse(
123
            $parser,
124
            $list,
125
            static::$OPTIONS
126
        );
127
        ++$list->idx;
128
129
        $token = $list->tokens[$list->idx];
0 ignored issues
show
Unused Code introduced by
$token is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
130
131
        /**
132
         * The state of the parser.
133
         *
134
         * Below are the states of the parser.
135
         *
136
         *      0 ---------------------------------[ INTO ]----------------------------------> 1
137
         *
138
         *      1 -------------------------[ VALUES/VALUE/SET/SELECT ]-----------------------> 2
139
         *
140
         * @var int $state
141
         */
142
        $state = 0;
143
144
        for (; $list->idx < $list->count; ++$list->idx) {
145
            /**
146
             * Token parsed at this moment.
147
             *
148
             * @var Token $token
149
             */
150
            $token = $list->tokens[$list->idx];
151
152
            // End of statement.
153
            if ($token->type === Token::TYPE_DELIMITER) {
154
                break;
155
            }
156
157
            // Skipping whitespaces and comments.
158
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
159
                continue;
160
            }
161
162
            if ($state === 0) {
163 View Code Duplication
                if ($token->type === Token::TYPE_KEYWORD
164
                    && $token->value !== 'INTO'
165
                ) {
166
                    $parser->error(__('Unexpected keyword.'), $token);
167
                    break;
168
                } else {
169
                    ++$list->idx;
170
                    $this->into = IntoKeyword::parse($parser, $list);
171
                }
172
173
                $state = 1;
174 View Code Duplication
            } elseif ($state === 1) {
175
                if ($token->type === Token::TYPE_KEYWORD) {
176
                    if ($token->value === 'VALUE'
177
                        || $token->value === 'VALUES'
178
                    ) {
179
                        ++$list->idx; // skip VALUES
180
181
                        $this->values = Array2d::parse($parser, $list);
0 ignored issues
show
Documentation Bug introduced by
It seems like \SqlParser\Components\Ar...::parse($parser, $list) of type array<integer,object<Sql...r\Components\ArrayObj>> is incompatible with the declared type object<SqlParser\Components\Array2d> of property $values.

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...
182
                    } elseif ($token->value === 'SET') {
183
                        ++$list->idx; // skip SET
184
185
                        $this->set = SetOperation::parse($parser, $list);
186
                    } elseif ($token->value === 'SELECT') {
187
                        $this->select = new SelectStatement($parser, $list);
188
                    } else {
189
                        $parser->error(
190
                            __('Unexpected keyword.'),
191
                            $token
192
                        );
193
                        break;
194
                    }
195
                    $state = 2;
196
                } else {
197
                    $parser->error(
198
                        __('Unexpected token.'),
199
                        $token
200
                    );
201
                    break;
202
                }
203
            }
204
        }
205
206
        --$list->idx;
207
    }
208
}
209