Collection::rewind()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 7
rs 10
1
<?php
2
3
namespace TraderInteractive\Api;
4
5
use TraderInteractive\Util;
6
7
/**
8
 * Class for iterating index responses. Collections are readonly
9
 */
10
final class Collection implements \Iterator, \Countable
11
{
12
    /**
13
     * API Client
14
     *
15
     * @var ClientInterface
16
     */
17
    private $client;
18
19
    /**
20
     * limit to give to API
21
     *
22
     * @var int
23
     */
24
    private $limit;
25
26
    /**
27
     * offset to give to API
28
     *
29
     * @var int
30
     */
31
    private $offset;
32
33
    /**
34
     * resource name for collection
35
     *
36
     * @var string
37
     */
38
    private $resource;
39
40
    /**
41
     * array of filters to pass to API
42
     *
43
     * @var array
44
     */
45
    private $filters;
46
47
    /**
48
     * Total number of elements in the collection
49
     *
50
     * @var int
51
     */
52
    private $total;
53
54
    /**
55
     * pointer in the paginated results
56
     *
57
     * @var int
58
     */
59
    private $position;
60
61
    /**
62
     * A paginated set of elements from the API
63
     *
64
     * @var array|null
65
     */
66
    private $result;
67
68
    /**
69
     * Create a new collection
70
     *
71
     * @param ClientInterface $client   Configured client connection to the API.
72
     * @param string          $resource The name of API resource to request.
73
     * @param array           $filters  A key value pair array of search filters.
74
     */
75
    public function __construct(ClientInterface $client, string $resource, array $filters = [])
76
    {
77
        $this->client = $client;
78
        $this->resource = $resource;
79
        $this->filters = $filters;
80
        $this->rewind();
81
    }
82
83
    /**
84
     * @see Countable::count()
85
     *
86
     * @return integer
87
     */
88
    public function count() : int
89
    {
90
        if ($this->position === -1) {
91
            $this->next();
92
        }
93
94
        return $this->total;
95
    }
96
97
    /**
98
     * @see Iterator::rewind()
99
     *
100
     * @return void
101
     */
102
    public function rewind()
103
    {
104
        $this->result = null;
105
        $this->offset = 0;
106
        $this->total = 0;
107
        $this->limit = 0;
108
        $this->position = -1;
109
    }
110
111
    /**
112
     * @see Iterator::key()
113
     *
114
     * @return integer
115
     */
116
    public function key() : int
117
    {
118
        if ($this->position === -1) {
119
            $this->next();
120
        }
121
122
        Util::ensure(false, empty($this->result), '\OutOfBoundsException', ['Collection contains no elements']);
123
124
        return $this->offset + $this->position;
125
    }
126
127
    /**
128
     * @see Iterator::valid()
129
     *
130
     * @return bool
131
     */
132
    public function valid() : bool
133
    {
134
        if ($this->position === -1) {
135
            $this->next();
136
        }
137
138
        return $this->offset + $this->position < $this->total;
139
    }
140
141
    /**
142
     * @see Iterator::next()
143
     *
144
     * @return void
145
     */
146
    public function next()
147
    {
148
        ++$this->position;
149
150
        if ($this->position < $this->limit) {
151
            return;
152
        }
153
154
        $this->offset += $this->limit;
155
        $this->filters['offset'] = $this->offset;
156
        $indexResponse = $this->client->index($this->resource, $this->filters);
157
158
        $httpCode = $indexResponse->getHttpCode();
159
        $expectedHttpCode = 200;
160
        $exceptionArgs = ["Did not receive 200 from API. Instead received {$httpCode}", $indexResponse];
161
162
        Util::ensure($expectedHttpCode, $httpCode, Exception::class, $exceptionArgs);
163
164
        $response = $indexResponse->getResponse();
165
        $this->limit = $response['pagination']['limit'];
166
        $this->total = $response['pagination']['total'];
167
        $this->result = $response['result'];
168
        $this->position = 0;
169
    }
170
171
    /**
172
     * @see Iterator::current()
173
     *
174
     * @return array
175
     */
176
    public function current() : array
177
    {
178
        if ($this->position === -1) {
179
            $this->next();
180
        }
181
182
        Util::ensure(
183
            true,
184
            array_key_exists($this->position, $this->result),
185
            '\OutOfBoundsException',
186
            ['Collection contains no element at current position']
187
        );
188
189
        return $this->result[$this->position];
190
    }
191
192
    /**
193
     * Returns the values from a single field this collection, identified by the given $key.
194
     *
195
     * @param string $key The name of the field for which the values will be returned.
196
     *
197
     * @return \Iterator
198
     */
199
    public function column(string $key) : \Iterator
200
    {
201
        foreach ($this as $item) {
202
            yield Util\Arrays::get($item, $key);
203
        }
204
    }
205
206
    /**
207
     * Return an iterable generator containing only the fields specified in the $keys array.
208
     *
209
     * @param array $keys The list of field names to be returned.
210
     *
211
     * @return \Generator
212
     */
213
    public function select(array $keys) : \Iterator
214
    {
215
        foreach ($this as $item) {
216
            $result = array_fill_keys($keys, null);
217
            Util\Arrays::copyIfKeysExist($item, $result, $keys);
218
            yield  $result;
219
        }
220
    }
221
}
222