GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 8abffd...754ed9 )
by Charlotte
03:13
created

StatementExecuteCommand   F

Complexity

Total Complexity 70

Size/Duplication

Total Lines 347
Duplicated Lines 0 %

Test Coverage

Coverage 88.38%

Importance

Changes 0
Metric Value
eloc 207
dl 0
loc 347
ccs 175
cts 198
cp 0.8838
rs 2.8
c 0
b 0
f 0
wmc 70

7 Methods

Rating   Name   Duplication   Size   Complexity  
A parseResultsetRow() 0 36 6
A __construct() 0 5 1
A resetSequence() 0 2 1
B stdEncodeValue() 0 42 11
B getEncodedMessage() 0 46 6
F stdDecodeBinaryValue() 0 140 43
A zeroFillInts() 0 8 2

How to fix   Complexity   

Complex Class

Complex classes like StatementExecuteCommand often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use StatementExecuteCommand, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Plasma Driver MySQL component
4
 * Copyright 2018 PlasmaPHP, All Rights Reserved
5
 *
6
 * Website: https://github.com/PlasmaPHP
7
 * License: https://github.com/PlasmaPHP/driver-mysql/blob/master/LICENSE
8
*/
9
10
namespace Plasma\Drivers\MySQL\Commands;
11
12
/**
13
 * Statement Execute command.
14
 * @internal
15
 */
16
class StatementExecuteCommand extends QueryCommand {
17
    /**
18
     * The identifier for this command.
19
     * @var int
20
     * @source
21
     */
22
    const COMMAND_ID = 0x17;
23
    
24
    /**
25
     * @var mixed
26
     */
27
    protected $id;
28
    
29
    /**
30
     * @var array
31
     */
32
    protected $params;
33
    
34
    /**
35
     * Constructor.
36
     * @param \Plasma\DriverInterface  $driver
37
     * @param mixed                    $id
38
     * @param string                   $query
39
     * @param array                    $params
40
     */
41 35
    function __construct(\Plasma\DriverInterface $driver, $id, string $query, array $params) {
42 35
        parent::__construct($driver, $query);
43
        
44 35
        $this->id = $id;
45 35
        $this->params = $params;
46 35
    }
47
    
48
    /**
49
     * Get the encoded message for writing to the database connection.
50
     * @return string
51
     */
52 34
    function getEncodedMessage(): string {
53 34
        $packet = \chr(static::COMMAND_ID);
54 34
        $packet .= \Plasma\BinaryBuffer::writeInt4($this->id);
55
        
56 34
        $packet .= "\x00"; // Cursor type flag
57 34
        $packet .= \Plasma\BinaryBuffer::writeInt4(1); // Iteration count is always 1
58
        
59 34
        $bitmapOffset = \strlen($packet);
60 34
        $packet .= \str_repeat("\x00", ((\count($this->params) + 7) >> 3));
61
        
62 34
        $bound = 0;
63
        
64 34
        $types = '';
65 34
        $values = '';
66
        
67 34
        foreach($this->params as $id => $param) {
68 34
            if($param === null) {
69 1
                $offset = $bitmapOffset + ($id >> 3);
70 1
                $packet[$offset] = $packet[$offset] | \chr((1 << ($id % 8)));
71
            } else {
72 34
                $bound = 1;
73
            }
74
            
75
            try {
76 34
                $manager = \Plasma\Types\TypeExtensionsManager::getManager('driver-mysql');
77
                $encode = $manager->encodeType($param);
78
                
79
                $unsigned = $encode->isUnsigned();
80
                $type = $encode->getSQLType();
81
                $value = $encode->getValue();
82 34
            } catch (\Plasma\Exception $e) {
83 34
                [ $unsigned, $type, $value ] = $this->stdEncodeValue($param);
84
            }
85
            
86 34
            $types .= \chr($type).($unsigned ? "\x80" : "\x00");
87 34
            $values .= $value;
88
        }
89
        
90 34
        $packet .= \chr($bound);
91
        
92 34
        if($bound) {
93 34
            $packet .= $types;
94 34
            $packet .= $values;
95
        }
96
        
97 34
        return $packet;
98
    }
99
    
100
    /**
101
     * Whether the sequence ID should be resetted.
102
     * @return bool
103
     */
104 34
    function resetSequence(): bool {
105 34
        return true;
106
    }
107
    
108
    /**
109
     * Parses the binary resultset row and returns the row.
110
     * @param \Plasma\BinaryBuffer  $buffer
111
     * @return array
112
     */
113 34
    protected function parseResultsetRow(\Plasma\BinaryBuffer $buffer): array {
114 34
        $buffer->read(1); // remove packet header
115
        
116 34
        $nullRow = array();
117 34
        $i = 0;
118
        
119
        /** @var \Plasma\ColumnDefinitionInterface  $column */
120 34
        foreach($this->fields as $column) { // Handle NULL-bitmap
121 34
            if((\ord($buffer[(($i + 2) >> 3)]) & (1 << (($i + 2) % 8))) !== 0) {
122 2
                $nullRow[$column->getName()] = null;
123
            }
124
            
125 34
            $i++;
126
        }
127
        
128 34
        $buffer->read(((\count($this->fields) + 9) >> 3)); // Remove NULL-bitmap
129 34
        $row = array();
130
        
131
        /** @var \Plasma\ColumnDefinitionInterface  $column */
132 34
        foreach($this->fields as $column) {
133 34
            if(\array_key_exists($column->getName(), $nullRow)) {
134 2
                $row[$column->getName()] = null;
135 2
                continue;
136
            }
137
            
138 34
            $value = $this->stdDecodeBinaryValue($column, $buffer);
139 34
            $parsedValue = $column->parseValue($value);
140
            
141 34
            if($value !== $parsedValue) {
142
                $value = $parsedValue;
143
            }
144
            
145 34
            $row[$column->getName()] = $value;
146
        }
147
        
148 34
        return $row;
149
    }
150
    
151
    /**
152
     * Standard encode value, if type extensions failed.
153
     * @param mixed                              $param
154
     * @return array
155
     * @throws \Plasma\Exception
156
     */
157 34
    protected function stdEncodeValue($param): array {
158 34
        $unsigned = false;
159
        
160 34
        switch(\gettype($param)) {
161
            case 'boolean':
162
                $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_TINY;
163
                $value = ($param ? "\x01" : "\0");
164
            break;
165
            case 'integer':
166 6
                if($param >= 0) {
167 6
                    $unsigned = true;
168
                }
169
                
170 6
                if($param >= 0 && $param < (1 << 15)) {
171 6
                    $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_SHORT;
172 6
                    $value = \Plasma\BinaryBuffer::writeInt2($param);
173 3
                } elseif(\PHP_INT_SIZE === 4) {
174
                    $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_LONG;
175
                    $value = \Plasma\BinaryBuffer::writeInt4($param);
176
                } else {
177 3
                    $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_LONGLONG;
178 3
                    $value = \Plasma\BinaryBuffer::writeInt8($param);
179
                }
180 6
            break;
181
            case 'double':
182 2
                $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_DOUBLE;
183 2
                $value = \Plasma\BinaryBuffer::writeDouble($param);
184 2
            break;
185
            case 'string':
186 26
                $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_LONG_BLOB;
187 26
                $value = \Plasma\BinaryBuffer::writeStringLength($param);
188 26
            break;
189
            case 'NULL':
190 1
                $type = \Plasma\Drivers\MySQL\FieldFlags::FIELD_TYPE_NULL;
191 1
                $value = '';
192 1
            break;
193
            default:
194
                throw new \Plasma\Exception('Unexpected type for binding parameter: '.\gettype($param));
195
            break;
196
        }
197
        
198 34
        return array($unsigned, $type, $value);
199
    }
200
    
201
    /**
202
     * Standard decode value, if type extensions failed.
203
     * @param \Plasma\ColumnDefinitionInterface  $column
204
     * @param \Plasma\BinaryBuffer               $buffer
205
     * @return mixed
206
     * @throws \Plasma\Exception
207
     */
208 34
    protected function stdDecodeBinaryValue(\Plasma\ColumnDefinitionInterface $column, \Plasma\BinaryBuffer $buffer) {
209 34
        $flags = $column->getFlags();
210 34
        $type = $column->getType();
211
        
212
        switch(true) {
213 34
            case ($type === 'STRING'):
214 34
            case ($type === 'VARCHAR'):
215 34
            case ($type === 'VARSTRING'):
216 32
            case ($type === 'ENUM'):
217 32
            case ($type === 'SET'):
218 32
            case ($type === 'LONGBLOB'):
219 32
            case ($type === 'MEDIUMBLOB'):
220 32
            case ($type === 'BLOB'):
221 32
            case ($type === 'TINY_BLOB'):
222 32
            case ($type === 'GEOMETRY'):
223 32
            case ($type === 'BIT'):
224 32
            case ($type === 'DECIMAL'):
225 32
            case ($type === 'NEWDECIMAL'):
226 16
            case ($type === 'JSON'):
227 18
                $value = $buffer->readStringLength();
228 18
            break;
229 16
            case ($type === 'TINY'):
230 6
                $value = $buffer->readInt1();
231 6
                $value = $this->zeroFillInts($column, $value);
232 6
            break;
233 16
            case ($type === 'SHORT'):
234 16
            case ($type === 'YEAR'):
235 6
                $value = $buffer->readInt2();
236 6
                $value = $this->zeroFillInts($column, $value);
237 6
            break;
238 16
            case ($type === 'INT24'):
239 16
            case ($type === 'LONG'):
240 6
                $value = $buffer->readInt4();
241
                
242 6
                if(($flags & \Plasma\Drivers\MySQL\FieldFlags::UNSIGNED_FLAG) !== 0 && \PHP_INT_SIZE <= 4) {
243
                    $value = \bcadd($value, '18446744073709551616');
244
                }
245
                
246 6
                $value = $this->zeroFillInts($column, $value);
247 6
            break;
248 16
            case ($type === 'LONGLONG'):
249 6
                $value = $buffer->readInt8();
250
                
251 6
                if(($flags & \Plasma\Drivers\MySQL\FieldFlags::UNSIGNED_FLAG) !== 0) {
252
                    $value = \bcadd($value, '18446744073709551616');
253 6
                } elseif(\PHP_INT_SIZE > 4) {
254 6
                    $value = (int) $value;
255
                }
256
                
257 6
                $value = $this->zeroFillInts($column, $value);
258 6
            break;
259 10
            case ($type === 'FLOAT'):
260 2
                $value = $buffer->readFloat();
261 2
            break;
262 10
            case ($type === 'DOUBLE'):
263 2
                $value = $buffer->readDouble();
264 2
            break;
265 8
            case ($type === 'DATE'):
266 8
            case ($type === 'NEWDATE'):
267 8
                $length = $buffer->readIntLength();
268 8
                if($length > 0) {
269 1
                    $year = $buffer->readInt2();
270 1
                    $month = $buffer->readInt1();
271 1
                    $day = $buffer->readInt1();
272
                    
273 1
                    $value = \sprintf('%04d-%02d-%02d', $year, $month, $day);
274
                } else {
275 7
                    $value = '0000-00-00';
276
                }
277 8
            break;
278 8
            case ($type === 'DATETIME'):
279 8
            case ($type === 'TIMESTAMP'):
280 8
                $length = $buffer->readIntLength();
281 8
                if($length > 0) {
282 2
                    $year = $buffer->readInt2();
283 2
                    $month = $buffer->readInt1();
284 2
                    $day = $buffer->readInt1();
285
                    
286 2
                    if($length > 4) {
287 1
                        $hour = $buffer->readInt1();
288 1
                        $min = $buffer->readInt1();
289 1
                        $sec = $buffer->readInt1();
290
                    } else {
291 1
                        $hour = 0;
292 1
                        $min = 0;
293 1
                        $sec = 0;
294
                    }
295
                    
296 2
                    if($length > 7) {
297
                        $microI = $buffer->readInt4();
298
                    } else {
299 2
                        $microI = 0;
300
                    }
301
                    
302 2
                    $micro = \str_pad($microI, 6, '0', \STR_PAD_LEFT);
303 2
                    $micro = \substr($micro, 0, 3).' '.\substr($micro, 3);
304
                    
305 2
                    $value = \sprintf('%04d-%02d-%02d %02d:%02d:%02d'.($microI > 0 ? '.%s' : ''), $year, $month, $day, $hour, $min, $sec, $micro);
306
                    
307 2
                    if($type === 'TIMESTAMP') {
308 2
                        $value = \DateTime::createFromFormat('Y-m-d H:i:s'.($microI > 0 ? '.u' : ''), $value)->getTimestamp();
309
                    }
310
                } else {
311 8
                    $value = '0000-00-00 00:00:00.000 000';
312
                }
313 8
            break;
314 8
            case ($type === 'TIME'):
315 8
                $length = $buffer->readIntLength();
316 8
                if($length > 1) {
317 1
                    $sign = $buffer->readInt1();
318 1
                    $days = $buffer->readInt4();
319
                    
320 1
                    if($sign === 1) {
321
                        $days *= -1;
322
                    }
323
                    
324 1
                    $hour = $buffer->readInt1();
325 1
                    $min = $buffer->readInt1();
326 1
                    $sec = $buffer->readInt1();
327
                    
328 1
                    if($length > 8) {
329
                        $microI = $buffer->readInt4();
330
                    } else {
331 1
                        $microI = 0;
332
                    }
333
                    
334 1
                    $micro = \str_pad($microI, 6, '0', \STR_PAD_LEFT);
335 1
                    $micro = \substr($micro, 0, 3).' '.\substr($micro, 3);
336
                    
337 1
                    $value = \sprintf('%dd %02d:%02d:%02d'.($microI > 0 ? '.%s' : ''), $days, $hour, $min, $sec, $micro);
338
                } else {
339 7
                    $value = '0d 00:00:00';
340
                }
341 8
            break;
342
            default:
343
                throw new \InvalidArgumentException('Unknown column type (flags: '.$flags.', type: '.$column->getType().')');
344
            break;
345
        }
346
        
347 34
        return $value;
348
    }
349
    
350
    /**
351
     * @param \Plasma\ColumnDefinitionInterface  $column
352
     * @param string|int                         $value
353
     * @return string|int
354
     */
355 6
    protected function zeroFillInts(\Plasma\ColumnDefinitionInterface $column, $value) {
356 6
        $flags = $column->getFlags();
357
        
358 6
        if(($flags & \Plasma\Drivers\MySQL\FieldFlags::ZEROFILL_FLAG) !== 0) {
359 6
            $value = \str_pad(((string) $value), $column->getLength(), '0', \STR_PAD_LEFT);
360
        }
361
        
362 6
        return $value;
363
    }
364
}
365