1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Analogue\ORM; |
4
|
|
|
|
5
|
|
|
use Analogue\ORM\Exceptions\MappingException; |
6
|
|
|
use Analogue\ORM\System\Manager; |
7
|
|
|
use Analogue\ORM\System\Wrappers\Factory; |
8
|
|
|
use Illuminate\Support\Collection; |
9
|
|
|
use Illuminate\Support\Arr; |
10
|
|
|
|
11
|
|
|
class EntityCollection extends Collection |
12
|
|
|
{ |
13
|
|
|
/** |
14
|
|
|
* Wrapper Factory |
15
|
|
|
* |
16
|
|
|
* @var \Analogue\ORM\System\Wrappers\Factory |
17
|
|
|
*/ |
18
|
|
|
protected $factory; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* EntityCollection constructor. |
22
|
|
|
* @param array|null $entities |
23
|
|
|
*/ |
24
|
|
|
public function __construct(array $entities = null) |
25
|
|
|
{ |
26
|
|
|
$this->factory = new Factory; |
27
|
|
|
|
28
|
|
|
parent::__construct($entities); |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Find an entity in the collection by key. |
33
|
|
|
* |
34
|
|
|
* @param mixed $key |
35
|
|
|
* @param mixed $default |
36
|
|
|
* @throws MappingException |
37
|
|
|
* @return \Analogue\ORM\Entity |
38
|
|
|
*/ |
39
|
|
|
public function find($key, $default = null) |
40
|
|
|
{ |
41
|
|
|
if ($key instanceof Mappable) { |
42
|
|
|
$key = $this->getEntityKey($key); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
return array_first($this->items, function ($itemKey, $entity) use ($key) { |
46
|
|
|
return $this->getEntityKey($entity) == $key; |
47
|
|
|
}, $default); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Add an entity to the collection. |
52
|
|
|
* |
53
|
|
|
* @param Mappable $entity |
54
|
|
|
* @return $this |
55
|
|
|
*/ |
56
|
|
|
public function add($entity) |
57
|
|
|
{ |
58
|
|
|
$this->push($entity); |
59
|
|
|
|
60
|
|
|
return $this; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Remove an entity from the collection |
65
|
|
|
* |
66
|
|
|
* @param $entity |
67
|
|
|
* @throws MappingException |
68
|
|
|
* @return mixed |
69
|
|
|
*/ |
70
|
|
|
public function remove($entity) |
71
|
|
|
{ |
72
|
|
|
$key = $this->getEntityKey($entity); |
73
|
|
|
|
74
|
|
|
return $this->pull($key); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* Push an item onto the end of the collection. |
79
|
|
|
* |
80
|
|
|
* @param mixed $value |
81
|
|
|
* @return void |
82
|
|
|
*/ |
83
|
|
|
public function push($value) |
84
|
|
|
{ |
85
|
|
|
$this->offsetSet(null, $value); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Put an item in the collection by key. |
90
|
|
|
* |
91
|
|
|
* @param mixed $key |
92
|
|
|
* @param mixed $value |
93
|
|
|
* @return void |
94
|
|
|
*/ |
95
|
|
|
public function put($key, $value) |
96
|
|
|
{ |
97
|
|
|
$this->offsetSet($key, $value); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Set the item at a given offset. |
102
|
|
|
* |
103
|
|
|
* @param mixed $key |
104
|
|
|
* @param mixed $value |
105
|
|
|
* @return void |
106
|
|
|
*/ |
107
|
|
|
public function offsetSet($key, $value) |
108
|
|
|
{ |
109
|
|
|
if (is_null($key)) { |
110
|
|
|
$this->items[] = $value; |
111
|
|
|
} else { |
112
|
|
|
$this->items[$key] = $value; |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Determine if a key exists in the collection. |
118
|
|
|
* |
119
|
|
|
* @param mixed $key |
120
|
|
|
* @param mixed|null $value |
121
|
|
|
* @return bool |
122
|
|
|
*/ |
123
|
|
|
public function contains($key, $value = null) |
124
|
|
|
{ |
125
|
|
|
if (func_num_args() == 2) { |
126
|
|
|
return !$this->where($key, $value)->isEmpty(); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
if ($this->useAsCallable($key)) { |
130
|
|
|
return !is_null($this->first($key)); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
return !is_null($this->find($key)); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Fetch a nested element of the collection. |
138
|
|
|
* |
139
|
|
|
* @param string $key |
140
|
|
|
* @return self |
141
|
|
|
*/ |
142
|
|
|
public function fetch($key) |
143
|
|
|
{ |
144
|
|
|
return new static(array_fetch($this->toArray(), $key)); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Generic function for returning class.key value pairs |
149
|
|
|
* |
150
|
|
|
* @throws MappingException |
151
|
|
|
* @return string |
152
|
|
|
*/ |
153
|
|
View Code Duplication |
public function getEntityHashes() |
|
|
|
|
154
|
|
|
{ |
155
|
|
|
return array_map(function ($entity) { |
156
|
|
|
$class = get_class($entity); |
157
|
|
|
|
158
|
|
|
$mapper = Manager::getMapper($class); |
159
|
|
|
|
160
|
|
|
$keyName = $mapper->getEntityMap()->getKeyName(); |
161
|
|
|
|
162
|
|
|
return $class . '.' . $entity->getEntityAttribute($keyName); |
163
|
|
|
}, |
164
|
|
|
$this->items); |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Get a subset of the collection from entity hashes |
169
|
|
|
* |
170
|
|
|
* @param array $hashes |
171
|
|
|
* @throws MappingException |
172
|
|
|
* @return array |
173
|
|
|
*/ |
174
|
|
|
public function getSubsetByHashes(array $hashes) |
175
|
|
|
{ |
176
|
|
|
$subset = []; |
177
|
|
|
|
178
|
|
|
foreach ($this->items as $item) { |
179
|
|
|
$class = get_class($item); |
180
|
|
|
|
181
|
|
|
$mapper = Manager::getMapper($class); |
182
|
|
|
|
183
|
|
|
$keyName = $mapper->getEntityMap()->getKeyName(); |
184
|
|
|
|
185
|
|
|
if (in_array($class . '.' . $item->$keyName, $hashes)) { |
186
|
|
|
$subset[] = $item; |
187
|
|
|
} |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
return $subset; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Merge the collection with the given items. |
195
|
|
|
* |
196
|
|
|
* @param array $items |
197
|
|
|
* @throws MappingException |
198
|
|
|
* @return self |
199
|
|
|
*/ |
200
|
|
|
public function merge($items) |
201
|
|
|
{ |
202
|
|
|
$dictionary = $this->getDictionary(); |
203
|
|
|
|
204
|
|
|
foreach ($items as $item) { |
205
|
|
|
$dictionary[$this->getEntityKey($item)] = $item; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
return new static(array_values($dictionary)); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Diff the collection with the given items. |
213
|
|
|
* |
214
|
|
|
* @param \ArrayAccess|array $items |
215
|
|
|
* @return self |
216
|
|
|
*/ |
217
|
|
View Code Duplication |
public function diff($items) |
|
|
|
|
218
|
|
|
{ |
219
|
|
|
$diff = new static; |
220
|
|
|
|
221
|
|
|
$dictionary = $this->getDictionary($items); |
222
|
|
|
|
223
|
|
|
foreach ($this->items as $item) { |
224
|
|
|
if (!isset($dictionary[$this->getEntityKey($item)])) { |
225
|
|
|
$diff->add($item); |
226
|
|
|
} |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
return $diff; |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* Intersect the collection with the given items. |
234
|
|
|
* |
235
|
|
|
* @param \ArrayAccess|array $items |
236
|
|
|
* @throws MappingException |
237
|
|
|
* @return self |
238
|
|
|
*/ |
239
|
|
View Code Duplication |
public function intersect($items) |
|
|
|
|
240
|
|
|
{ |
241
|
|
|
$intersect = new static; |
242
|
|
|
|
243
|
|
|
$dictionary = $this->getDictionary($items); |
244
|
|
|
|
245
|
|
|
foreach ($this->items as $item) { |
246
|
|
|
if (isset($dictionary[$this->getEntityKey($item)])) { |
247
|
|
|
$intersect->add($item); |
248
|
|
|
} |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
return $intersect; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Returns only the models from the collection with the specified keys. |
256
|
|
|
* |
257
|
|
|
* @param mixed $keys |
258
|
|
|
* @return self |
259
|
|
|
*/ |
260
|
|
|
public function only($keys) |
261
|
|
|
{ |
262
|
|
|
$dictionary = array_only($this->getDictionary(), $keys); |
263
|
|
|
|
264
|
|
|
return new static(array_values($dictionary)); |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* Returns all models in the collection except the models with specified keys. |
269
|
|
|
* |
270
|
|
|
* @param mixed $keys |
271
|
|
|
* @return self |
272
|
|
|
*/ |
273
|
|
|
public function except($keys) |
274
|
|
|
{ |
275
|
|
|
$dictionary = array_except($this->getDictionary(), $keys); |
276
|
|
|
|
277
|
|
|
return new static(array_values($dictionary)); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
/** |
281
|
|
|
* Get a dictionary keyed by primary keys. |
282
|
|
|
* |
283
|
|
|
* @param \ArrayAccess|array $items |
284
|
|
|
* @throws MappingException |
285
|
|
|
* @return array |
286
|
|
|
*/ |
287
|
|
|
public function getDictionary($items = null) |
288
|
|
|
{ |
289
|
|
|
$items = is_null($items) ? $this->items : $items; |
290
|
|
|
|
291
|
|
|
$dictionary = []; |
292
|
|
|
|
293
|
|
|
foreach ($items as $value) { |
294
|
|
|
$dictionary[$this->getEntityKey($value)] = $value; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
return $dictionary; |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
/** |
301
|
|
|
* @throws MappingException |
302
|
|
|
* @return array |
303
|
|
|
*/ |
304
|
|
|
public function getEntityKeys() |
305
|
|
|
{ |
306
|
|
|
return array_keys($this->getDictionary()); |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* @param $entity |
311
|
|
|
* @throws MappingException |
312
|
|
|
* @return mixed |
313
|
|
|
*/ |
314
|
|
|
protected function getEntityKey($entity) |
315
|
|
|
{ |
316
|
|
|
$keyName = Manager::getMapper($entity)->getEntityMap()->getKeyName(); |
317
|
|
|
|
318
|
|
|
$wrapper = $this->factory->make($entity); |
319
|
|
|
|
320
|
|
|
return $wrapper->getEntityAttribute($keyName); |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* Get the max value of a given key. |
325
|
|
|
* |
326
|
|
|
* @param string|null $key |
327
|
|
|
* @throws MappingException |
328
|
|
|
* @return mixed |
329
|
|
|
*/ |
330
|
|
View Code Duplication |
public function max($key = null) |
|
|
|
|
331
|
|
|
{ |
332
|
|
|
return $this->reduce(function ($result, $item) use ($key) { |
333
|
|
|
$wrapper = $this->factory->make($item); |
334
|
|
|
|
335
|
|
|
return (is_null($result) || $wrapper->getEntityAttribute($key) > $result) ? |
336
|
|
|
$wrapper->getEntityAttribute($key) : $result; |
337
|
|
|
}); |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
/** |
341
|
|
|
* Get the min value of a given key. |
342
|
|
|
* |
343
|
|
|
* @param string|null $key |
344
|
|
|
* @throws MappingException |
345
|
|
|
* @return mixed |
346
|
|
|
*/ |
347
|
|
View Code Duplication |
public function min($key = null) |
|
|
|
|
348
|
|
|
{ |
349
|
|
|
return $this->reduce(function ($result, $item) use ($key) { |
350
|
|
|
$wrapper = $this->factory->make($item); |
351
|
|
|
|
352
|
|
|
return (is_null($result) || $wrapper->getEntityAttribute($key) < $result) |
353
|
|
|
? $wrapper->getEntityAttribute($key) : $result; |
354
|
|
|
}); |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
/** |
358
|
|
|
* Get an array with the values of a given key. |
359
|
|
|
* |
360
|
|
|
* @param string $value |
361
|
|
|
* @param string|null $key |
362
|
|
|
* @return self |
363
|
|
|
*/ |
364
|
|
|
public function pluck($value, $key = null) |
365
|
|
|
{ |
366
|
|
|
return new Collection(Arr::pluck($this->items, $value, $key)); |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
/** |
370
|
|
|
* Alias for the "pluck" method. |
371
|
|
|
* |
372
|
|
|
* @param string $value |
373
|
|
|
* @param string|null $key |
374
|
|
|
* @return self |
375
|
|
|
*/ |
376
|
|
|
public function lists($value, $key = null) |
377
|
|
|
{ |
378
|
|
|
return $this->pluck($value, $key); |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
/** |
382
|
|
|
* Return only unique items from the collection. |
383
|
|
|
* |
384
|
|
|
* @param string|null $key |
385
|
|
|
* @throws MappingException |
386
|
|
|
* @return self |
387
|
|
|
*/ |
388
|
|
|
public function unique($key = null) |
389
|
|
|
{ |
390
|
|
|
$dictionary = $this->getDictionary(); |
391
|
|
|
|
392
|
|
|
return new static(array_values($dictionary)); |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
/** |
396
|
|
|
* Get a base Support collection instance from this collection. |
397
|
|
|
* |
398
|
|
|
* @return \Illuminate\Support\Collection |
399
|
|
|
*/ |
400
|
|
|
public function toBase() |
401
|
|
|
{ |
402
|
|
|
return new Collection($this->items); |
403
|
|
|
} |
404
|
|
|
} |
405
|
|
|
|
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.