1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace TraderInteractive\Api; |
4
|
|
|
|
5
|
|
|
use DominionEnterprises\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 Client $client client connection to the API |
72
|
|
|
* @param string $resource name of API resource to request |
73
|
|
|
* @param array $filters key value pair array of search filters |
74
|
|
|
*/ |
75
|
|
|
public function __construct(ClientInterface $client, $resource, array $filters = []) |
76
|
|
|
{ |
77
|
|
|
Util::throwIfNotType(['string' => [$resource]], true); |
78
|
|
|
|
79
|
|
|
$this->client = $client; |
80
|
|
|
$this->resource = $resource; |
81
|
|
|
$this->filters = $filters; |
82
|
|
|
$this->rewind(); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @see Countable::count() |
87
|
|
|
* |
88
|
|
|
* @return int |
89
|
|
|
*/ |
90
|
|
|
public function count() |
91
|
|
|
{ |
92
|
|
|
if ($this->position === -1) { |
93
|
|
|
$this->next(); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
return $this->total; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @see Iterator::rewind() |
101
|
|
|
* |
102
|
|
|
* @return void |
103
|
|
|
*/ |
104
|
|
|
public function rewind() |
105
|
|
|
{ |
106
|
|
|
$this->result = null; |
107
|
|
|
$this->offset = 0; |
108
|
|
|
$this->total = 0; |
109
|
|
|
$this->limit = 0; |
110
|
|
|
$this->position = -1; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* @see Iterator::key() |
115
|
|
|
* |
116
|
|
|
* @return int |
117
|
|
|
*/ |
118
|
|
View Code Duplication |
public function key() |
|
|
|
|
119
|
|
|
{ |
120
|
|
|
if ($this->position === -1) { |
121
|
|
|
$this->next(); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
Util::ensure(false, empty($this->result), '\OutOfBoundsException', ['Collection contains no elements']); |
125
|
|
|
|
126
|
|
|
return $this->offset + $this->position; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* @see Iterator::valid() |
131
|
|
|
* |
132
|
|
|
* @return bool |
133
|
|
|
*/ |
134
|
|
|
public function valid() |
135
|
|
|
{ |
136
|
|
|
if ($this->position === -1) { |
137
|
|
|
$this->next(); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return $this->offset + $this->position < $this->total; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* @see Iterator::next() |
145
|
|
|
* |
146
|
|
|
* @return void |
147
|
|
|
*/ |
148
|
|
|
public function next() |
149
|
|
|
{ |
150
|
|
|
++$this->position; |
151
|
|
|
|
152
|
|
|
if ($this->position < $this->limit) { |
153
|
|
|
return; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
$this->offset += $this->limit; |
157
|
|
|
$this->filters['offset'] = $this->offset; |
158
|
|
|
$indexResponse = $this->client->index($this->resource, $this->filters); |
159
|
|
|
|
160
|
|
|
$httpCode = $indexResponse->getHttpCode(); |
161
|
|
|
Util::ensure(200, $httpCode, "Did not receive 200 from API. Instead received {$httpCode}"); |
162
|
|
|
|
163
|
|
|
$response = $indexResponse->getResponse(); |
164
|
|
|
$this->limit = $response['pagination']['limit']; |
165
|
|
|
$this->total = $response['pagination']['total']; |
166
|
|
|
$this->result = $response['result']; |
167
|
|
|
$this->position = 0; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @see Iterator::current() |
172
|
|
|
* |
173
|
|
|
* @return array |
174
|
|
|
*/ |
175
|
|
View Code Duplication |
public function current() |
|
|
|
|
176
|
|
|
{ |
177
|
|
|
if ($this->position === -1) { |
178
|
|
|
$this->next(); |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
Util::ensure( |
182
|
|
|
true, |
183
|
|
|
array_key_exists($this->position, $this->result), |
184
|
|
|
'\OutOfBoundsException', |
185
|
|
|
['Collection contains no element at current position'] |
186
|
|
|
); |
187
|
|
|
|
188
|
|
|
return $this->result[$this->position]; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Returns the values from a single field this collection, identified by the given $key. |
193
|
|
|
* |
194
|
|
|
* @param string $key The name of the field for which the values will be returned. |
195
|
|
|
* |
196
|
|
|
* @return iterable |
197
|
|
|
*/ |
198
|
|
|
public function column($key) |
199
|
|
|
{ |
200
|
|
|
foreach ($this as $item) { |
201
|
|
|
yield Util\Arrays::get($item, $key); |
202
|
|
|
} |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Return an iterable generator containing only the fields specified in the $keys array. |
207
|
|
|
* |
208
|
|
|
* @param array $keys The list of field names to be returned. |
209
|
|
|
* |
210
|
|
|
* @return \Generator |
211
|
|
|
*/ |
212
|
|
|
public function select(array $keys) |
213
|
|
|
{ |
214
|
|
|
foreach ($this as $item) { |
215
|
|
|
$result = array_fill_keys($keys, null); |
216
|
|
|
Util\Arrays::copyIfKeysExist($item, $result, $keys); |
217
|
|
|
yield $result; |
218
|
|
|
} |
219
|
|
|
} |
220
|
|
|
} |
221
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.