Failed Conditions
Pull Request — master (#3359)
by Sergei
25:01 queued 22:04
created

SQLAnywhereStatement::castObject()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 34
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

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

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

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

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

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

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

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

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

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

210
                return /** @scrutinizer ignore-call */ sasql_fetch_assoc($this->result);
Loading history...
211
212
            case FetchMode::MIXED:
213
                return sasql_fetch_array($this->result, SASQL_BOTH);
0 ignored issues
show
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

213
                return /** @scrutinizer ignore-call */ sasql_fetch_array($this->result, SASQL_BOTH);
Loading history...
Bug introduced by
The constant SASQL_BOTH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
214
215
            case FetchMode::CUSTOM_OBJECT:
216
                $className = $this->defaultFetchClass;
217
                $ctorArgs  = $this->defaultFetchClassCtorArgs;
218
219
                if (func_num_args() >= 2) {
220
                    $args      = func_get_args();
221
                    $className = $args[1];
222
                    $ctorArgs  = $args[2] ?? [];
223
                }
224
225
                $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

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

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

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