Completed
Pull Request — master (#7)
by Sandro
04:25
created

Statement::hasMore()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 6
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 6
1
<?php
2
/**
3
 * Sandro Keil (https://sandro-keil.de)
4
 *
5
 * @link      http://github.com/sandrokeil/arangodb-php-client for the canonical source repository
6
 * @copyright Copyright (c) 2018-2019 Sandro Keil
7
 * @license   http://github.com/sandrokeil/arangodb-php-client/blob/master/LICENSE.md New BSD License
8
 */
9
10
namespace ArangoDb;
11
12
use ArangoDb\Exception\ServerException;
13
use ArangoDb\Statement\QueryResult;
14
use ArangoDb\Statement\StreamHandler;
15
use ArangoDb\Statement\StreamHandlerFactoryInterface;
16
use Countable;
17
use Fig\Http\Message\RequestMethodInterface;
18
use Fig\Http\Message\StatusCodeInterface;
19
use Iterator;
20
use Psr\Http\Client\ClientExceptionInterface;
21
use Psr\Http\Client\ClientInterface;
22
use Psr\Http\Message\RequestFactoryInterface;
23
use Psr\Http\Message\RequestInterface;
24
25
final class Statement implements QueryResult, Iterator, Countable
26
{
27
    /**
28
     * @var ClientInterface
29
     */
30
    private $client;
31
32
    /**
33
     * @var RequestFactoryInterface
34
     */
35
    private $requestFactory;
36
37
    /**
38
     * @var RequestInterface
39
     */
40
    private $request;
41
42
    /**
43
     * @var StreamHandler
44
     */
45
    private $streamHandler;
46
47
    /**
48
     * @var StreamHandlerFactoryInterface
49
     */
50
    private $streamHandlerFactory;
51
52
    /**
53
     * Number of HTTP calls that were made to build the cursor result
54
     *
55
     * @var int
56
     */
57
    private $fetches = 0;
58
59
    /**
60
     * Query is executed on first access
61
     *
62
     * @param ClientInterface $client - connection to be used
63
     * @param RequestInterface $request Cursor request
64
     * @param RequestFactoryInterface $requestFactory
65
     * @param StreamHandlerFactoryInterface $streamHandlerFactory
66
     */
67 9
    public function __construct(
68
        ClientInterface $client,
69
        RequestInterface $request,
70
        RequestFactoryInterface $requestFactory,
71
        StreamHandlerFactoryInterface $streamHandlerFactory
72
    ) {
73 9
        $this->client = $client;
74 9
        $this->request = $request;
75 9
        $this->requestFactory = $requestFactory;
76 9
        $this->streamHandlerFactory = $streamHandlerFactory;
77 9
    }
78
79
    /**
80
     * Fetch outstanding results from the server
81
     *
82
     * @return void
83
     * @throws ClientExceptionInterface
84
     */
85 9
    private function fetchOutstanding(): void
86
    {
87 9
        $request = $this->fetches === 0
88 9
            ? $this->request
89 4
            : $this->requestFactory->createRequest(
90 4
                RequestMethodInterface::METHOD_PUT,
91 9
                Url::CURSOR . '/' . $this->streamHandler->cursorId()
92
            );
93
94 9
        $request->getBody()->rewind();
95 9
        $response = $this->client->sendRequest($request);
96
97 9
        $httpStatusCode = $response->getStatusCode();
98
99 9
        if ($httpStatusCode < StatusCodeInterface::STATUS_OK
100 9
            || $httpStatusCode > StatusCodeInterface::STATUS_MULTIPLE_CHOICES
101
        ) {
102
            throw ServerException::with($request, $response);
103
        }
104
105 9
        if ($this->fetches === 0) {
106 9
            $this->streamHandler = $this->streamHandlerFactory->createStreamHandler($response->getBody());
107
        } else {
108 4
            $this->streamHandler->appendStream($response->getBody());
109
        }
110 7
        $this->fetches++;
111 7
    }
112
113
    /**
114
     * Fetches next result from server and returns all current loaded results. Null if cursor end has reached.
115
     *
116
     * @return string|array|object|null Data
117
     * @throws ClientExceptionInterface
118
     */
119 1
    public function fetch()
120
    {
121 1
        if (null === $this->streamHandler || $this->streamHandler->hasMore()) {
122 1
            $this->fetchOutstanding();
123 1
            return $this->streamHandler->result();
124
        }
125 1
        return null;
126
    }
127
128
    /**
129
     * Fetches all results from server and returns overall result.
130
     * This might issue additional HTTP requests to fetch any outstanding results from the server.
131
     *
132
     * @return string|array|object Data
133
     * @throws ClientExceptionInterface
134
     */
135 4
    public function fetchAll()
136
    {
137 4
        while (null === $this->streamHandler || $this->streamHandler->hasMore()) {
138 3
            $this->fetchOutstanding();
139
        }
140
141 4
        return $this->streamHandler->completeResult();
142
    }
143
144 1
    public function resultCount(): ?int
145
    {
146 1
        if (null === $this->streamHandler) {
147
            $this->fetchOutstanding();
148
        }
149 1
        return $this->streamHandler->resultCount();
150
    }
151
152 1
    public function result()
153
    {
154 1
        if (null === $this->streamHandler) {
155
            $this->fetchOutstanding();
156
        }
157 1
        return $this->streamHandler->result();
158
    }
159
160
    /**
161
     * Get the total number of results in the cursor.
162
     *
163
     * This might issue additional HTTP requests to fetch any outstanding results from the server.
164
     *
165
     * @return int Total number of results
166
     * @throws ClientExceptionInterface
167
     */
168 1
    public function count()
169
    {
170 1
        if (null === $this->streamHandler) {
171
            $this->fetchOutstanding();
172
        }
173
174 1
        while ($this->streamHandler->hasMore()) {
175 1
            $this->fetchOutstanding();
176
        }
177
178 1
        return $this->streamHandler->count();
179
    }
180
181
    /**
182
     * Rewind the cursor, loads first batch, can be repeated (new cursor will be created)
183
     *
184
     * @return void
185
     * @throws ClientExceptionInterface
186
     */
187 5
    public function rewind()
188
    {
189 5
        $this->fetches = 0;
190 5
        $this->fetchOutstanding();
191 3
    }
192
193
    /**
194
     * Return the current result row depending on stream handler
195
     *
196
     * @return string|array|object Data
197
     */
198 3
    public function current()
199
    {
200 3
        if (null === $this->streamHandler) {
201
            $this->fetchOutstanding();
202
        }
203 3
        return $this->streamHandler->current();
204
    }
205
206 3
    public function key(): int
207
    {
208 3
        if (null === $this->streamHandler) {
209
            $this->fetchOutstanding();
210
        }
211 3
        return $this->streamHandler->key();
212
    }
213
214 3
    public function next(): void
215
    {
216 3
        $this->streamHandler->next();
217 3
    }
218
219
    /**
220
     * @return bool
221
     * @throws ClientExceptionInterface
222
     */
223 3
    public function valid(): bool
224
    {
225 3
        if (null === $this->streamHandler) {
226
            $this->fetchOutstanding();
227
        }
228
229 3
        if (true === $this->streamHandler->valid()) {
230 3
            return true;
231
        }
232
233 3
        if (! $this->streamHandler->hasMore() || $this->streamHandler->cursorId() === null) {
234 3
            return false;
235
        }
236
237
        // need to fetch additional results from the server
238 2
        $this->fetchOutstanding();
239
240 2
        return $this->streamHandler->valid();
241
    }
242
243
    /**
244
     * Returns the number of HTTP calls that were made to build the cursor result
245
     *
246
     * @return int
247
     */
248 9
    public function fetches(): int
249
    {
250 9
        return $this->fetches;
251
    }
252
253
    public function cursorId(): ?string
254
    {
255
        if (null === $this->streamHandler) {
256
            $this->fetchOutstanding();
257
        }
258
        return $this->streamHandler->cursorId();
259
    }
260
261
    public function hasMore(): bool
262
    {
263
        if (null === $this->streamHandler) {
264
            $this->fetchOutstanding();
265
        }
266
        return $this->streamHandler->hasMore();
267
    }
268
269
    public function warnings(): array
270
    {
271
        if (null === $this->streamHandler) {
272
            $this->fetchOutstanding();
273
        }
274
        return $this->streamHandler->warnings();
275
    }
276
277 1
    public function fullCount(): ?int
278
    {
279 1
        if (null === $this->streamHandler) {
280 1
            $this->fetchOutstanding();
281
        }
282 1
        return $this->streamHandler->fullCount();
283
    }
284
285
    public function isCached(): bool
286
    {
287
        if (null === $this->streamHandler) {
288
            $this->fetchOutstanding();
289
        }
290
        return $this->streamHandler->isCached();
291
    }
292
293
    public function writesExecuted(): ?int
294
    {
295
        if (null === $this->streamHandler) {
296
            $this->fetchOutstanding();
297
        }
298
        return $this->streamHandler->writesExecuted();
299
    }
300
301
    public function writesIgnored(): ?int
302
    {
303
        if (null === $this->streamHandler) {
304
            $this->fetchOutstanding();
305
        }
306
        return $this->streamHandler->writesIgnored();
307
    }
308
309
    public function scannedFull(): ?int
310
    {
311
        if (null === $this->streamHandler) {
312
            $this->fetchOutstanding();
313
        }
314
        return $this->streamHandler->scannedFull();
315
    }
316
317
    public function scannedIndex(): ?int
318
    {
319
        if (null === $this->streamHandler) {
320
            $this->fetchOutstanding();
321
        }
322
        return $this->streamHandler->scannedIndex();
323
    }
324
325
    public function filtered(): ?int
326
    {
327
        if (null === $this->streamHandler) {
328
            $this->fetchOutstanding();
329
        }
330
        return $this->streamHandler->filtered();
331
    }
332
333
    /**
334
     * @return string|array|object Complete response body data
335
     */
336
    public function raw()
337
    {
338
        return $this->streamHandler->raw();
339
    }
340
}
341