Completed
Push — master ( 5e4dda...9f6473 )
by Luke
09:18
created

Collection::filter()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 9
cts 9
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 3
nop 1
crap 3
1
<?php
2
namespace Noz\Collection;
3
4
use Countable;
5
use JsonSerializable;
6
use Iterator;
7
use ArrayAccess;
8
use RuntimeException;
9
10
/**
11
 * Nozavroni Collection
12
 */
13
class Collection implements ArrayAccess, Iterator, Countable, JsonSerializable
14
{
15
    /** @var array */
16
    protected $items;
17
18
    /**
19
     * Collection constructor.
20
     *
21
     * @param array $items
22
     */
23 35
    public function __construct(array $items = [])
24
    {
25 35
        $this->items = $items;
26 35
        $this->rewind();
27 35
    }
28
29
    /**
30
     * Generate a collection from an array of items.
31
     * I created this method so that it's possible to extend a collection more easily.
32
     *
33
     * @param array $items
34
     *
35
     * @return Collection
36
     */
37 10
    public static function factory(array $items = [])
38
    {
39 10
        return new Collection($items);
40
    }
41
42
    /**
43
     * Get collection as an array
44
     *
45
     * @return array
46
     */
47 13
    public function toArray()
48
    {
49 13
        return $this->items;
50
    }
51
52
    /**
53
     * Determine if collection has a given key
54
     *
55
     * @param mixed $key The key to look for
56
     *
57
     * @return bool
58
     */
59 21
    public function has($key)
60
    {
61 21
        return isset($this->items[$key]) || array_key_exists($key, $this->items);
62
    }
63
64
    /**
65
     * Does collection have item at position?
66
     *
67
     * Determine if collection has an item at a particular position (indexed from one).
68
     * Position can be positive and start from the beginning or it can be negative and
69
     * start from the end.
70
     *
71
     * @param int $position
72
     *
73
     * @return bool
74
     */
75 2
    public function hasValueAt($position)
76
    {
77
        try {
78 2
            $this->getKeyAt($position);
79 2
            return true;
80 2
        } catch (RuntimeException $e) {
81 2
            return false;
82
        }
83
    }
84
85
    /**
86
     * Get key at given position
87
     *
88
     * Returns the key at the given position, starting from one. Position can be positive (start from beginning) or
89
     * negative (start from the end).
90
     *
91
     * If the position does not exist, a RuntimeException is thrown.
92
     *
93
     * @param int $position
94
     *
95
     * @return string
96
     *
97
     * @throws RuntimeException
98
     */
99 6
    public function getKeyAt($position)
100
    {
101 6
        $collection = $this;
102 6
        if ($position < 0) {
103 3
            $collection = $this->reverse();
104 3
        }
105 6
        $i = 1;
106 6
        foreach ($collection as $key => $val) {
107 6
            if (abs($position) == $i++) {
108 5
                return $key;
109
            }
110 6
        }
111 3
        throw new RuntimeException("No key at position {$position}");
112
    }
113
114
    /**
115
     * Get value at given position
116
     *
117
     * Returns the value at the given position, starting from one. Position can be positive (start from beginning) or
118
     * negative (start from the end).
119
     *
120
     * If the position does not exist, a RuntimeException is thrown.
121
     *
122
     * @param int $position
123
     *
124
     * @return mixed
125
     *
126
     * @throws RuntimeException
127
     */
128 2
    public function getValueAt($position)
129
    {
130 2
        return $this->get($this->getKeyAt($position));
131
    }
132
133
    /**
134
     * Get item by key, with an optional default return value
135
     *
136
     * @param mixed $key
137
     * @param mixed $default
138
     *
139
     * @return mixed
140
     */
141 7
    public function get($key, $default = null)
142
    {
143 7
        if ($this->has($key)) {
144 7
            return $this->items[$key];
145
        }
146
147 3
        return $default;
148
    }
149
150
    /**
151
     * Add an item with no regard to key
152
     *
153
     * @param mixed $value
154
     *
155
     * @return $this
156
     */
157 3
    public function add($value)
158
    {
159 3
        $this->items[] = $value;
160
161 3
        return $this;
162
    }
163
164
    /**
165
     * Set an item at a given key
166
     *
167
     * @param mixed $key
168
     * @param mixed $value
169
     *
170
     * @return $this
171
     */
172 5
    public function set($key, $value)
173
    {
174 5
        $this->items[$key] = $value;
175
176 5
        return $this;
177
    }
178
179
    /**
180
     * Delete an item by key
181
     *
182
     * @param mixed $key
183
     *
184
     * @return $this
185
     */
186 3
    public function delete($key)
187
    {
188 3
        unset($this->items[$key]);
189
190 3
        return $this;
191
    }
192
193
    /**
194
     * Clear the collection of all its items.
195
     *
196
     * @return $this
197
     */
198 1
    public function clear()
199
    {
200 1
        $this->items = [];
201
202 1
        return $this;
203
    }
204
205
    /**
206
     * Determine if collection contains given value
207
     *
208
     * @param mixed $val
209
     *
210
     * @return bool
211
     */
212 2
    public function contains($val)
213
    {
214 2
        return in_array($val, $this->items, true);
215
    }
216
217
    /**
218
     * Fetch item from collection by key and remove it from collection
219
     *
220
     * @param mixed $key
221
     *
222
     * @return mixed
223
     */
224 1
    public function pull($key)
225
    {
226 1
        if ($this->has($key)) {
227 1
            $value = $this->get($key);
228 1
            $this->delete($key);
229 1
            return $value;
230
        }
231 1
    }
232
233
    /**
234
     * Join collection items using a delimiter
235
     *
236
     * @param string $delim
237
     *
238
     * @return string
239
     */
240 1
    public function join($delim = '')
241
    {
242 1
        return implode($delim, $this->items);
243
    }
244
245
    /**
246
     * Determine if collection has any items
247
     *
248
     * @return bool
249
     */
250 3
    public function isEmpty()
251
    {
252 3
        return $this->count() == 0;
253
    }
254
255
    /**
256
     * Get a collection of only this collection's values (without its keys)
257
     *
258
     * @return Collection
259
     */
260 1
    public function values()
261
    {
262 1
        return static::factory(array_values($this->items));
263
    }
264
265
    /**
266
     * Get a collection of only this collection's keys
267
     *
268
     * @return Collection
269
     */
270 1
    public function keys()
271
    {
272 1
        return static::factory(array_keys($this->items));
273
    }
274
275
    /**
276
     * Get a collection with order reversed
277
     *
278
     * @return Collection
279
     */
280 3
    public function reverse()
281
    {
282 3
        return static::factory(array_reverse($this->items));
283
    }
284
285
    /**
286
     * Get a collection with keys and values flipped
287
     *
288
     * @return Collection
289
     */
290 1
    public function flip()
291
    {
292 1
        $collection = static::factory();
293 1
        foreach ($this as $key => $val) {
294 1
            $collection->set($val, $key);
295 1
        }
296 1
        return $collection;
297
    }
298
299
    /**
300
     * Shuffle the order of this collection's values
301
     *
302
     * @return Collection
303
     */
304 1
    public function shuffle()
305
    {
306 1
        shuffle($this->items);
307 1
        return $this;
308
    }
309
310
    /**
311
     * Get a random value from the collection
312
     *
313
     * @return mixed
314
     */
315 1
    public function random()
316
    {
317 1
        return $this->getValueAt(rand(1, $this->count()));
318
    }
319
320
    /**
321
     * Sort the collection
322
     *
323
     * @param mixed $algo
324
     *
325
     * @return Collection
326
     */
327
    public function sort($algo = null)
0 ignored issues
show
Unused Code introduced by
The parameter $algo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
328
    {
329
330
    }
331
332
    /**
333
     * Get a new collection with only distinct values
334
     *
335
     * @return Collection
336
     */
337 1
    public function distinct()
338
    {
339 1
        $collection = static::factory();
340 1
        foreach ($this as $key => $val) {
341 1
            if (!$collection->contains($val)) {
342 1
                $collection->set($key, $val);
343 1
            }
344 1
        }
345 1
        return $collection;
346
    }
347
348
    /**
349
     * Remove all duplicate values from collection in-place
350
     *
351
     * @return Collection
352
     */
353 1
    public function deduplicate()
354
    {
355 1
        $this->items = array_unique($this->items);
356
357 1
        return $this;
358
    }
359
360
    /**
361
     * Return a new collection with only filtered keys/values
362
     *
363
     * The callback accepts value, key, index and should return true if the item should be added to the returned
364
     * collection
365
     *
366
     * @param callable $callback
367
     *
368
     * @return Collection
369
     */
370 1
    public function filter(callable $callback)
371
    {
372 1
        $collection = static::factory();
373 1
        $index = 0;
374 1
        foreach ($this as $key => $value) {
375 1
            if ($callback($value, $key, $index++)) {
376 1
                $collection->set($key, $value);
377 1
            }
378 1
        }
379
380 1
        return $collection;
381
    }
382
383 1
    public function fold($callback, $initial = null)
384
    {
385 1
        $index = 0;
386 1
        $folded = $initial;
387 1
        foreach ($this as $key => $val) {
388 1
            $folded = $callback($folded, $val, $key, $index++);
389 1
        }
390 1
        return $folded;
391
    }
392
393
    /** ++++                  ++++ **/
394
    /** ++ Interface Compliance ++ **/
395
    /** ++++                  ++++ **/
396
397
    /**
398
     * @return array
399
     */
400 1
    public function jsonSerialize()
401
    {
402 1
        return $this->toArray();
403
    }
404
405
    /** ++++                  ++++ **/
406
    /** ++ Array Access Methods ++ **/
407
    /** ++++                  ++++ **/
408
409
    /**
410
     * {@inheritDoc}
411
     */
412 1
    public function offsetExists($offset)
413
    {
414 1
        return $this->has($offset);
415
    }
416
417
    /**
418
     * {@inheritDoc}
419
     */
420 2
    public function offsetGet($offset)
421
    {
422 2
        if (!$this->has($offset)) {
423 1
            throw new RuntimeException("Unknown offset: {$offset}");
424
        }
425
426 1
        return $this->get($offset);
427
    }
428
429
    /**
430
     * {@inheritDoc}
431
     */
432 1
    public function offsetUnset($offset)
433
    {
434 1
        $this->delete($offset);
435 1
    }
436
437
    /**
438
     * {@inheritDoc}
439
     */
440 1
    public function offsetSet($offset, $value)
441
    {
442 1
        if (!isset($offset)) {
443 1
            $this->add($value);
444 1
        }
445
446 1
        $this->set($offset, $value);
447 1
    }
448
449
    /** ++++                  ++++ **/
450
    /** ++   Iterator Methods   ++ **/
451
    /** ++++                  ++++ **/
452
453
    /**
454
     * {@inheritDoc}
455
     */
456 11
    public function current()
457
    {
458 11
        return current($this->items);
459
    }
460
461
    /**
462
     * {@inheritDoc}
463
     */
464 11
    public function key()
465
    {
466 11
        return key($this->items);
467
    }
468
469
    /**
470
     * {@inheritDoc}
471
     */
472 11
    public function next()
473
    {
474 11
        return next($this->items);
475
    }
476
477
    /**
478
     * {@inheritDoc}
479
     */
480 35
    public function rewind()
481
    {
482 35
        reset($this->items);
483 35
    }
484
485
    /**
486
     * {@inheritDoc}
487
     */
488 11
    public function valid()
489
    {
490 11
        return $this->has(key($this->items));
491
    }
492
493
    /** ++++                  ++++ **/
494
    /** ++   Countable Method   ++ **/
495
    /** ++++                  ++++ **/
496
497
    /**
498
     * {@inheritDoc}
499
     */
500 5
    public function count()
501
    {
502 5
        return count($this->items);
503
    }
504
}