Completed
Branch master (9dff9d)
by Albert
05:30
created

PDOStatement::fetchAll()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 3
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Copyright: Swlib
5
 * Author: Twosee <[email protected]>
6
 * Modifier: Albert Chen
7
 * License: Apache 2.0
8
 */
9
10
namespace SwooleTW\Http\Coroutine;
11
12
use PDOStatement as BaseStatement;
13
use SwooleTW\Http\Coroutine\PDO;
14
use Swoole\Coroutine\MySQL\Statement;
15
16
class PDOStatement extends BaseStatement
17
{
18
    private $parent;
19
    public $statement;
20
    public $timeout;
21
    public $bindMap = [];
22
    public $cursor = -1;
23
    public $cursorOrientation = PDO::FETCH_ORI_NEXT;
24
    public $resultSet = [];
25
    public $fetchStyle = PDO::FETCH_BOTH;
26
27
    public function __construct(PDO $parent, Statement $statement, array $driverOptions = [])
28
    {
29
        $this->parent = $parent;
30
        $this->statement = $statement;
31
        $this->timeout = $driverOptions['timeout'] ?? -1;
32
    }
33
34
    public function errorCode()
35
    {
36
        return $this->statement->errno;
37
    }
38
39
    public function errorInfo()
40
    {
41
        return $this->statement->error;
42
    }
43
44
    public function rowCount()
45
    {
46
        return $this->statement->affected_rows;
47
    }
48
49
    public function bindParam($parameter, &$variable, $type = null, $maxlen = null, $driverdata = null)
50
    {
51
        if (! is_string($parameter) && ! is_int($parameter)) {
52
            return false;
53
        }
54
55
        $parameter = ltrim($parameter, ':');
56
        $this->bindMap[$parameter] = &$variable;
57
58
        return true;
59
    }
60
61
    public function bindValue($parameter, $variable, $type = null)
62
    {
63
        if (! is_string($parameter) && ! is_int($parameter)) {
64
            return false;
65
        }
66
67
        if (is_object($variable)) {
68
            if (! method_exists($variable, '__toString')) {
69
                return false;
70
            } else {
71
                $variable = (string) $variable;
72
            }
73
        }
74
75
        $parameter = ltrim($parameter, ':');
76
        $this->bindMap[$parameter] = $variable;
77
78
        return true;
79
    }
80
81
    private function afterExecute()
82
    {
83
        $this->cursor = -1;
84
        $this->bindMap = [];
85
    }
86
87
    public function execute($inputParameters = null)
88
    {
89
        if (! empty($inputParameters)) {
90
            foreach ($inputParameters as $key => $value) {
91
                $this->bindParam($key, $value);
92
            }
93
        }
94
95
        $inputParameters = [];
96
        if (! empty($this->statement->bindKeyMap)) {
97
            foreach ($this->statement->bindKeyMap as $nameKey => $numKey) {
0 ignored issues
show
Bug introduced by
The property bindKeyMap does not seem to exist on Swoole\Coroutine\Mysql\Statement.
Loading history...
98
                $inputParameters[$numKey] = $this->bindMap[$nameKey];
99
            }
100
        } else {
101
            $inputParameters = $this->bindMap;
102
        }
103
104
        $result = $this->statement->execute($inputParameters, $this->timeout);
105
        $this->resultSet = ($ok = $result !== false) ? $result : [];
106
        $this->afterExecute();
107
108
        return $ok;
109
    }
110
111
    public function setFetchMode($fetchStyle, $params = null)
112
    {
113
        $this->fetchStyle = $fetchStyle;
0 ignored issues
show
Bug Best Practice introduced by
The expression ImplicitReturnNode returns the type null which is incompatible with the return type mandated by PDOStatement::setFetchMode() of boolean.

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...
114
    }
115
116
    private function __executeWhenStringQueryEmpty()
117
    {
118
        if (is_string($this->statement) && empty($this->resultSet)) {
0 ignored issues
show
introduced by
The condition is_string($this->statement) is always false.
Loading history...
119
            $this->resultSet = $this->parent->client->query($this->statement);
120
            $this->afterExecute();
121
        }
122
    }
123
124
    private function transBoth($rawData)
125
    {
126
        $temp = [];
127
        foreach ($rawData as $row) {
128
            $rowSet = [];
129
            $i = 0;
130
            foreach ($row as $key => $value) {
131
                $rowSet[$key] = $value;
132
                $rowSet[$i++] = $value;
133
            }
134
            $temp[] = $rowSet;
135
        }
136
137
        return $temp;
138
    }
139
140
    private function transStyle(
141
        $rawData,
142
        $fetchStyle = null,
143
        $fetchArgument = null,
144
        $ctorArgs = null
145
    ) {
146
        if (! is_array($rawData)) {
147
            return false;
148
        }
149
        if (empty($rawData)) {
150
            return $rawData;
151
        }
152
153
        $fetchStyle = is_null($fetchStyle) ? $this->fetchStyle : $fetchStyle;
154
        $ctorArgs = is_null($ctorArgs) ? [] : $ctorArgs;
0 ignored issues
show
Unused Code introduced by
The assignment to $ctorArgs is dead and can be removed.
Loading history...
155
156
        $resultSet = [];
157
        switch ($fetchStyle) {
158
            case PDO::FETCH_BOTH:
159
                $resultSet = $this->transBoth($rawData);
160
                break;
161
            case PDO::FETCH_COLUMN:
162
                $resultSet = array_column(
163
                    is_numeric($fetchArgument) ? $this->transBoth($rawData) : $rawData,
164
                    $fetchArgument
165
                );
166
                break;
167
            case PDO::FETCH_OBJ:
168
                foreach ($rawData as $row) {
169
                    $resultSet[] = (object) $row;
170
                }
171
                break;
172
            case PDO::FETCH_NUM:
173
                foreach ($rawData as $row) {
174
                    $resultSet[] = array_values($row);
175
                }
176
                break;
177
            case PDO::FETCH_ASSOC:
178
            default:
179
                return $rawData;
180
        }
181
182
        return $resultSet;
183
    }
184
185
    public function fetch(
186
        $fetchStyle = null,
187
        $cursorOrientation = null,
188
        $cursorOffset = null,
189
        $fetchArgument = null
190
    ) {
191
        $this->__executeWhenStringQueryEmpty();
192
193
        $cursorOrientation = is_null($cursorOrientation) ? PDO::FETCH_ORI_NEXT : $cursorOrientation;
194
        $cursorOffset = is_null($cursorOffset) ? 0 : (int) $cursorOffset;
195
196
        switch ($cursorOrientation) {
197
            case PDO::FETCH_ORI_ABS:
198
                $this->cursor = $cursorOffset;
199
                break;
200
            case PDO::FETCH_ORI_REL:
201
                $this->cursor += $cursorOffset;
202
                break;
203
            case PDO::FETCH_ORI_NEXT:
204
            default:
205
                $this->cursor++;
206
        }
207
208
        if (isset($this->resultSet[$this->cursor])) {
209
            $result = $this->resultSet[$this->cursor];
210
            unset($this->resultSet[$this->cursor]);
211
        } else {
212
            $result = false;
213
        }
214
215
        if (empty($result)) {
216
            return $result;
217
        } else {
218
            return $this->transStyle([$result], $fetchStyle, $fetchArgument)[0];
219
        }
220
    }
221
222
    /**
223
     * Returns a single column from the next row of a result set or FALSE if there are no more rows.
224
     *
225
     * @param int $column_number
226
     * 0-indexed number of the column you wish to retrieve from the row.
227
     * If no value is supplied, PDOStatement::fetchColumn() fetches the first column.
228
     *
229
     * @return bool|mixed
230
     */
231
    public function fetchColumn($columnNumber = null)
232
    {
233
        $columnNumber = is_null($columnNumber) ? 0 : $columnNumber;
234
        $this->__executeWhenStringQueryEmpty();
235
        return $this->fetch(PDO::FETCH_COLUMN, PDO::FETCH_ORI_NEXT, 0, $columnNumber);
236
    }
237
238
    public function fetchAll($fetchStyle = null, $fetchArgument = null, $ctorArgs = null)
239
    {
240
        $this->__executeWhenStringQueryEmpty();
241
        $resultSet = $this->transStyle($this->resultSet, $fetchStyle, $fetchArgument, $ctorArgs);
242
        $this->resultSet = [];
243
244
        return $resultSet;
245
    }
246
}
247