Result::withoutStorage()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace BenTools\SimpleDBAL\Model\Adapter\Mysqli;
4
5
use BenTools\SimpleDBAL\Contract\ResultInterface;
6
use BenTools\SimpleDBAL\Model\Exception\DBALException;
7
use IteratorAggregate;
8
use mysqli;
9
use mysqli_result;
10
use mysqli_stmt;
11
12
class Result implements IteratorAggregate, ResultInterface
13
{
14
    /**
15
     * @var mysqli
16
     */
17
    private $mysqli;
18
19
    /**
20
     * @var mysqli_stmt
21
     */
22
    private $stmt;
23
24
    /**
25
     * @var mysqli_result
26
     */
27
    private $result;
28
29
    private $storage = [];
30
31
    /**
32
     * @var bool
33
     */
34
    private $storageEnabled = true;
35
36
    /**
37
     * Result constructor.
38
     * @param mysqli        $mysqli
39
     * @param mysqli_stmt   $stmt
40
     * @param mysqli_result $result
41
     */
42
    public function __construct(mysqli $mysqli, mysqli_result $result = null, mysqli_stmt $stmt = null)
43
    {
44
        $this->mysqli = $mysqli;
45
        $this->stmt = $stmt;
46
        $this->result = $result;
47
    }
48
49
    /**
50
     * @inheritDoc
51
     */
52
    public function getLastInsertId()
53
    {
54
        return $this->mysqli->insert_id;
55
    }
56
57
    /**
58
     * @inheritDoc
59
     */
60
    public function count()
61
    {
62
        return null === $this->result ? $this->mysqli->affected_rows : $this->result->num_rows;
63
    }
64
65
    /**
66
     * @inheritDoc
67
     */
68
    public function asArray(): array
69
    {
70
        if (null === $this->result) {
71
            throw new DBALException("No mysqli_result object provided.");
72
        }
73
        if (empty($this->storage['array'])) {
74
            if ($this->shouldResetResultset()) {
75
                $this->resetResultset();
76
            }
77
78
            $result = $this->result->fetch_all(MYSQLI_ASSOC);
79
80
            if (true === $this->storageEnabled) {
81
                $this->storage['array'] = $result;
82
            }
83
84
            return $result;
85
        }
86
        return $this->storage['array'];
87
    }
88
89
    /**
90
     * @inheritDoc
91
     */
92
    public function asRow(): ?array
93
    {
94
        if (null === $this->result) {
95
            throw new DBALException("No mysqli_result object provided.");
96
        }
97
        if (empty($this->storage['row'])) {
98
            if (isset($this->storage['array'][0])) {
99
                $this->storage['row'] = &$this->storage['array'][0];
100
            } else {
101
                if ($this->shouldResetResultset()) {
102
                    $this->resetResultset();
103
                }
104
105
                $result = $this->result->fetch_array(MYSQLI_ASSOC) ?: null;
106
107
                if (true === $this->storageEnabled) {
108
                    $this->storage['row'] = $result;
109
                }
110
111
                return $result;
112
            }
113
        }
114
        return $this->storage['row'];
115
    }
116
117
    /**
118
     * @inheritDoc
119
     */
120
    public function asList(): array
121
    {
122
        if (null === $this->result) {
123
            throw new DBALException("No mysqli_result object provided.");
124
        }
125
        if (empty($this->storage['list'])) {
126
            if (!empty($this->storage['array'])) {
127
                $this->storage['list'] = array_column($this->storage['array'], array_keys($this->storage['array'][0])[0]);
128
            } else {
129
                if ($this->shouldResetResultset()) {
130
                    $this->resetResultset();
131
                }
132
133
                $generator = function (\mysqli_result $result) {
134
                    while ($row = $result->fetch_array(MYSQLI_NUM)) {
135
                        yield $row[0];
136
                    }
137
                };
138
                $result = iterator_to_array($generator($this->result));
139
140
                if (true === $this->storageEnabled) {
141
                    $this->storage['list'] = $result;
142
                }
143
144
                return $result;
145
            }
146
        }
147
        return $this->storage['list'];
148
    }
149
150
    /**
151
     * @inheritDoc
152
     */
153
    public function asValue()
154
    {
155
        if (null === $this->result) {
156
            throw new DBALException("No mysqli_result object provided.");
157
        }
158
        if (empty($this->storage['value'])) {
159
            if (!empty($this->storage['list'][0])) {
160
                $this->storage['value'] = $this->storage['list'][0];
161
            } elseif (!empty($this->storage['row'])) {
162
                $this->storage['value'] = array_values($this->storage['row'])[0];
163
            } elseif (!empty($this->storage['array'])) {
164
                $this->storage['value'] = array_values($this->storage['array'][0])[0];
165
            } else {
166
                if ($this->shouldResetResultset()) {
167
                    $this->resetResultset();
168
                }
169
170
                $row = $this->result->fetch_array(MYSQLI_NUM);
171
                $result = $row ? $row[0] : null;
172
173
                if (true === $this->storageEnabled) {
174
                    $this->storage['value'] = $result;
175
                }
176
177
                return $result;
178
            }
179
        }
180
        return $this->storage['value'];
181
    }
182
183
    /**
184
     * @inheritDoc
185
     */
186
    public function getIterator()
187
    {
188
        if (null === $this->result) {
189
            throw new DBALException("No mysqli_result object provided.");
190
        }
191
        if (!empty($this->storage['array'])) {
192
            foreach ($this->storage['array'] as $key => $value) {
193
                yield $key => $value;
194
            }
195
        } else {
196
            if ($this->shouldResetResultset()) {
197
                $this->resetResultset();
198
            }
199
200
            while ($row = $this->result->fetch_array(MYSQLI_ASSOC)) {
201
                if (empty($this->storage['yield'])) {
202
                    $this->storage['yield'] = true;
203
                }
204
                yield $row;
205
            }
206
        }
207
    }
208
209
210
    /**
211
     * If asRow(), asList() or asValue() was called earlier, the iterator may be incomplete.
212
     * In such case we need to rewind the iterator by executing the statement a second time.
213
     * You should avoid to call getIterator() and asRow(), etc. with the same resultset.
214
     *
215
     * @return bool
216
     */
217
    private function shouldResetResultset(): bool
218
    {
219
        return !empty($this->storage['row']) || !empty($this->storage['value']) || !empty($this->storage['list']) || !empty($this->storage['yield']);
220
    }
221
222
223
    /**
224
     * Reset the resultset.
225
     */
226
    private function resetResultset()
227
    {
228
        if (null !== $this->stmt) {
229
            $this->stmt->execute();
230
            $this->result = $this->stmt->get_result();
231
        }
232
    }
233
234
    /**
235
     * @return ResultInterface
236
     */
237
    public function withoutStorage(): ResultInterface
238
    {
239
        $clone = clone $this;
240
        $clone->storage = [];
241
        $clone->storageEnabled = false;
242
        return $clone;
243
    }
244
}
245