Skip to content

Commit cb1fe18

Browse files
author
Bl00D4NGEL
committed
feat: add every, none and some functions to collection
1 parent 1f7d851 commit cb1fe18

File tree

2 files changed

+181
-0
lines changed

2 files changed

+181
-0
lines changed

src/Domain/Collection.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ final public function __construct(
3535
* @param iterable<T> $items
3636
* @param class-string<T>|null $itemType
3737
* @return self<T>
38+
* @throws Assert\AssertionFailedException
3839
*/
3940
public static function fromIterable(iterable $items, ?string $itemType = null): static
4041
{
@@ -49,6 +50,75 @@ public static function fromIterable(iterable $items, ?string $itemType = null):
4950
return new static(iterator_to_array($items), $itemType);
5051
}
5152

53+
/**
54+
* Returns true if every value in the collection passes the callback truthy test. Opposite of self::none().
55+
* Callback arguments will be element, index, collection.
56+
* Function short-circuits on first falsy return value
57+
*
58+
* @param ?callable(T, int, static): bool $callback
59+
* @return bool
60+
*/
61+
public function every(callable $callback = null): bool
62+
{
63+
if ($callback === null) {
64+
$callback = static fn ($item, $index, $self) => $item;
65+
}
66+
67+
foreach ($this->items as $index => $item) {
68+
if (!$callback($item, $index, $this)) {
69+
return false;
70+
}
71+
}
72+
73+
return true;
74+
}
75+
76+
/**
77+
* Returns true if every value in the collection passes the callback falsy test. Opposite of self::every().
78+
* Callback arguments will be element, index, collection.
79+
* Function short-circuits on first truthy return value
80+
*
81+
* @param ?callable(T, int, static): bool $callback
82+
* @return bool
83+
*/
84+
public function none(callable $callback = null): bool
85+
{
86+
if ($callback === null) {
87+
$callback = static fn ($item, $index, $self) => $item;
88+
}
89+
90+
foreach ($this->items as $index => $item) {
91+
if ($callback($item, $index, $this)) {
92+
return false;
93+
}
94+
}
95+
96+
return true;
97+
}
98+
99+
/**
100+
* Returns true if at least one value in the collection passes the callback truthy test.
101+
* Callback arguments will be element, index, collection.
102+
* Function short-circuits on first truthy return value
103+
*
104+
* @param ?callable(T, int, static): bool $callback
105+
* @return bool
106+
*/
107+
public function some(callable $callback = null): bool
108+
{
109+
if ($callback === null) {
110+
$callback = static fn ($item, $index, $self) => $item;
111+
}
112+
113+
foreach ($this->items as $index => $item) {
114+
if ($callback($item, $index, $this)) {
115+
return true;
116+
}
117+
}
118+
119+
return false;
120+
}
121+
52122
/**
53123
* Add one or more items to the collection. It **does not** modify the
54124
* current collection, but returns a new one.

tests/Domain/CollectionTest.php

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,4 +320,115 @@ public function testFromIterable(): void
320320
$collectionFromGenerator = Collection::fromIterable($generatorFn());
321321
$this->assertSame($items, iterator_to_array($collectionFromGenerator));
322322
}
323+
324+
public function testEvery(): void
325+
{
326+
$items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
327+
$collection = new Collection($items);
328+
329+
$this->assertFalse($collection->every(static fn ($item) => $item > 10));
330+
$this->assertFalse($collection->every(static fn ($item) => $item > 5));
331+
$this->assertTrue($collection->every(static fn ($item) => $item > 0));
332+
}
333+
334+
public function testEveryWithoutArgumentDefaultsToTruthyCheck(): void
335+
{
336+
$this->assertTrue((new Collection([1, true]))->every());
337+
$this->assertTrue((new Collection([1, true]))->every());
338+
$this->assertFalse((new Collection([null, false]))->every());
339+
$this->assertFalse((new Collection([false, null]))->every());
340+
$this->assertFalse((new Collection([0, false]))->every());
341+
}
342+
343+
public function testEveryReturnsTrueOnEmptyCollection(): void
344+
{
345+
$this->assertTrue((new Collection())->every(static fn ($item) => false));
346+
}
347+
348+
public function testEveryShortCircuitsOnFirstFalsyValue(): void
349+
{
350+
$items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
351+
$collection = new Collection($items);
352+
353+
$collection->every(function ($item, $index, $c) use ($collection): bool {
354+
// First item already returns false therefore the index should never be something other than 0
355+
$this->assertSame(0, $index);
356+
$this->assertSame($c, $collection);
357+
return false;
358+
});
359+
}
360+
361+
public function testNone(): void
362+
{
363+
$items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
364+
$collection = new Collection($items);
365+
366+
$this->assertTrue($collection->none(static fn ($item) => $item > 10));
367+
$this->assertFalse($collection->none(static fn ($item) => $item > 5));
368+
$this->assertFalse($collection->none(static fn ($item) => $item > 0));
369+
}
370+
371+
public function testNoneWithoutArgumentDefaultsToTruthyCheck(): void
372+
{
373+
$this->assertFalse((new Collection([1, true]))->none());
374+
$this->assertFalse((new Collection([1, true]))->none());
375+
$this->assertTrue((new Collection([null, false]))->none());
376+
$this->assertTrue((new Collection([false, null]))->none());
377+
$this->assertTrue((new Collection([0, false]))->none());
378+
}
379+
380+
public function testNoneReturnsFalseOnEmptyCollection(): void
381+
{
382+
$this->assertTrue((new Collection())->none(static fn ($item) => true));
383+
}
384+
385+
public function testNoneShortCircuitsOnFirstFalsyValue(): void
386+
{
387+
$items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
388+
$collection = new Collection($items);
389+
390+
$collection->none(function ($item, $index, $c) use ($collection): bool {
391+
// First item already returns true therefore the index should never be something other than 0
392+
$this->assertSame(0, $index);
393+
$this->assertSame($c, $collection);
394+
return true;
395+
});
396+
}
397+
398+
public function testSome(): void
399+
{
400+
$items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
401+
$collection = new Collection($items);
402+
403+
$this->assertFalse($collection->some(static fn ($item) => $item > 10));
404+
$this->assertTrue($collection->some(static fn ($item) => $item > 5));
405+
$this->assertTrue($collection->some(static fn ($item) => $item > 0));
406+
}
407+
408+
public function testSomeWithoutArgumentDefaultsToTruthyCheck(): void
409+
{
410+
$this->assertTrue((new Collection([1, true]))->some());
411+
$this->assertTrue((new Collection([1, true]))->some());
412+
$this->assertFalse((new Collection([null, false]))->some());
413+
$this->assertFalse((new Collection([false, null]))->some());
414+
$this->assertFalse((new Collection([0, false]))->some());
415+
}
416+
417+
public function testSomeReturnsFalseOnEmptyCollection(): void
418+
{
419+
$this->assertFalse((new Collection())->some(static fn ($item) => true));
420+
}
421+
422+
public function testSomeShortCircuitsOnFirstFalsyValue(): void
423+
{
424+
$items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
425+
$collection = new Collection($items);
426+
427+
$collection->some(function ($item, $index, $c) use ($collection): bool {
428+
// First item already returns true therefore the index should never be something other than 0
429+
$this->assertSame(0, $index);
430+
$this->assertSame($c, $collection);
431+
return true;
432+
});
433+
}
323434
}

0 commit comments

Comments
 (0)