Failed Conditions
Push — exceptions ( 7b5f2f...d1ce0d )
by Michael
24:32
created

SQLAnywhereStatement   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 325
Duplicated Lines 0 %

Test Coverage

Coverage 1.87%

Importance

Changes 0
Metric Value
wmc 51
dl 0
loc 325
ccs 2
cts 107
cp 0.0187
rs 8.3206
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
B execute() 0 19 6
A errorCode() 0 3 1
A fetchColumn() 0 9 2
A rowCount() 0 3 1
C fetch() 0 43 11
A setFetchMode() 0 5 3
A __construct() 0 11 3
A columnCount() 0 3 1
A errorInfo() 0 3 1
A getIterator() 0 3 1
A bindValue() 0 3 1
B fetchAll() 0 24 6
A closeCursor() 0 7 2
C bindParam() 0 26 7
B castObject() 0 33 5

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace Doctrine\DBAL\Driver\SQLAnywhere;
4
5
use Doctrine\DBAL\Driver\Statement;
6
use Doctrine\DBAL\Driver\StatementIterator;
7
use Doctrine\DBAL\FetchMode;
8
use Doctrine\DBAL\ParameterType;
9
use IteratorAggregate;
10
use const SASQL_BOTH;
0 ignored issues
show
Bug introduced by
The constant SASQL_BOTH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
11
use function array_key_exists;
12
use function gettype;
13
use function is_array;
14
use function is_numeric;
15
use function is_object;
16
use function is_resource;
17
use function is_string;
18
use function sasql_fetch_array;
0 ignored issues
show
introduced by
The function sasql_fetch_array was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
19
use function sasql_fetch_assoc;
0 ignored issues
show
introduced by
The function sasql_fetch_assoc was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
20
use function sasql_fetch_object;
0 ignored issues
show
introduced by
The function sasql_fetch_object was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
21
use function sasql_fetch_row;
0 ignored issues
show
introduced by
The function sasql_fetch_row was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
22
use function sasql_prepare;
0 ignored issues
show
introduced by
The function sasql_prepare was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
23
use function sasql_stmt_affected_rows;
0 ignored issues
show
introduced by
The function sasql_stmt_affected_rows was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
24
use function sasql_stmt_bind_param_ex;
0 ignored issues
show
introduced by
The function sasql_stmt_bind_param_ex was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
25
use function sasql_stmt_errno;
0 ignored issues
show
introduced by
The function sasql_stmt_errno was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
26
use function sasql_stmt_error;
0 ignored issues
show
introduced by
The function sasql_stmt_error was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
27
use function sasql_stmt_execute;
0 ignored issues
show
introduced by
The function sasql_stmt_execute was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
28
use function sasql_stmt_field_count;
0 ignored issues
show
introduced by
The function sasql_stmt_field_count was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
29
use function sasql_stmt_reset;
0 ignored issues
show
introduced by
The function sasql_stmt_reset was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
30
use function sasql_stmt_result_metadata;
0 ignored issues
show
introduced by
The function sasql_stmt_result_metadata was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
31
use function sprintf;
32
33
/**
34
 * SAP SQL Anywhere implementation of the Statement interface.
35
 *
36
 * @author Steve Müller <[email protected]>
37
 * @link   www.doctrine-project.org
38
 * @since  2.5
39
 */
40
class SQLAnywhereStatement implements IteratorAggregate, Statement
41
{
42
    /**
43
     * @var resource The connection resource.
44
     */
45
    private $conn;
46
47
    /**
48
     * @var string Name of the default class to instantiate when fetching class instances.
49
     */
50
    private $defaultFetchClass = '\stdClass';
51
52
    /**
53
     * @var string Constructor arguments for the default class to instantiate when fetching class instances.
54
     */
55
    private $defaultFetchClassCtorArgs = [];
56
57
    /**
58
     * @var int Default fetch mode to use.
59
     */
60
    private $defaultFetchMode = FetchMode::MIXED;
61
62
    /**
63
     * @var resource The result set resource to fetch.
64
     */
65
    private $result;
66
67
    /**
68
     * @var resource The prepared SQL statement to execute.
69
     */
70
    private $stmt;
71
72
    /**
73
     * Constructor.
74
     *
75
     * Prepares given statement for given connection.
76
     *
77
     * @param resource $conn The connection resource to use.
78
     * @param string   $sql  The SQL statement to prepare.
79
     *
80
     * @throws SQLAnywhereException
81
     */
82
    public function __construct($conn, $sql)
83
    {
84
        if ( ! is_resource($conn)) {
85
            throw new SQLAnywhereException('Invalid SQL Anywhere connection resource: ' . $conn);
86
        }
87
88
        $this->conn = $conn;
89
        $this->stmt = sasql_prepare($conn, $sql);
0 ignored issues
show
Bug introduced by
The function sasql_prepare 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

89
        $this->stmt = /** @scrutinizer ignore-call */ sasql_prepare($conn, $sql);
Loading history...
90
91
        if ( ! is_resource($this->stmt)) {
92
            throw SQLAnywhereException::fromSQLAnywhereError($conn);
93
        }
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     *
99
     * @throws SQLAnywhereException
100
     */
101
    public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null)
102
    {
103
        switch ($type) {
104
            case ParameterType::INTEGER:
105
            case ParameterType::BOOLEAN:
106
                $type = 'i';
107
                break;
108
109
            case ParameterType::LARGE_OBJECT:
110
                $type = 'b';
111
                break;
112
113
            case ParameterType::NULL:
114
            case ParameterType::STRING:
115
                $type = 's';
116
                break;
117
118
            default:
119
                throw new SQLAnywhereException('Unknown type: ' . $type);
120
        }
121
122
        if ( ! sasql_stmt_bind_param_ex($this->stmt, $column - 1, $variable, $type, $variable === null)) {
0 ignored issues
show
Bug introduced by
The function sasql_stmt_bind_param_ex 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

122
        if ( ! /** @scrutinizer ignore-call */ sasql_stmt_bind_param_ex($this->stmt, $column - 1, $variable, $type, $variable === null)) {
Loading history...
123
            throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
124
        }
125
126
        return true;
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132
    public function bindValue($param, $value, $type = ParameterType::STRING)
133
    {
134
        return $this->bindParam($param, $value, $type);
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     *
140
     * @throws SQLAnywhereException
141
     */
142
    public function closeCursor()
143
    {
144
        if (!sasql_stmt_reset($this->stmt)) {
0 ignored issues
show
Bug introduced by
The function sasql_stmt_reset 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

144
        if (!/** @scrutinizer ignore-call */ sasql_stmt_reset($this->stmt)) {
Loading history...
145
            throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
146
        }
147
148
        return true;
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154
    public function columnCount()
155
    {
156
        return sasql_stmt_field_count($this->stmt);
0 ignored issues
show
Bug introduced by
The function sasql_stmt_field_count 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

156
        return /** @scrutinizer ignore-call */ sasql_stmt_field_count($this->stmt);
Loading history...
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function errorCode()
163
    {
164
        return sasql_stmt_errno($this->stmt);
0 ignored issues
show
Bug introduced by
The function sasql_stmt_errno 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

164
        return /** @scrutinizer ignore-call */ sasql_stmt_errno($this->stmt);
Loading history...
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170
    public function errorInfo()
171
    {
172
        return sasql_stmt_error($this->stmt);
0 ignored issues
show
Bug introduced by
The function sasql_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

172
        return /** @scrutinizer ignore-call */ sasql_stmt_error($this->stmt);
Loading history...
173
    }
174
175
    /**
176
     * {@inheritdoc}
177
     *
178
     * @throws SQLAnywhereException
179
     */
180
    public function execute($params = null)
181
    {
182
        if (is_array($params)) {
183
            $hasZeroIndex = array_key_exists(0, $params);
184
185
            foreach ($params as $key => $val) {
186
                $key = ($hasZeroIndex && is_numeric($key)) ? $key + 1 : $key;
187
188
                $this->bindValue($key, $val);
189
            }
190
        }
191
192
        if ( ! sasql_stmt_execute($this->stmt)) {
0 ignored issues
show
Bug introduced by
The function sasql_stmt_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

192
        if ( ! /** @scrutinizer ignore-call */ sasql_stmt_execute($this->stmt)) {
Loading history...
193
            throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
194
        }
195
196
        $this->result = sasql_stmt_result_metadata($this->stmt);
0 ignored issues
show
Bug introduced by
The function sasql_stmt_result_metadata 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

196
        $this->result = /** @scrutinizer ignore-call */ sasql_stmt_result_metadata($this->stmt);
Loading history...
197
198
        return true;
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     *
204
     * @throws SQLAnywhereException
205
     */
206
    public function fetch($fetchMode = null, ...$args)
207
    {
208
        if ( ! is_resource($this->result)) {
209
            return false;
210
        }
211
212
        $fetchMode = $fetchMode ?: $this->defaultFetchMode;
213
214
        switch ($fetchMode) {
215
            case FetchMode::COLUMN:
216
                return $this->fetchColumn();
217
218
            case FetchMode::ASSOCIATIVE:
219
                return sasql_fetch_assoc($this->result);
0 ignored issues
show
Bug introduced by
The function sasql_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

219
                return /** @scrutinizer ignore-call */ sasql_fetch_assoc($this->result);
Loading history...
220
221
            case FetchMode::MIXED:
222
                return sasql_fetch_array($this->result, SASQL_BOTH);
0 ignored issues
show
Bug introduced by
The constant SASQL_BOTH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The function sasql_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

222
                return /** @scrutinizer ignore-call */ sasql_fetch_array($this->result, SASQL_BOTH);
Loading history...
223
224
            case FetchMode::CUSTOM_OBJECT:
225
                $className = $this->defaultFetchClass;
226
                $ctorArgs  = $this->defaultFetchClassCtorArgs;
227
228
                if (count($args) > 0) {
229
                    $className = $args[0];
230
                    $ctorArgs  = $args[1] ?? [];
231
                }
232
233
                $result = sasql_fetch_object($this->result);
0 ignored issues
show
Bug introduced by
The function sasql_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 */ sasql_fetch_object($this->result);
Loading history...
234
235
                if ($result instanceof \stdClass) {
236
                    $result = $this->castObject($result, $className, $ctorArgs);
237
                }
238
239
                return $result;
240
241
            case FetchMode::NUMERIC:
242
                return sasql_fetch_row($this->result);
0 ignored issues
show
Bug introduced by
The function sasql_fetch_row 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

242
                return /** @scrutinizer ignore-call */ sasql_fetch_row($this->result);
Loading history...
243
244
            case FetchMode::STANDARD_OBJECT:
245
                return sasql_fetch_object($this->result);
246
247
            default:
248
                throw new SQLAnywhereException('Fetch mode is not supported: ' . $fetchMode);
249
        }
250
    }
251
252
    /**
253
     * {@inheritdoc}
254
     */
255
    public function fetchAll($fetchMode = null, ...$args)
256
    {
257
        $rows = [];
258
259
        switch ($fetchMode) {
260
            case FetchMode::CUSTOM_OBJECT:
261
                while (($row = $this->fetch($fetchMode, ...$args)) !== false) {
262
                    $rows[] = $row;
263
                }
264
                break;
265
266
            case FetchMode::COLUMN:
267
                while (($row = $this->fetchColumn()) !== false) {
268
                    $rows[] = $row;
269
                }
270
                break;
271
272
            default:
273
                while (($row = $this->fetch($fetchMode)) !== false) {
274
                    $rows[] = $row;
275
                }
276
        }
277
278
        return $rows;
279
    }
280
281
    /**
282
     * {@inheritdoc}
283
     */
284
    public function fetchColumn($columnIndex = 0)
285
    {
286
        $row = $this->fetch(FetchMode::NUMERIC);
287
288
        if (false === $row) {
289
            return false;
290
        }
291
292
        return $row[$columnIndex] ?? null;
293
    }
294
295
    /**
296
     * {@inheritdoc}
297
     */
298 32
    public function getIterator()
299
    {
300 32
        return new StatementIterator($this);
301
    }
302
303
    /**
304
     * {@inheritdoc}
305
     */
306
    public function rowCount() : int
307
    {
308
        return sasql_stmt_affected_rows($this->stmt);
0 ignored issues
show
Bug introduced by
The function sasql_stmt_affected_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

308
        return /** @scrutinizer ignore-call */ sasql_stmt_affected_rows($this->stmt);
Loading history...
309
    }
310
311
    /**
312
     * {@inheritdoc}
313
     */
314
    public function setFetchMode($fetchMode, ...$args)
315
    {
316
        $this->defaultFetchMode          = $fetchMode;
317
        $this->defaultFetchClass         = $arg2 ? $arg2 : $this->defaultFetchClass;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $arg2 seems to be never defined.
Loading history...
318
        $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $arg3 seems to be never defined.
Loading history...
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...
319
    }
320
321
    /**
322
     * Casts a stdClass object to the given class name mapping its' properties.
323
     *
324
     * @param \stdClass     $sourceObject     Object to cast from.
325
     * @param string|object $destinationClass Name of the class or class instance to cast to.
326
     * @param array         $ctorArgs         Arguments to use for constructing the destination class instance.
327
     *
328
     * @return object
329
     *
330
     * @throws SQLAnywhereException
331
     */
332
    private function castObject(\stdClass $sourceObject, $destinationClass, array $ctorArgs = [])
333
    {
334
        if ( ! is_string($destinationClass)) {
335
            if ( ! is_object($destinationClass)) {
336
                throw new SQLAnywhereException(sprintf(
337
                    'Destination class has to be of type string or object, %s given.', gettype($destinationClass)
338
                ));
339
            }
340
        } else {
341
            $destinationClass = new \ReflectionClass($destinationClass);
342
            $destinationClass = $destinationClass->newInstanceArgs($ctorArgs);
343
        }
344
345
        $sourceReflection           = new \ReflectionObject($sourceObject);
346
        $destinationClassReflection = new \ReflectionObject($destinationClass);
347
348
        foreach ($sourceReflection->getProperties() as $sourceProperty) {
349
            $sourceProperty->setAccessible(true);
350
351
            $name  = $sourceProperty->getName();
352
            $value = $sourceProperty->getValue($sourceObject);
353
354
            if ($destinationClassReflection->hasProperty($name)) {
355
                $destinationProperty = $destinationClassReflection->getProperty($name);
356
357
                $destinationProperty->setAccessible(true);
358
                $destinationProperty->setValue($destinationClass, $value);
359
            } else {
360
                $destinationClass->$name = $value;
361
            }
362
        }
363
364
        return $destinationClass;
365
    }
366
}
367