Failed Conditions
Push — master ( cfe3be...296b0e )
by Sergei
33:23 queued 11s
created

SQLAnywhereStatement   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 314
Duplicated Lines 0 %

Test Coverage

Coverage 1.83%

Importance

Changes 0
Metric Value
wmc 52
eloc 117
dl 0
loc 314
ccs 2
cts 109
cp 0.0183
rs 7.44
c 0
b 0
f 0

15 Methods

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

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 PDO;
11
use ReflectionClass;
12
use ReflectionObject;
13
use stdClass;
14
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...
15
use function array_key_exists;
16
use function func_get_args;
17
use function func_num_args;
18
use function gettype;
19
use function is_array;
20
use function is_numeric;
21
use function is_object;
22
use function is_resource;
23
use function is_string;
24
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...
25
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...
26
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...
27
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...
28
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...
29
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...
30
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...
31
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...
32
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...
33
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...
34
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...
35
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...
36
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...
37
use function sprintf;
38
39
/**
40
 * SAP SQL Anywhere implementation of the Statement interface.
41
 */
42
class SQLAnywhereStatement implements IteratorAggregate, Statement
43
{
44
    /** @var resource The connection resource. */
45
    private $conn;
46
47
    /** @var string Name of the default class to instantiate when fetching class instances. */
48
    private $defaultFetchClass = '\stdClass';
49
50
    /** @var mixed[] Constructor arguments for the default class to instantiate when fetching class instances. */
51
    private $defaultFetchClassCtorArgs = [];
52
53
    /** @var int Default fetch mode to use. */
54
    private $defaultFetchMode = FetchMode::MIXED;
55
56
    /** @var resource The result set resource to fetch. */
57
    private $result;
58
59
    /** @var resource The prepared SQL statement to execute. */
60
    private $stmt;
61
62
    /**
63
     * Prepares given statement for given connection.
64
     *
65
     * @param resource $conn The connection resource to use.
66
     * @param string   $sql  The SQL statement to prepare.
67
     *
68
     * @throws SQLAnywhereException
69
     */
70
    public function __construct($conn, $sql)
71
    {
72
        if (! is_resource($conn)) {
73
            throw new SQLAnywhereException('Invalid SQL Anywhere connection resource: ' . $conn);
74
        }
75
76
        $this->conn = $conn;
77
        $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

77
        $this->stmt = /** @scrutinizer ignore-call */ sasql_prepare($conn, $sql);
Loading history...
78
79
        if (! is_resource($this->stmt)) {
80
            throw SQLAnywhereException::fromSQLAnywhereError($conn);
81
        }
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     *
87
     * @throws SQLAnywhereException
88
     */
89
    public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null)
90
    {
91
        switch ($type) {
92
            case ParameterType::INTEGER:
93
            case ParameterType::BOOLEAN:
94
                $type = 'i';
95
                break;
96
97
            case ParameterType::LARGE_OBJECT:
98
                $type = 'b';
99
                break;
100
101
            case ParameterType::NULL:
102
            case ParameterType::STRING:
103
            case ParameterType::BINARY:
104
                $type = 's';
105
                break;
106
107
            default:
108
                throw new SQLAnywhereException('Unknown type: ' . $type);
109
        }
110
111
        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

111
        if (! /** @scrutinizer ignore-call */ sasql_stmt_bind_param_ex($this->stmt, $column - 1, $variable, $type, $variable === null)) {
Loading history...
112
            throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
113
        }
114
115
        return true;
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function bindValue($param, $value, $type = ParameterType::STRING)
122
    {
123
        return $this->bindParam($param, $value, $type);
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     *
129
     * @throws SQLAnywhereException
130
     */
131
    public function closeCursor()
132
    {
133
        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

133
        if (! /** @scrutinizer ignore-call */ sasql_stmt_reset($this->stmt)) {
Loading history...
134
            throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
135
        }
136
137
        return true;
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public function columnCount()
144
    {
145
        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

145
        return /** @scrutinizer ignore-call */ sasql_stmt_field_count($this->stmt);
Loading history...
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    public function errorCode()
152
    {
153
        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

153
        return /** @scrutinizer ignore-call */ sasql_stmt_errno($this->stmt);
Loading history...
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159
    public function errorInfo()
160
    {
161
        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

161
        return /** @scrutinizer ignore-call */ sasql_stmt_error($this->stmt);
Loading history...
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     *
167
     * @throws SQLAnywhereException
168
     */
169
    public function execute($params = null)
170
    {
171
        if (is_array($params)) {
172
            $hasZeroIndex = array_key_exists(0, $params);
173
174
            foreach ($params as $key => $val) {
175
                $key = $hasZeroIndex && is_numeric($key) ? $key + 1 : $key;
176
177
                $this->bindValue($key, $val);
178
            }
179
        }
180
181
        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

181
        if (! /** @scrutinizer ignore-call */ sasql_stmt_execute($this->stmt)) {
Loading history...
182
            throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt);
183
        }
184
185
        $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

185
        $this->result = /** @scrutinizer ignore-call */ sasql_stmt_result_metadata($this->stmt);
Loading history...
186
187
        return true;
188
    }
189
190
    /**
191
     * {@inheritdoc}
192
     *
193
     * @throws SQLAnywhereException
194
     */
195
    public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
196
    {
197
        if (! is_resource($this->result)) {
198
            return false;
199
        }
200
201
        $fetchMode = $fetchMode ?: $this->defaultFetchMode;
202
203
        switch ($fetchMode) {
204
            case FetchMode::COLUMN:
205
                return $this->fetchColumn();
206
207
            case FetchMode::ASSOCIATIVE:
208
                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

208
                return /** @scrutinizer ignore-call */ sasql_fetch_assoc($this->result);
Loading history...
209
210
            case FetchMode::MIXED:
211
                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

211
                return /** @scrutinizer ignore-call */ sasql_fetch_array($this->result, SASQL_BOTH);
Loading history...
212
213
            case FetchMode::CUSTOM_OBJECT:
214
                $className = $this->defaultFetchClass;
215
                $ctorArgs  = $this->defaultFetchClassCtorArgs;
216
217
                if (func_num_args() >= 2) {
218
                    $args      = func_get_args();
219
                    $className = $args[1];
220
                    $ctorArgs  = $args[2] ?? [];
221
                }
222
223
                $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

223
                $result = /** @scrutinizer ignore-call */ sasql_fetch_object($this->result);
Loading history...
224
225
                if ($result instanceof stdClass) {
226
                    $result = $this->castObject($result, $className, $ctorArgs);
227
                }
228
229
                return $result;
230
231
            case FetchMode::NUMERIC:
232
                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

232
                return /** @scrutinizer ignore-call */ sasql_fetch_row($this->result);
Loading history...
233
234
            case FetchMode::STANDARD_OBJECT:
235
                return sasql_fetch_object($this->result);
236
237
            default:
238
                throw new SQLAnywhereException('Fetch mode is not supported: ' . $fetchMode);
239
        }
240
    }
241
242
    /**
243
     * {@inheritdoc}
244
     */
245
    public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
246
    {
247
        $rows = [];
248
249
        switch ($fetchMode) {
250
            case FetchMode::CUSTOM_OBJECT:
251
                while ($row = $this->fetch(...func_get_args())) {
252
                    $rows[] = $row;
253
                }
254
                break;
255
256
            case FetchMode::COLUMN:
257
                while ($row = $this->fetchColumn()) {
258
                    $rows[] = $row;
259
                }
260
                break;
261
262
            default:
263
                while ($row = $this->fetch($fetchMode)) {
264
                    $rows[] = $row;
265
                }
266
        }
267
268
        return $rows;
269
    }
270
271
    /**
272
     * {@inheritdoc}
273
     */
274
    public function fetchColumn($columnIndex = 0)
275
    {
276
        $row = $this->fetch(FetchMode::NUMERIC);
277
278
        if ($row === false) {
279
            return false;
280
        }
281
282
        return $row[$columnIndex] ?? null;
283
    }
284
285
    /**
286
     * {@inheritdoc}
287
     */
288 48
    public function getIterator()
289
    {
290 48
        return new StatementIterator($this);
291
    }
292
293
    /**
294
     * {@inheritdoc}
295
     */
296
    public function rowCount()
297
    {
298
        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

298
        return /** @scrutinizer ignore-call */ sasql_stmt_affected_rows($this->stmt);
Loading history...
299
    }
300
301
    /**
302
     * {@inheritdoc}
303
     */
304
    public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
305
    {
306
        $this->defaultFetchMode          = $fetchMode;
307
        $this->defaultFetchClass         = $arg2 ?: $this->defaultFetchClass;
308
        $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs;
309
    }
310
311
    /**
312
     * Casts a stdClass object to the given class name mapping its' properties.
313
     *
314
     * @param stdClass      $sourceObject     Object to cast from.
315
     * @param string|object $destinationClass Name of the class or class instance to cast to.
316
     * @param mixed[]       $ctorArgs         Arguments to use for constructing the destination class instance.
317
     *
318
     * @return object
319
     *
320
     * @throws SQLAnywhereException
321
     */
322
    private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = [])
323
    {
324
        if (! is_string($destinationClass)) {
325
            if (! is_object($destinationClass)) {
326
                throw new SQLAnywhereException(sprintf(
327
                    'Destination class has to be of type string or object, %s given.',
328
                    gettype($destinationClass)
329
                ));
330
            }
331
        } else {
332
            $destinationClass = new ReflectionClass($destinationClass);
333
            $destinationClass = $destinationClass->newInstanceArgs($ctorArgs);
334
        }
335
336
        $sourceReflection           = new ReflectionObject($sourceObject);
337
        $destinationClassReflection = new ReflectionObject($destinationClass);
338
339
        foreach ($sourceReflection->getProperties() as $sourceProperty) {
340
            $sourceProperty->setAccessible(true);
341
342
            $name  = $sourceProperty->getName();
343
            $value = $sourceProperty->getValue($sourceObject);
344
345
            if ($destinationClassReflection->hasProperty($name)) {
346
                $destinationProperty = $destinationClassReflection->getProperty($name);
347
348
                $destinationProperty->setAccessible(true);
349
                $destinationProperty->setValue($destinationClass, $value);
350
            } else {
351
                $destinationClass->$name = $value;
352
            }
353
        }
354
355
        return $destinationClass;
356
    }
357
}
358