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

ReplaceStatement   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 159
Duplicated Lines 31.45 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 50
loc 159
ccs 65
cts 65
cp 1
rs 10
c 1
b 0
f 0
wmc 21
lcom 1
cbo 8

2 Methods

Rating   Name   Duplication   Size   Complexity  
B build() 7 15 7
D parse() 43 93 14

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * `REPLACE` statement.
5
 */
6
7
namespace PhpMyAdmin\SqlParser\Statements;
8
9
use PhpMyAdmin\SqlParser\Parser;
10
use PhpMyAdmin\SqlParser\Token;
11
use PhpMyAdmin\SqlParser\TokensList;
12
use PhpMyAdmin\SqlParser\Statement;
13
use PhpMyAdmin\SqlParser\Components\Array2d;
14
use PhpMyAdmin\SqlParser\Components\IntoKeyword;
15
use PhpMyAdmin\SqlParser\Components\OptionsArray;
16
use PhpMyAdmin\SqlParser\Components\SetOperation;
17
18
/**
19
 * `REPLACE` statement.
20
 *
21
 * REPLACE [LOW_PRIORITY | DELAYED]
22
 *     [INTO] tbl_name [(col_name,...)]
23
 *     {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
24
 *
25
 * or
26
 *
27
 * REPLACE [LOW_PRIORITY | DELAYED]
28
 *     [INTO] tbl_name
29
 *     SET col_name={expr | DEFAULT}, ...
30
 *
31
 * or
32
 *
33
 * REPLACE [LOW_PRIORITY | DELAYED]
34
 *   [INTO] tbl_name
35
 *   [PARTITION (partition_name,...)]
36
 *   [(col_name,...)]
37
 *   SELECT ...
38
 *
39
 * @category   Statements
40
 *
41
 * @license    https://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
42
 */
43
class ReplaceStatement extends Statement
44
{
45
    /**
46
     * Options for `REPLACE` statements and their slot ID.
47
     *
48
     * @var array
49
     */
50
    public static $OPTIONS = array(
51
        'LOW_PRIORITY' => 1,
52
        'DELAYED' => 1,
53
    );
54
55
    /**
56
     * Tables used as target for this statement.
57
     *
58
     * @var IntoKeyword
59
     */
60
    public $into;
61
62
    /**
63
     * Values to be replaced.
64
     *
65
     * @var Array2d
66
     */
67
    public $values;
68
69
    /**
70
     * If SET clause is present
71
     * holds the SetOperation.
72
     *
73
     * @var SetOperation[]
74
     */
75
    public $set;
76
77
    /**
78
     * If SELECT clause is present
79
     * holds the SelectStatement.
80
     *
81
     * @var SelectStatement
82
     */
83
    public $select;
84
85
    /**
86
     * @return string
87
     */
88 3
    public function build()
89
    {
90 3
        $ret = 'REPLACE ' . $this->options
91 3
            . ' INTO ' . $this->into;
92
93 3 View Code Duplication
        if ($this->values != null && count($this->values) > 0) {
94 1
            $ret .= ' VALUES ' . Array2d::build($this->values);
0 ignored issues
show
Documentation introduced by
$this->values is of type object<PhpMyAdmin\SqlParser\Components\Array2d>, but the function expects a array<integer,object<Php...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...
95 3
        } elseif ($this->set != null && count($this->set) > 0) {
96 1
            $ret .= ' SET ' . SetOperation::build($this->set);
97 2
        } elseif ($this->select != null && strlen($this->select) > 0) {
98 1
            $ret .= ' ' . $this->select->build();
99 1
        }
100
101 3
        return $ret;
102
    }
103
104
    /**
105
     * @param Parser     $parser the instance that requests parsing
106
     * @param TokensList $list   the list of tokens to be parsed
107
     */
108 13
    public function parse(Parser $parser, TokensList $list)
109
    {
110 13
        ++$list->idx; // Skipping `REPLACE`.
111
112
        // parse any options if provided
113 13
        $this->options = OptionsArray::parse(
114 13
            $parser,
115 13
            $list,
116
            static::$OPTIONS
117 13
        );
118 13
        ++$list->idx;
119
120
        /**
121
         * The state of the parser.
122
         *
123
         * Below are the states of the parser.
124
         *
125
         *      0 ---------------------------------[ INTO ]----------------------------------> 1
126
         *
127
         *      1 -------------------------[ VALUES/VALUE/SET/SELECT ]-----------------------> 2
128
         *
129
         * @var int
130
         */
131 13
        $state = 0;
132
133 13
        for (; $list->idx < $list->count; ++$list->idx) {
134
            /**
135
             * Token parsed at this moment.
136
             *
137
             * @var Token
138
             */
139 13
            $token = $list->tokens[$list->idx];
140
141
            // End of statement.
142 13
            if ($token->type === Token::TYPE_DELIMITER) {
143 9
                break;
144
            }
145
146
            // Skipping whitespaces and comments.
147 13
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
148 8
                continue;
149
            }
150
151 13
            if ($state === 0) {
152 13 View Code Duplication
                if ($token->type === Token::TYPE_KEYWORD
153 13
                    && $token->value !== 'INTO'
154 13
                ) {
155 1
                    $parser->error(__('Unexpected keyword.'), $token);
156 1
                    break;
157
                } else {
158 12
                    ++$list->idx;
159 12
                    $this->into = IntoKeyword::parse(
160 12
                        $parser,
161 12
                        $list,
162 12
                        array('fromReplace' => true)
163 12
                    );
164
                }
165
166 12
                $state = 1;
167 12 View Code Duplication
            } elseif ($state === 1) {
168 12
                if ($token->type === Token::TYPE_KEYWORD) {
169 10
                    if ($token->value === 'VALUE'
170 10
                        || $token->value === 'VALUES'
171 10
                    ) {
172 4
                        ++$list->idx; // skip VALUES
173
174 4
                        $this->values = Array2d::parse($parser, $list);
0 ignored issues
show
Documentation Bug introduced by
It seems like \PhpMyAdmin\SqlParser\Co...::parse($parser, $list) of type array<integer,object<Php...r\Components\ArrayObj>> is incompatible with the declared type object<PhpMyAdmin\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...
175 10
                    } elseif ($token->value === 'SET') {
176 3
                        ++$list->idx; // skip SET
177
178 3
                        $this->set = SetOperation::parse($parser, $list);
179 6
                    } elseif ($token->value === 'SELECT') {
180 2
                        $this->select = new SelectStatement($parser, $list);
181 2
                    } else {
182 1
                        $parser->error(
183 1
                            __('Unexpected keyword.'),
184
                            $token
185 1
                        );
186 1
                        break;
187
                    }
188 9
                    $state = 2;
189 9
                } else {
190 2
                    $parser->error(
191 2
                        __('Unexpected token.'),
192
                        $token
193 2
                    );
194 2
                    break;
195
                }
196 9
            }
197 12
        }
198
199 13
        --$list->idx;
200 13
    }
201
}
202