Failed Conditions
Push — master ( edfbda...298c91 )
by Luís
16s
created

DB2Statement   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 335
Duplicated Lines 26.87 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 50
dl 90
loc 335
ccs 0
cts 181
cp 0
rs 8.6206
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A columnCount() 0 7 2
B execute() 0 25 5
A setFetchMode() 7 7 3
A fetchColumn() 9 9 3
A bindParam() 0 15 4
A rowCount() 0 3 2
A closeCursor() 0 15 3
A errorCode() 0 3 1
B castObject() 10 51 6
A getIterator() 0 3 1
A __construct() 0 3 1
A bindValue() 0 3 1
C fetch() 37 37 11
A errorInfo() 0 5 1
B fetchAll() 22 22 6

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like DB2Statement 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 DB2Statement, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Driver\IBMDB2;
21
22
use Doctrine\DBAL\Driver\Statement;
23
use Doctrine\DBAL\Driver\StatementIterator;
24
25
class DB2Statement implements \IteratorAggregate, Statement
26
{
27
    /**
28
     * @var resource
29
     */
30
    private $_stmt;
31
32
    /**
33
     * @var array
34
     */
35
    private $_bindParam = [];
36
37
    /**
38
     * @var string Name of the default class to instantiate when fetch mode is \PDO::FETCH_CLASS.
39
     */
40
    private $defaultFetchClass = '\stdClass';
41
42
    /**
43
     * @var string Constructor arguments for the default class to instantiate when fetch mode is \PDO::FETCH_CLASS.
44
     */
45
    private $defaultFetchClassCtorArgs = [];
46
47
    /**
48
     * @var integer
49
     */
50
    private $_defaultFetchMode = \PDO::FETCH_BOTH;
51
52
    /**
53
     * Indicates whether the statement is in the state when fetching results is possible
54
     *
55
     * @var bool
56
     */
57
    private $result = false;
58
59
    /**
60
     * DB2_BINARY, DB2_CHAR, DB2_DOUBLE, or DB2_LONG
61
     *
62
     * @var array
63
     */
64
    static private $_typeMap = [
65
        \PDO::PARAM_INT => DB2_LONG,
0 ignored issues
show
Bug introduced by
The constant Doctrine\DBAL\Driver\IBMDB2\DB2_LONG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
66
        \PDO::PARAM_STR => DB2_CHAR,
0 ignored issues
show
Bug introduced by
The constant Doctrine\DBAL\Driver\IBMDB2\DB2_CHAR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
67
    ];
68
69
    /**
70
     * @param resource $stmt
71
     */
72
    public function __construct($stmt)
73
    {
74
        $this->_stmt = $stmt;
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    public function bindValue($param, $value, $type = null)
81
    {
82
        return $this->bindParam($param, $value, $type);
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88
    public function bindParam($column, &$variable, $type = null, $length = null)
89
    {
90
        $this->_bindParam[$column] =& $variable;
91
92
        if ($type && isset(self::$_typeMap[$type])) {
93
            $type = self::$_typeMap[$type];
94
        } else {
95
            $type = DB2_CHAR;
0 ignored issues
show
Bug introduced by
The constant Doctrine\DBAL\Driver\IBMDB2\DB2_CHAR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
96
        }
97
98
        if (!db2_bind_param($this->_stmt, $column, "variable", DB2_PARAM_IN, $type)) {
0 ignored issues
show
Bug introduced by
The function db2_bind_param was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

98
        if (!/** @scrutinizer ignore-call */ db2_bind_param($this->_stmt, $column, "variable", DB2_PARAM_IN, $type)) {
Loading history...
Bug introduced by
The constant Doctrine\DBAL\Driver\IBMDB2\DB2_PARAM_IN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
99
            throw new DB2Exception(db2_stmt_errormsg());
0 ignored issues
show
Bug introduced by
The function db2_stmt_errormsg was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

99
            throw new DB2Exception(/** @scrutinizer ignore-call */ db2_stmt_errormsg());
Loading history...
100
        }
101
102
        return true;
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108
    public function closeCursor()
109
    {
110
        if ( ! $this->_stmt) {
111
            return false;
112
        }
113
114
        $this->_bindParam = [];
115
116
        if (!db2_free_result($this->_stmt)) {
0 ignored issues
show
Bug introduced by
The function db2_free_result was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

116
        if (!/** @scrutinizer ignore-call */ db2_free_result($this->_stmt)) {
Loading history...
117
            return false;
118
        }
119
120
        $this->result = false;
121
122
        return true;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function columnCount()
129
    {
130
        if ( ! $this->_stmt) {
131
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the return type mandated by Doctrine\DBAL\Driver\Res...tatement::columnCount() of integer.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
132
        }
133
134
        return db2_num_fields($this->_stmt);
0 ignored issues
show
Bug introduced by
The function db2_num_fields was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

134
        return /** @scrutinizer ignore-call */ db2_num_fields($this->_stmt);
Loading history...
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function errorCode()
141
    {
142
        return db2_stmt_error();
0 ignored issues
show
Bug introduced by
The function db2_stmt_error was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

142
        return /** @scrutinizer ignore-call */ db2_stmt_error();
Loading history...
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148
    public function errorInfo()
149
    {
150
        return [
151
            db2_stmt_errormsg(),
0 ignored issues
show
Bug introduced by
The function db2_stmt_errormsg was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

151
            /** @scrutinizer ignore-call */ 
152
            db2_stmt_errormsg(),
Loading history...
152
            db2_stmt_error(),
0 ignored issues
show
Bug introduced by
The function db2_stmt_error was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

152
            /** @scrutinizer ignore-call */ 
153
            db2_stmt_error(),
Loading history...
153
        ];
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159
    public function execute($params = null)
160
    {
161
        if ( ! $this->_stmt) {
162
            return false;
163
        }
164
165
        if ($params === null) {
166
            ksort($this->_bindParam);
167
168
            $params = [];
169
170
            foreach ($this->_bindParam as $column => $value) {
171
                $params[] = $value;
172
            }
173
        }
174
175
        $retval = @db2_execute($this->_stmt, $params);
0 ignored issues
show
Bug introduced by
The function db2_execute was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

175
        $retval = @/** @scrutinizer ignore-call */ db2_execute($this->_stmt, $params);
Loading history...
176
177
        if ($retval === false) {
178
            throw new DB2Exception(db2_stmt_errormsg());
0 ignored issues
show
Bug introduced by
The function db2_stmt_errormsg was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

178
            throw new DB2Exception(/** @scrutinizer ignore-call */ db2_stmt_errormsg());
Loading history...
179
        }
180
181
        $this->result = true;
182
183
        return $retval;
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     */
189 View Code Duplication
    public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
190
    {
191
        $this->_defaultFetchMode         = $fetchMode;
192
        $this->defaultFetchClass         = $arg2 ? $arg2 : $this->defaultFetchClass;
193
        $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs;
0 ignored issues
show
Documentation Bug introduced by
It seems like $arg3 ? (array)$arg3 : $...faultFetchClassCtorArgs can also be of type array. However, the property $defaultFetchClassCtorArgs is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
194
195
        return true;
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201
    public function getIterator()
202
    {
203
        return new StatementIterator($this);
204
    }
205
206
    /**
207
     * {@inheritdoc}
208
     */
209 View Code Duplication
    public function fetch($fetchMode = null, $cursorOrientation = \PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
210
    {
211
        // do not try fetching from the statement if it's not expected to contain result
212
        // in order to prevent exceptional situation
213
        if (!$this->result) {
214
            return false;
215
        }
216
217
        $fetchMode = $fetchMode ?: $this->_defaultFetchMode;
218
        switch ($fetchMode) {
219
            case \PDO::FETCH_BOTH:
220
                return db2_fetch_both($this->_stmt);
0 ignored issues
show
Bug introduced by
The function db2_fetch_both was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

220
                return /** @scrutinizer ignore-call */ db2_fetch_both($this->_stmt);
Loading history...
221
            case \PDO::FETCH_ASSOC:
222
                return db2_fetch_assoc($this->_stmt);
0 ignored issues
show
Bug introduced by
The function db2_fetch_assoc was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

222
                return /** @scrutinizer ignore-call */ db2_fetch_assoc($this->_stmt);
Loading history...
223
            case \PDO::FETCH_CLASS:
224
                $className = $this->defaultFetchClass;
225
                $ctorArgs  = $this->defaultFetchClassCtorArgs;
226
227
                if (func_num_args() >= 2) {
228
                    $args      = func_get_args();
229
                    $className = $args[1];
230
                    $ctorArgs  = isset($args[2]) ? $args[2] : [];
231
                }
232
233
                $result = db2_fetch_object($this->_stmt);
0 ignored issues
show
Bug introduced by
The function db2_fetch_object was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

233
                $result = /** @scrutinizer ignore-call */ db2_fetch_object($this->_stmt);
Loading history...
234
235
                if ($result instanceof \stdClass) {
236
                    $result = $this->castObject($result, $className, $ctorArgs);
0 ignored issues
show
Bug introduced by
It seems like $ctorArgs can also be of type string; however, parameter $ctorArgs of Doctrine\DBAL\Driver\IBM...Statement::castObject() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

236
                    $result = $this->castObject($result, $className, /** @scrutinizer ignore-type */ $ctorArgs);
Loading history...
237
                }
238
239
                return $result;
240
            case \PDO::FETCH_NUM:
241
                return db2_fetch_array($this->_stmt);
0 ignored issues
show
Bug introduced by
The function db2_fetch_array was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

241
                return /** @scrutinizer ignore-call */ db2_fetch_array($this->_stmt);
Loading history...
242
            case \PDO::FETCH_OBJ:
243
                return db2_fetch_object($this->_stmt);
244
            default:
245
                throw new DB2Exception('Given Fetch-Style ' . $fetchMode . ' is not supported.');
246
        }
247
    }
248
249
    /**
250
     * {@inheritdoc}
251
     */
252 View Code Duplication
    public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
253
    {
254
        $rows = [];
255
256
        switch ($fetchMode) {
257
            case \PDO::FETCH_CLASS:
258
                while ($row = call_user_func_array([$this, 'fetch'], func_get_args())) {
259
                    $rows[] = $row;
260
                }
261
                break;
262
            case \PDO::FETCH_COLUMN:
263
                while ($row = $this->fetchColumn()) {
264
                    $rows[] = $row;
265
                }
266
                break;
267
            default:
268
                while ($row = $this->fetch($fetchMode)) {
269
                    $rows[] = $row;
270
                }
271
        }
272
273
        return $rows;
274
    }
275
276
    /**
277
     * {@inheritdoc}
278
     */
279 View Code Duplication
    public function fetchColumn($columnIndex = 0)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
280
    {
281
        $row = $this->fetch(\PDO::FETCH_NUM);
282
283
        if (false === $row) {
284
            return false;
285
        }
286
287
        return isset($row[$columnIndex]) ? $row[$columnIndex] : null;
288
    }
289
290
    /**
291
     * {@inheritdoc}
292
     */
293
    public function rowCount()
294
    {
295
        return (@db2_num_rows($this->_stmt)) ? : 0;
0 ignored issues
show
Bug introduced by
The function db2_num_rows was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

295
        return (@/** @scrutinizer ignore-call */ db2_num_rows($this->_stmt)) ? : 0;
Loading history...
296
    }
297
298
    /**
299
     * Casts a stdClass object to the given class name mapping its' properties.
300
     *
301
     * @param \stdClass     $sourceObject     Object to cast from.
302
     * @param string|object $destinationClass Name of the class or class instance to cast to.
303
     * @param array         $ctorArgs         Arguments to use for constructing the destination class instance.
304
     *
305
     * @return object
306
     *
307
     * @throws DB2Exception
308
     */
309
    private function castObject(\stdClass $sourceObject, $destinationClass, array $ctorArgs = [])
310
    {
311 View Code Duplication
        if ( ! is_string($destinationClass)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
312
            if ( ! is_object($destinationClass)) {
313
                throw new DB2Exception(sprintf(
314
                    'Destination class has to be of type string or object, %s given.', gettype($destinationClass)
315
                ));
316
            }
317
        } else {
318
            $destinationClass = new \ReflectionClass($destinationClass);
319
            $destinationClass = $destinationClass->newInstanceArgs($ctorArgs);
320
        }
321
322
        $sourceReflection           = new \ReflectionObject($sourceObject);
323
        $destinationClassReflection = new \ReflectionObject($destinationClass);
0 ignored issues
show
Bug introduced by
It seems like $destinationClass can also be of type string; however, parameter $argument of ReflectionObject::__construct() does only seem to accept object, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

323
        $destinationClassReflection = new \ReflectionObject(/** @scrutinizer ignore-type */ $destinationClass);
Loading history...
324
        /** @var \ReflectionProperty[] $destinationProperties */
325
        $destinationProperties      = array_change_key_case($destinationClassReflection->getProperties(), \CASE_LOWER);
326
327
        foreach ($sourceReflection->getProperties() as $sourceProperty) {
328
            $sourceProperty->setAccessible(true);
329
330
            $name  = $sourceProperty->getName();
331
            $value = $sourceProperty->getValue($sourceObject);
332
333
            // Try to find a case-matching property.
334
            if ($destinationClassReflection->hasProperty($name)) {
335
                $destinationProperty = $destinationClassReflection->getProperty($name);
336
337
                $destinationProperty->setAccessible(true);
338
                $destinationProperty->setValue($destinationClass, $value);
339
340
                continue;
341
            }
342
343
            $name = strtolower($name);
344
345
            // Try to find a property without matching case.
346
            // Fallback for the driver returning either all uppercase or all lowercase column names.
347
            if (isset($destinationProperties[$name])) {
348
                $destinationProperty = $destinationProperties[$name];
349
350
                $destinationProperty->setAccessible(true);
351
                $destinationProperty->setValue($destinationClass, $value);
352
353
                continue;
354
            }
355
356
            $destinationClass->$name = $value;
357
        }
358
359
        return $destinationClass;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $destinationClass also could return the type string which is incompatible with the documented return type object.
Loading history...
360
    }
361
}
362