1
|
|
|
<?php |
2
|
|
|
namespace Intraxia\Jaxion\Axolotl; |
3
|
|
|
|
4
|
|
|
use Intraxia\Jaxion\Contract\Axolotl\Collection as CollectionContract; |
5
|
|
|
use Intraxia\Jaxion\Contract\Axolotl\Serializes; |
6
|
|
|
use InvalidArgumentException; |
7
|
|
|
use OutOfBoundsException; |
8
|
|
|
use OutOfRangeException; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Class Collection |
12
|
|
|
* |
13
|
|
|
* @package Intraxia\Jaxion |
14
|
|
|
* @subpackage Axolotl |
15
|
|
|
*/ |
16
|
|
|
class Collection implements CollectionContract { |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Collection elements. |
20
|
|
|
* |
21
|
|
|
* @var array |
22
|
|
|
*/ |
23
|
|
|
protected $elements = array(); |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Collection type to enforce. |
27
|
|
|
* |
28
|
|
|
* @var Type |
29
|
|
|
*/ |
30
|
|
|
private $type; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Where Collection is in loop. |
34
|
|
|
* |
35
|
|
|
* @var int |
36
|
|
|
*/ |
37
|
|
|
protected $position = 0; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Collection constructor. |
41
|
|
|
* |
42
|
|
|
* @param string $type |
43
|
|
|
* @param array $elements |
44
|
|
|
*/ |
45
|
312 |
|
public function __construct( $type, array $elements = array() ) { |
46
|
312 |
|
$this->type = new Type( $type ); |
47
|
|
|
|
48
|
309 |
|
if ( $this->type->is_model() ) { |
49
|
33 |
|
foreach ( $elements as $idx => $element ) { |
50
|
27 |
|
if ( is_array( $element ) ) { |
51
|
9 |
|
$elements[ $idx ] = $this->type->create_model( $element ); |
52
|
6 |
|
} |
53
|
22 |
|
} |
54
|
22 |
|
} |
55
|
|
|
|
56
|
309 |
|
if ( $elements ) { |
57
|
216 |
|
$this->type->validate_elements( $elements ); |
58
|
144 |
|
} |
59
|
|
|
|
60
|
309 |
|
$this->elements = $elements; |
61
|
309 |
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* {@inheritdoc} |
65
|
|
|
* |
66
|
|
|
* @return string |
67
|
|
|
*/ |
68
|
144 |
|
public function get_type() { |
69
|
144 |
|
return $this->type->get_type(); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* {@inheritdoc} |
74
|
|
|
* |
75
|
|
|
* @param mixed $element |
76
|
|
|
* |
77
|
|
|
* @return Collection |
78
|
|
|
* |
79
|
|
|
* @throws InvalidArgumentException |
80
|
|
|
*/ |
81
|
51 |
|
public function add( $element ) { |
82
|
51 |
|
if ( $this->type->is_model() && is_array( $element ) ) { |
83
|
3 |
|
$element = $this->type->create_model( $element ); |
84
|
2 |
|
} |
85
|
|
|
|
86
|
51 |
|
$this->type->validate_element( $element ); |
87
|
|
|
|
88
|
45 |
|
$elements = $this->elements; |
89
|
45 |
|
$elements[] = $element; |
90
|
|
|
|
91
|
45 |
|
$collection = new static( $this->get_type() ); |
92
|
45 |
|
$collection->set_from_trusted( $elements ); |
93
|
|
|
|
94
|
45 |
|
return $collection; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* {@inheritdoc} |
99
|
|
|
* |
100
|
|
|
* @return Collection |
101
|
|
|
*/ |
102
|
6 |
|
public function clear() { |
103
|
6 |
|
return new static( $this->get_type() ); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* {@inheritdoc} |
108
|
|
|
* |
109
|
|
|
* @param callable $condition Condition to satisfy. |
110
|
|
|
* |
111
|
|
|
* @return bool |
112
|
|
|
*/ |
113
|
9 |
|
public function contains( $condition ) { |
114
|
9 |
|
return (bool) $this->find( $condition ); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* {@inheritdoc} |
119
|
|
|
* |
120
|
|
|
* @param callable $condition Condition to satisfy. |
121
|
|
|
* |
122
|
|
|
* @return mixed |
123
|
|
|
*/ |
124
|
15 |
|
public function find( $condition ) { |
125
|
15 |
|
$index = $this->find_index( $condition ); |
126
|
|
|
|
127
|
15 |
|
return -1 === $index ? null : $this->elements[ $index ]; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* {@inheritdoc} |
132
|
|
|
* |
133
|
|
|
* @param callable $condition Condition to satisfy. |
134
|
|
|
* |
135
|
|
|
* @return int |
136
|
|
|
*/ |
137
|
21 |
|
public function find_index( $condition ) { |
138
|
21 |
|
$index = -1; |
139
|
|
|
|
140
|
21 |
|
for ( $i = 0, $count = count( $this->elements ); $i < $count; $i++ ) { |
141
|
21 |
|
if ( call_user_func( $condition, ($this->at( $i ) ) ) ) { |
142
|
12 |
|
$index = $i; |
143
|
12 |
|
break; |
144
|
|
|
} |
145
|
10 |
|
} |
146
|
|
|
|
147
|
21 |
|
return $index; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Fetches the element at the provided index. |
152
|
|
|
* |
153
|
|
|
* @param int $index Index to get element from. |
154
|
|
|
* |
155
|
|
|
* @return mixed |
156
|
|
|
* |
157
|
|
|
* @throws OutOfRangeException |
158
|
|
|
*/ |
159
|
99 |
|
public function at( $index ) { |
160
|
99 |
|
$this->validate_index( $index ); |
161
|
|
|
|
162
|
90 |
|
return $this->elements[ $index ]; |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* {@inheritdoc} |
167
|
|
|
* |
168
|
|
|
* @param int $index Index to check for existence. |
169
|
|
|
* |
170
|
|
|
* @return bool |
171
|
|
|
* |
172
|
|
|
* @throws InvalidArgumentException |
173
|
|
|
*/ |
174
|
111 |
|
public function index_exists( $index ) { |
175
|
111 |
|
if ( ! is_int( $index ) ) { |
176
|
6 |
|
throw new InvalidArgumentException( 'Index must be an integer' ); |
177
|
|
|
} |
178
|
|
|
|
179
|
105 |
|
if ( $index < 0 ) { |
180
|
6 |
|
throw new InvalidArgumentException( 'Index must be a non-negative integer' ); |
181
|
|
|
} |
182
|
|
|
|
183
|
99 |
|
return $index < $this->count(); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* {@inheritdoc} |
188
|
|
|
* |
189
|
|
|
* @param callable $condition Condition to satisfy. |
190
|
|
|
* |
191
|
|
|
* @return Collection |
192
|
|
|
*/ |
193
|
6 |
|
public function filter( $condition ) { |
194
|
6 |
|
$elements = array(); |
195
|
|
|
|
196
|
6 |
|
foreach ( $this->elements as $element ) { |
197
|
6 |
|
if ( call_user_func( $condition, $element ) ) { |
198
|
6 |
|
$elements[] = $element; |
199
|
4 |
|
} |
200
|
4 |
|
} |
201
|
|
|
|
202
|
6 |
|
return $this->new_from_trusted( $elements ); |
203
|
|
|
} |
204
|
|
|
/** |
205
|
|
|
* {@inheritdoc} |
206
|
|
|
* |
207
|
|
|
* @param callable $condition Condition to satisfy. |
208
|
|
|
* |
209
|
|
|
* @return mixed |
210
|
|
|
*/ |
211
|
6 |
|
public function find_last( $condition ) { |
212
|
6 |
|
$index = $this->find_last_index( $condition ); |
213
|
|
|
|
214
|
6 |
|
return -1 === $index ? null : $this->elements[ $index ]; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* {@inheritdoc} |
219
|
|
|
* |
220
|
|
|
* @param callable $condition |
221
|
|
|
* @return int |
222
|
|
|
*/ |
223
|
12 |
|
public function find_last_index( $condition ) { |
224
|
12 |
|
$index = -1; |
225
|
|
|
|
226
|
12 |
|
for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) { |
227
|
12 |
|
if ( call_user_func( $condition, $this->elements[ $i ] ) ) { |
228
|
6 |
|
$index = $i; |
229
|
6 |
|
break; |
230
|
|
|
} |
231
|
6 |
|
} |
232
|
|
|
|
233
|
12 |
|
return $index; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* {@inheritdoc} |
238
|
|
|
* |
239
|
|
|
* @param int $start Begining index to slice from. |
240
|
|
|
* @param int $end End index to slice to. |
241
|
|
|
* |
242
|
|
|
* @return Collection |
243
|
|
|
* |
244
|
|
|
* @throws InvalidArgumentException |
245
|
|
|
*/ |
246
|
81 |
|
public function slice( $start, $end ) { |
247
|
81 |
|
if ( $start < 0 || ! is_int( $start ) ) { |
248
|
3 |
|
throw new InvalidArgumentException( 'Start must be a non-negative integer' ); |
249
|
|
|
} |
250
|
|
|
|
251
|
78 |
|
if ( $end < 0 || ! is_int( $end ) ) { |
252
|
6 |
|
throw new InvalidArgumentException( 'End must be a positive integer' ); |
253
|
|
|
} |
254
|
|
|
|
255
|
72 |
|
if ( $start > $end ) { |
256
|
3 |
|
throw new InvalidArgumentException( 'End must be greater than start' ); |
257
|
|
|
} |
258
|
|
|
|
259
|
69 |
|
if ( $end > $this->count() + 1 ) { |
260
|
9 |
|
throw new InvalidArgumentException( 'End must be less than the count of the items in the Collection' ); |
261
|
|
|
} |
262
|
|
|
|
263
|
60 |
|
$length = $end - $start + 1; |
264
|
|
|
|
265
|
60 |
|
return $this->new_from_trusted( array_slice( $this->elements, $start, $length ) ); |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* {@inheritdoc} |
270
|
|
|
* |
271
|
|
|
* @param int $index Index to start at. |
272
|
|
|
* @param mixed $element Element to insert. |
273
|
|
|
* |
274
|
|
|
* @return Collection |
275
|
|
|
* |
276
|
|
|
* @throws InvalidArgumentException |
277
|
|
|
* @throws OutOfRangeException |
278
|
|
|
*/ |
279
|
3 |
|
public function insert( $index, $element ) { |
280
|
3 |
|
$this->validate_index( $index ); |
281
|
3 |
|
$this->type->validate_element( $element ); |
282
|
|
|
|
283
|
3 |
|
$a = array_slice( $this->elements, 0, $index ); |
284
|
3 |
|
$b = array_slice( $this->elements, $index, count( $this->elements ) ); |
285
|
|
|
|
286
|
3 |
|
$a[] = $element; |
287
|
|
|
|
288
|
3 |
|
return $this->new_from_trusted( array_merge( $a, $b ) ); |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
/** |
292
|
|
|
* {@inheritdoc} |
293
|
|
|
* |
294
|
|
|
* @param int $index Index to start insertion at. |
295
|
|
|
* @param array $elements Elements in insert. |
296
|
|
|
* |
297
|
|
|
* @return Collection |
298
|
|
|
* |
299
|
|
|
* @throws OutOfRangeException |
300
|
|
|
*/ |
301
|
3 |
|
public function insert_range( $index, array $elements ) { |
302
|
3 |
|
$this->validate_index( $index ); |
303
|
3 |
|
$this->type->validate_elements( $elements ); |
304
|
|
|
|
305
|
3 |
|
if ( $index < 0 ) { |
306
|
|
|
$index = $this->count() + $index + 1; |
307
|
|
|
} |
308
|
|
|
|
309
|
3 |
|
return $this->new_from_trusted( |
310
|
3 |
|
array_merge( |
311
|
3 |
|
array_slice( $this->elements, 0, $index ), |
312
|
2 |
|
$elements, |
313
|
3 |
|
array_slice( $this->elements, $index, count( $this->elements ) ) |
314
|
2 |
|
) |
315
|
2 |
|
); |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
/** |
319
|
|
|
* {@inheritdoc} |
320
|
|
|
* |
321
|
|
|
* @param callable $condition Condition to satisfy. |
322
|
|
|
* |
323
|
|
|
* @return Collection |
324
|
|
|
*/ |
325
|
2 |
|
public function reject( $condition ) { |
326
|
1 |
|
$inverse = function ( $element ) use ( $condition ) { |
327
|
3 |
|
return ! call_user_func( $condition, $element ); |
328
|
3 |
|
}; |
329
|
|
|
|
330
|
3 |
|
return $this->filter( $inverse ); |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
/** |
334
|
|
|
* {@inheritdoc} |
335
|
|
|
* |
336
|
|
|
* @param int $index Index to remove. |
337
|
|
|
* |
338
|
|
|
* @return Collection |
339
|
|
|
* |
340
|
|
|
* @throws OutOfRangeException |
341
|
|
|
*/ |
342
|
3 |
|
public function remove_at( $index ) { |
343
|
3 |
|
$this->validate_index( $index ); |
344
|
|
|
|
345
|
3 |
|
$elements = $this->elements; |
346
|
|
|
|
347
|
3 |
|
return $this->new_from_trusted( |
348
|
3 |
|
array_merge( |
349
|
3 |
|
array_slice( $elements, 0, $index ), |
350
|
3 |
|
array_slice( $elements, $index + 1, count( $elements ) ) |
351
|
2 |
|
) |
352
|
2 |
|
); |
353
|
|
|
} |
354
|
|
|
/** |
355
|
|
|
* {@inheritdoc} |
356
|
|
|
* |
357
|
|
|
* @return Collection |
358
|
|
|
*/ |
359
|
3 |
|
public function reverse() { |
360
|
3 |
|
return $this->new_from_trusted( |
361
|
3 |
|
array_reverse( $this->elements ) |
362
|
2 |
|
); |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
/** |
366
|
|
|
* {@inheritdoc} |
367
|
|
|
* |
368
|
|
|
* @param callable $callback Sort callback. |
369
|
|
|
* |
370
|
|
|
* @return Collection |
371
|
|
|
*/ |
372
|
3 |
|
public function sort( $callback ) { |
373
|
3 |
|
$elements = $this->elements; |
374
|
3 |
|
usort( $elements, $callback ); |
375
|
3 |
|
return $this->new_from_trusted( $elements ); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* {@inheritdoc} |
380
|
|
|
* |
381
|
|
|
* @return array |
382
|
|
|
*/ |
383
|
30 |
|
public function to_array() { |
384
|
30 |
|
return $this->elements; |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
/** |
388
|
|
|
* {@inheritdoc} |
389
|
|
|
* |
390
|
|
|
* @param callable $callable Reducer function. |
391
|
|
|
* |
392
|
|
|
* @param null $initial Initial reducer value. |
393
|
|
|
* |
394
|
|
|
* @return mixed |
395
|
|
|
*/ |
396
|
3 |
|
public function reduce( $callable, $initial = null ) { |
397
|
3 |
|
return array_reduce( $this->elements, $callable, $initial ); |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* {@inheritdoc} |
402
|
|
|
* |
403
|
|
|
* @param callable $condition Condition callback. |
404
|
|
|
* |
405
|
|
|
* @return bool |
406
|
|
|
*/ |
407
|
6 |
|
public function every( $condition ) { |
408
|
6 |
|
$response = true; |
409
|
|
|
|
410
|
6 |
|
foreach ( $this->elements as $element ) { |
411
|
6 |
|
$result = call_user_func( $condition, $element ); |
412
|
|
|
|
413
|
6 |
|
if ( false === $result ) { |
414
|
3 |
|
$response = false; |
415
|
3 |
|
break; |
416
|
|
|
} |
417
|
4 |
|
} |
418
|
|
|
|
419
|
6 |
|
return $response; |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
/** |
423
|
|
|
* {@inheritdoc} |
424
|
|
|
* |
425
|
|
|
* @param int $num Number of elements to drop. |
426
|
|
|
* |
427
|
|
|
* @return Collection |
428
|
|
|
* |
429
|
|
|
* @throws InvalidArgumentException |
430
|
|
|
*/ |
431
|
18 |
|
public function drop( $num ) { |
432
|
18 |
|
if ( $num > $this->count() ) { |
433
|
3 |
|
$num = $this->count(); |
434
|
2 |
|
} |
435
|
|
|
|
436
|
18 |
|
return $this->slice( $num, $this->count() ); |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
/** |
440
|
|
|
* {@inheritdoc} |
441
|
|
|
* |
442
|
|
|
* @param int $num Number of elements to drop. |
443
|
|
|
* |
444
|
|
|
* @return Collection |
445
|
|
|
* |
446
|
|
|
* @throws InvalidArgumentException |
447
|
|
|
*/ |
448
|
9 |
|
public function drop_right( $num ) { |
449
|
9 |
|
return $num !== $this->count() |
450
|
9 |
|
? $this->slice( 0, $this->count() - $num - 1 ) |
451
|
9 |
|
: $this->clear(); |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
/** |
455
|
|
|
* {@inheritdoc} |
456
|
|
|
* |
457
|
|
|
* @param callable $condition Condition callback. |
458
|
|
|
* |
459
|
|
|
* @return Collection |
460
|
|
|
*/ |
461
|
9 |
|
public function drop_while( $condition ) { |
462
|
9 |
|
$count = $this->count_while_true( $condition ); |
463
|
9 |
|
return $count ? $this->drop( $count ) : $this; |
464
|
|
|
} |
465
|
|
|
/** |
466
|
|
|
* {@inheritdoc} |
467
|
|
|
* |
468
|
|
|
* @return Collection |
469
|
|
|
* |
470
|
|
|
* @throws InvalidArgumentException |
471
|
|
|
*/ |
472
|
3 |
|
public function tail() { |
473
|
3 |
|
return $this->slice( 1, $this->count() ); |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
/** |
477
|
|
|
* {@inheritdoc} |
478
|
|
|
* |
479
|
|
|
* @param int $num Number of elements to take. |
480
|
|
|
* |
481
|
|
|
* @return Collection |
482
|
|
|
* |
483
|
|
|
* @throws InvalidArgumentException |
484
|
|
|
*/ |
485
|
18 |
|
public function take( $num ) { |
486
|
18 |
|
return $this->slice( 0, $num - 1 ); |
487
|
|
|
} |
488
|
|
|
|
489
|
|
|
/** |
490
|
|
|
* {@inheritdoc} |
491
|
|
|
* |
492
|
|
|
* @param int $num Number of elements to take. |
493
|
|
|
* |
494
|
|
|
* @return Collection |
495
|
|
|
* |
496
|
|
|
* @throws InvalidArgumentException |
497
|
|
|
*/ |
498
|
3 |
|
public function take_right( $num ) { |
499
|
3 |
|
return $this->slice( $this->count() - $num, $this->count() ); |
500
|
|
|
} |
501
|
|
|
|
502
|
|
|
/** |
503
|
|
|
* {@inheritdoc} |
504
|
|
|
* |
505
|
|
|
* @param callable $condition Callback function. |
506
|
|
|
* |
507
|
|
|
* @return Collection |
508
|
|
|
*/ |
509
|
3 |
|
public function take_while( $condition ) { |
510
|
3 |
|
$count = $this->count_while_true( $condition ); |
511
|
|
|
|
512
|
3 |
|
return $count ? $this->take( $count ) : $this->clear(); |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
/** |
516
|
|
|
* {@inheritdoc} |
517
|
|
|
* |
518
|
|
|
* @param callable $callable Callback function. |
519
|
|
|
*/ |
520
|
3 |
|
public function each( $callable ) { |
521
|
3 |
|
foreach ( $this->elements as $element ) { |
522
|
3 |
|
call_user_func( $callable, $element ); |
523
|
2 |
|
} |
524
|
3 |
|
} |
525
|
|
|
|
526
|
|
|
/** |
527
|
|
|
* {@inheritdoc} |
528
|
|
|
* |
529
|
|
|
* @param callable $callable Callback function. |
530
|
|
|
* |
531
|
|
|
* @return Collection |
532
|
|
|
*/ |
533
|
18 |
|
public function map( $callable ) { |
534
|
18 |
|
$elements = array(); |
535
|
18 |
|
$type = null; |
536
|
18 |
|
foreach ( $this->elements as $element ) { |
537
|
15 |
|
$result = call_user_func( $callable, $element ); |
538
|
|
|
|
539
|
15 |
|
if ( null === $type ) { |
540
|
15 |
|
$type = gettype( $result ); |
541
|
|
|
|
542
|
15 |
|
if ( 'object' === $type ) { |
543
|
3 |
|
$type = get_class( $result ); |
544
|
2 |
|
} |
545
|
10 |
|
} |
546
|
|
|
|
547
|
15 |
|
$elements[] = $result; |
548
|
12 |
|
} |
549
|
|
|
|
550
|
18 |
|
return $this->new_from_trusted( $elements, $type ? : $this->get_type() ); |
551
|
|
|
} |
552
|
|
|
|
553
|
|
|
/** |
554
|
|
|
* {@inheritdoc} |
555
|
|
|
* |
556
|
|
|
* @param callable $callable Reducer function. |
557
|
|
|
* @param null $initial Initial value. |
558
|
|
|
* |
559
|
|
|
* @return mixed |
560
|
|
|
*/ |
561
|
15 |
|
public function reduce_right( $callable, $initial = null ) { |
562
|
15 |
|
return array_reduce( |
563
|
15 |
|
array_reverse( $this->elements ), |
564
|
10 |
|
$callable, |
565
|
|
|
$initial |
566
|
10 |
|
); |
567
|
|
|
} |
568
|
|
|
|
569
|
|
|
/** |
570
|
|
|
* {@inheritdoc} |
571
|
|
|
* |
572
|
|
|
* @return Collection |
573
|
|
|
*/ |
574
|
3 |
|
public function shuffle() { |
575
|
3 |
|
$elements = $this->elements; |
576
|
3 |
|
shuffle( $elements ); |
577
|
|
|
|
578
|
3 |
|
return $this->new_from_trusted( $elements ); |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
/** |
582
|
|
|
* {@inheritdoc} |
583
|
|
|
* |
584
|
|
|
* @param array|Collection $elements Array of elements to merge. |
585
|
|
|
* |
586
|
|
|
* @return Collection |
587
|
|
|
* |
588
|
|
|
* @throws InvalidArgumentException |
589
|
|
|
*/ |
590
|
12 |
View Code Duplication |
public function merge( $elements ) { |
|
|
|
|
591
|
12 |
|
if ( $elements instanceof static ) { |
592
|
3 |
|
$elements = $elements->to_array(); |
593
|
2 |
|
} |
594
|
|
|
|
595
|
12 |
|
if ( ! is_array( $elements ) ) { |
596
|
3 |
|
throw new InvalidArgumentException( 'Merge must be given array or Collection' ); |
597
|
|
|
} |
598
|
|
|
|
599
|
9 |
|
$this->type->validate_elements( $elements ); |
600
|
|
|
|
601
|
6 |
|
return $this->new_from_trusted( |
602
|
6 |
|
array_merge( $this->elements, $elements ) |
603
|
4 |
|
); |
604
|
|
|
} |
605
|
|
|
|
606
|
|
|
/** |
607
|
|
|
* {@inheritdoc} |
608
|
|
|
* |
609
|
|
|
* @return mixed |
610
|
|
|
* |
611
|
|
|
* @throws OutOfBoundsException |
612
|
|
|
*/ |
613
|
6 |
|
public function first() { |
614
|
6 |
|
if ( empty( $this->elements ) ) { |
615
|
3 |
|
throw new OutOfBoundsException( 'Cannot get first element of empty Collection' ); |
616
|
|
|
} |
617
|
|
|
|
618
|
3 |
|
return reset( $this->elements ); |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
/** |
622
|
|
|
* {@inheritdoc} |
623
|
|
|
* |
624
|
|
|
* @return mixed |
625
|
|
|
* |
626
|
|
|
* @throws OutOfBoundsException |
627
|
|
|
*/ |
628
|
6 |
|
public function last() { |
629
|
6 |
|
if ( empty( $this->elements ) ) { |
630
|
3 |
|
throw new OutOfBoundsException( 'Cannot get last element of empty Collection' ); |
631
|
|
|
} |
632
|
|
|
|
633
|
3 |
|
return end( $this->elements ); |
634
|
|
|
} |
635
|
|
|
|
636
|
|
|
/** |
637
|
|
|
* {@inheritdoc} |
638
|
|
|
* |
639
|
|
|
* @return int |
640
|
|
|
*/ |
641
|
168 |
|
public function count() { |
642
|
168 |
|
return count( $this->elements ); |
643
|
|
|
} |
644
|
|
|
|
645
|
|
|
/** |
646
|
|
|
* {@inheritDoc} |
647
|
|
|
* |
648
|
|
|
* @return array |
649
|
|
|
*/ |
650
|
|
|
public function serialize() { |
651
|
9 |
|
return $this->map(function( $element ) { |
652
|
6 |
|
if ( $element instanceof Serializes ) { |
653
|
3 |
|
return $element->serialize(); |
654
|
|
|
} |
655
|
|
|
|
656
|
3 |
|
return $element; |
657
|
9 |
|
} )->to_array(); |
658
|
|
|
} |
659
|
|
|
|
660
|
|
|
/** |
661
|
|
|
* Return the current element. |
662
|
|
|
* |
663
|
|
|
* @return mixed |
664
|
|
|
*/ |
665
|
3 |
|
public function current() { |
666
|
3 |
|
return $this->at( $this->position ); |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
/** |
670
|
|
|
* Move forward to next element. |
671
|
|
|
*/ |
672
|
3 |
|
public function next() { |
673
|
3 |
|
$this->position ++; |
674
|
3 |
|
} |
675
|
|
|
|
676
|
|
|
/** |
677
|
|
|
* Return the key of the current element. |
678
|
|
|
* |
679
|
|
|
* @return mixed |
680
|
|
|
*/ |
681
|
3 |
|
public function key() { |
682
|
3 |
|
return $this->position; |
683
|
|
|
} |
684
|
|
|
|
685
|
|
|
/** |
686
|
|
|
* Checks if current position is valid. |
687
|
|
|
* |
688
|
|
|
* @return bool |
689
|
|
|
*/ |
690
|
3 |
|
public function valid() { |
691
|
3 |
|
return isset( $this->elements[ $this->position ] ); |
692
|
|
|
} |
693
|
|
|
|
694
|
|
|
/** |
695
|
|
|
* Rewind the Iterator to the first element. |
696
|
|
|
*/ |
697
|
3 |
|
public function rewind() { |
698
|
3 |
|
$this->position = 0; |
699
|
3 |
|
} |
700
|
|
|
|
701
|
|
|
/** |
702
|
|
|
* Creates a new instance of the Collection |
703
|
|
|
* from a trusted set of elements. |
704
|
|
|
* |
705
|
|
|
* @param array $elements Array of elements to pass into new collection. |
706
|
|
|
* @param null|mixed $type |
707
|
|
|
* |
708
|
|
|
* @return static |
709
|
|
|
*/ |
710
|
108 |
|
protected function new_from_trusted( array $elements, $type = null ) { |
711
|
108 |
|
$collection = new static( null !== $type ? $type : $this->get_type() ); |
712
|
108 |
|
$collection->set_from_trusted( $elements ); |
713
|
|
|
|
714
|
108 |
|
return $collection; |
715
|
|
|
} |
716
|
|
|
|
717
|
|
|
/** |
718
|
|
|
* Sets the elements without validating them. |
719
|
|
|
* |
720
|
|
|
* @param array $elements Pre-validated elements to set. |
721
|
|
|
*/ |
722
|
153 |
|
protected function set_from_trusted( array $elements ) { |
723
|
153 |
|
$this->elements = $elements; |
724
|
153 |
|
} |
725
|
|
|
|
726
|
|
|
/** |
727
|
|
|
* Number of elements true for the condition. |
728
|
|
|
* |
729
|
|
|
* @param callable $condition Condition to check. |
730
|
|
|
* @return int |
731
|
|
|
*/ |
732
|
12 |
|
protected function count_while_true( $condition ) { |
733
|
12 |
|
$count = 0; |
734
|
|
|
|
735
|
12 |
|
foreach ( $this->elements as $element ) { |
736
|
12 |
|
if ( ! $condition($element) ) { |
737
|
9 |
|
break; |
738
|
|
|
} |
739
|
9 |
|
$count++; |
740
|
8 |
|
} |
741
|
|
|
|
742
|
12 |
|
return $count; |
743
|
|
|
} |
744
|
|
|
|
745
|
|
|
/** |
746
|
|
|
* Validates a number to be used as an index. |
747
|
|
|
* |
748
|
|
|
* @param integer $index The number to be validated as an index. |
749
|
|
|
* |
750
|
|
|
* @throws OutOfRangeException |
751
|
|
|
*/ |
752
|
102 |
|
protected function validate_index( $index ) { |
753
|
102 |
|
$exists = $this->index_exists( $index ); |
754
|
|
|
|
755
|
96 |
|
if ( ! $exists ) { |
756
|
6 |
|
throw new OutOfRangeException( 'Index out of bounds of collection' ); |
757
|
|
|
} |
758
|
93 |
|
} |
759
|
|
|
} |
760
|
|
|
|
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.