From 054789ce607b0e1e30142748c00007cb8b7cb8d0 Mon Sep 17 00:00:00 2001 From: Ryuta Hamasaki Date: Sat, 8 Jun 2024 15:55:31 +0900 Subject: [PATCH 01/10] add before method to Collection --- src/Illuminate/Collections/Collection.php | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 995ea2ac2429..0fac54d5bce1 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1113,6 +1113,34 @@ public function search($value, $strict = false) return false; } + /** + * Get the item before the given item. + * + * @param TValue|(callable(TValue,TKey): bool) $value + * @param bool $strict + * @return TValue|null + */ + public function before($value, $strict = false) + { + // $key can be an array index or an associative array key which is a string. + $key = $this->search($value, $strict); + + if ($key === false) { + return null; + } + + // Find the key position to cater for the case when the collection is an associative array. + $position = $this->keys()->search($key); + + if ($position === false || $position === 0) { + return null; + } + + $previousKey = $this->keys()->get($position - 1); + + return $this->get($previousKey); + } + /** * Get and remove the first N items from the collection. * From 63d1f562e5628b9e5a289001760a97ec794409b9 Mon Sep 17 00:00:00 2001 From: Ryuta Hamasaki Date: Sat, 8 Jun 2024 16:21:02 +0900 Subject: [PATCH 02/10] add tests for before method --- tests/Support/SupportCollectionTest.php | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 01de6e32904d..4c05beea260b 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -3702,6 +3702,64 @@ public function testSearchReturnsFalseWhenItemIsNotFound($collection) })); } + #[DataProvider('collectionClassProvider')] + public function testBeforeReturnsItemBeforeTheGivenItem($collection) + { + $c = new $collection([1, 2, 3, 4, 5, 2, 5, 'foo' => 'bar']); + + $this->assertEquals(1, $c->before(2)); + $this->assertEquals(1, $c->before('2')); + $this->assertSame(5, $c->before('bar')); + $this->assertEquals(4, $c->before(function ($value) { + return $value > 4; + })); + $this->assertSame(5, $c->before(function ($value) { + return ! is_numeric($value); + })); + } + + #[DataProvider('collectionClassProvider')] + public function testBeforeInStrictMode($collection) + { + $c = new $collection([false, 0, 1, [], '']); + $this->assertNull($c->before('false', true)); + $this->assertNull($c->before('1', true)); + $this->assertNull($c->before(false, true)); + $this->assertEquals(false, $c->before(0, true)); + $this->assertEquals(0, $c->before(1, true)); + $this->assertEquals(1, $c->before([], true)); + $this->assertEquals([], $c->before('', true)); + } + + #[DataProvider('collectionClassProvider')] + public function testBeforeReturnsNullWhenItemIsNotFound($collection) + { + $c = new $collection([1, 2, 3, 4, 5, 'foo' => 'bar']); + + $this->assertNull($c->before(6)); + $this->assertNull($c->before('foo')); + $this->assertNull($c->before(function ($value) { + return $value < 1 && is_numeric($value); + })); + $this->assertNull($c->before(function ($value) { + return $value === 'nope'; + })); + } + + #[DataProvider('collectionClassProvider')] + public function testBeforeReturnsNullWhenItemOnTheFirstitem($collection) + { + $c = new $collection([1, 2, 3, 4, 5, 'foo' => 'bar']); + + $this->assertNull($c->before(1)); + $this->assertNull($c->before(function ($value) { + return $value < 2 && is_numeric($value); + })); + + $c = new $collection(['foo' => 'bar', 1, 2, 3, 4, 5]); + $this->assertNull($c->before('foo')); + } + #[DataProvider('collectionClassProvider')] public function testKeys($collection) { From a7334c1065e284d2246163cc3eb22d6ef43470c6 Mon Sep 17 00:00:00 2001 From: Ryuta Hamasaki Date: Mon, 10 Jun 2024 09:57:31 +0900 Subject: [PATCH 03/10] add before method to Enumerable interface --- src/Illuminate/Collections/Enumerable.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index f52b67e7e9d7..de32beab9bbf 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -889,6 +889,15 @@ public function reverse(); */ public function search($value, $strict = false); + /** + * Get the item before the given item. + * + * @param TValue|(callable(TValue,TKey): bool) $value + * @param bool $strict + * @return TValue|null + */ + public function before($value, $strict = false); + /** * Shuffle the items in the collection. * From 4d5506319a9d8690cd4173a585ee5678bfadc4bb Mon Sep 17 00:00:00 2001 From: Ryuta Hamasaki Date: Mon, 10 Jun 2024 10:43:56 +0900 Subject: [PATCH 04/10] add before method to LazyCollection --- src/Illuminate/Collections/LazyCollection.php | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 8aea9e1ee29e..6df3a899c67f 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1082,6 +1082,35 @@ public function search($value, $strict = false) return false; } + /** + * Get the item before the given item. + * + * @param TValue|(callable(TValue,TKey): bool) $value + * @param bool $strict + * @return TValue|null + */ + public function before($value, $strict = false) + { + $previous = null; + + /** @var (callable(TValue,TKey): bool) $predicate */ + $predicate = $this->useAsCallable($value) + ? $value + : function ($item) use ($value, $strict) { + return $strict ? $item === $value : $item == $value; + }; + + foreach ($this as $key => $item) { + if ($predicate($item, $key)) { + return $previous; + } + + $previous = $item; + } + + return null; + } + /** * Shuffle the items in the collection. * From 645e03122f39c900827bb2c552ade63b0fe23737 Mon Sep 17 00:00:00 2001 From: Ryuta Hamasaki Date: Mon, 10 Jun 2024 10:44:13 +0900 Subject: [PATCH 05/10] update tests --- tests/Support/SupportCollectionTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 4c05beea260b..494d6073fc1c 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -3705,11 +3705,12 @@ public function testSearchReturnsFalseWhenItemIsNotFound($collection) #[DataProvider('collectionClassProvider')] public function testBeforeReturnsItemBeforeTheGivenItem($collection) { - $c = new $collection([1, 2, 3, 4, 5, 2, 5, 'foo' => 'bar']); + $c = new $collection([1, 2, 3, 4, 5, 2, 5, 'name' => 'taylor', 'framework' => 'laravel']); $this->assertEquals(1, $c->before(2)); $this->assertEquals(1, $c->before('2')); - $this->assertSame(5, $c->before('bar')); + $this->assertSame(5, $c->before('taylor')); + $this->assertSame('taylor', $c->before('laravel')); $this->assertEquals(4, $c->before(function ($value) { return $value > 4; })); @@ -3757,7 +3758,7 @@ public function testBeforeReturnsNullWhenItemOnTheFirstitem($collection) })); $c = new $collection(['foo' => 'bar', 1, 2, 3, 4, 5]); - $this->assertNull($c->before('foo')); + $this->assertNull($c->before('bar')); } #[DataProvider('collectionClassProvider')] From cf356be653ca02dbaac5b89889be4d93b4932340 Mon Sep 17 00:00:00 2001 From: Ryuta Hamasaki Date: Mon, 10 Jun 2024 11:43:17 +0900 Subject: [PATCH 06/10] add "after" method to collection --- src/Illuminate/Collections/Collection.php | 28 ++++++++++++++++- src/Illuminate/Collections/Enumerable.php | 9 ++++++ src/Illuminate/Collections/LazyCollection.php | 31 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 0fac54d5bce1..e15d3c0d6790 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1122,7 +1122,6 @@ public function search($value, $strict = false) */ public function before($value, $strict = false) { - // $key can be an array index or an associative array key which is a string. $key = $this->search($value, $strict); if ($key === false) { @@ -1141,6 +1140,33 @@ public function before($value, $strict = false) return $this->get($previousKey); } + /** + * Get the item after the given item. + * + * @param TValue|(callable(TValue,TKey): bool) $value + * @param bool $strict + * @return TValue|null + */ + public function after($value, $strict = false) + { + $key = $this->search($value, $strict); + + if ($key === false) { + return null; + } + + // Find the key position to cater for the case when the collection is an associative array. + $position = $this->keys()->search($key); + + if ($position === false || $position === $this->keys()->count() - 1) { + return null; + } + + $nextKey = $this->keys()->get($position + 1); + + return $this->get($nextKey); + } + /** * Get and remove the first N items from the collection. * diff --git a/src/Illuminate/Collections/Enumerable.php b/src/Illuminate/Collections/Enumerable.php index de32beab9bbf..eaef19990dad 100644 --- a/src/Illuminate/Collections/Enumerable.php +++ b/src/Illuminate/Collections/Enumerable.php @@ -898,6 +898,15 @@ public function search($value, $strict = false); */ public function before($value, $strict = false); + /** + * Get the item after the given item. + * + * @param TValue|(callable(TValue,TKey): bool) $value + * @param bool $strict + * @return TValue|null + */ + public function after($value, $strict = false); + /** * Shuffle the items in the collection. * diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 6df3a899c67f..5b674df1ad53 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1111,6 +1111,37 @@ public function before($value, $strict = false) return null; } + /** + * Get the item after the given item. + * + * @param TValue|(callable(TValue,TKey): bool) $value + * @param bool $strict + * @return TValue|null + */ + public function after($value, $strict = false) + { + $found = false; + + /** @var (callable(TValue,TKey): bool) $predicate */ + $predicate = $this->useAsCallable($value) + ? $value + : function ($item) use ($value, $strict) { + return $strict ? $item === $value : $item == $value; + }; + + foreach ($this as $key => $item) { + if ($found) { + return $item; + } + + if ($predicate($item, $key)) { + $found = true; + } + } + + return null; + } + /** * Shuffle the items in the collection. * From 2f41114eea7fc5e3e4175a978d18685bb638d3b6 Mon Sep 17 00:00:00 2001 From: Ryuta Hamasaki Date: Mon, 10 Jun 2024 11:53:26 +0900 Subject: [PATCH 07/10] add tests for after method --- tests/Support/SupportCollectionTest.php | 66 ++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 494d6073fc1c..063f3421ea9d 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -3709,12 +3709,12 @@ public function testBeforeReturnsItemBeforeTheGivenItem($collection) $this->assertEquals(1, $c->before(2)); $this->assertEquals(1, $c->before('2')); - $this->assertSame(5, $c->before('taylor')); + $this->assertEquals(5, $c->before('taylor')); $this->assertSame('taylor', $c->before('laravel')); $this->assertEquals(4, $c->before(function ($value) { return $value > 4; })); - $this->assertSame(5, $c->before(function ($value) { + $this->assertEquals(5, $c->before(function ($value) { return ! is_numeric($value); })); } @@ -3761,6 +3761,68 @@ public function testBeforeReturnsNullWhenItemOnTheFirstitem($collection) $this->assertNull($c->before('bar')); } + #[DataProvider('collectionClassProvider')] + public function testAfterReturnsItemAfterTheGivenItem($collection) + { + $c = new $collection([1, 2, 3, 4, 2, 5, 'name' => 'taylor', 'framework' => 'laravel']); + + $this->assertEquals(2, $c->after(1)); + $this->assertEquals(3, $c->after(2)); + $this->assertEquals(4, $c->after(3)); + $this->assertEquals(2, $c->after(4)); + $this->assertEquals('taylor', $c->after(5)); + $this->assertEquals('laravel', $c->after('taylor')); + + $this->assertEquals(4, $c->after(function ($value) { + return $value > 2; + })); + $this->assertEquals('laravel', $c->after(function ($value) { + return ! is_numeric($value); + })); + } + + #[DataProvider('collectionClassProvider')] + public function testAfterInStrictMode($collection) + { + $c = new $collection([false, 0, 1, [], '']); + + $this->assertNull($c->after('false', true)); + $this->assertNull($c->after('1', true)); + $this->assertNull($c->after('', true)); + $this->assertEquals(0, $c->after(false, true)); + $this->assertEquals([], $c->after(1, true)); + $this->assertEquals('', $c->after([], true)); + } + + #[DataProvider('collectionClassProvider')] + public function testAfterReturnsNullWhenItemIsNotFound($collection) + { + $c = new $collection([1, 2, 3, 4, 5, 'foo' => 'bar']); + + $this->assertNull($c->after(6)); + $this->assertNull($c->after('foo')); + $this->assertNull($c->after(function ($value) { + return $value < 1 && is_numeric($value); + })); + $this->assertNull($c->after(function ($value) { + return $value === 'nope'; + })); + } + + #[DataProvider('collectionClassProvider')] + public function testAfterReturnsNullWhenItemOnTheLastItem($collection) + { + $c = new $collection([1, 2, 3, 4, 5, 'foo' => 'bar']); + + $this->assertNull($c->after('bar')); + $this->assertNull($c->after(function ($value) { + return $value > 4 && !is_numeric($value); + })); + + $c = new $collection(['foo' => 'bar', 1, 2, 3, 4, 5]); + $this->assertNull($c->after(5)); + } + #[DataProvider('collectionClassProvider')] public function testKeys($collection) { From bb8937f3317b224b772b62484908ef0d97b57dc7 Mon Sep 17 00:00:00 2001 From: Ryuta Hamasaki Date: Mon, 10 Jun 2024 13:11:22 +0900 Subject: [PATCH 08/10] remove unnecessary condition --- src/Illuminate/Collections/Collection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index e15d3c0d6790..4192d8210cf7 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1131,7 +1131,7 @@ public function before($value, $strict = false) // Find the key position to cater for the case when the collection is an associative array. $position = $this->keys()->search($key); - if ($position === false || $position === 0) { + if ($position === 0) { return null; } @@ -1158,7 +1158,7 @@ public function after($value, $strict = false) // Find the key position to cater for the case when the collection is an associative array. $position = $this->keys()->search($key); - if ($position === false || $position === $this->keys()->count() - 1) { + if ($position === $this->keys()->count() - 1) { return null; } From b743f54bc53507ca0511359fced6ebee8d466c50 Mon Sep 17 00:00:00 2001 From: Ryuta Hamasaki Date: Mon, 10 Jun 2024 14:51:21 +0900 Subject: [PATCH 09/10] fix coding style --- src/Illuminate/Collections/LazyCollection.php | 8 ++++---- tests/Support/SupportCollectionTest.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php index 5b674df1ad53..958daf8a7508 100644 --- a/src/Illuminate/Collections/LazyCollection.php +++ b/src/Illuminate/Collections/LazyCollection.php @@ -1085,8 +1085,8 @@ public function search($value, $strict = false) /** * Get the item before the given item. * - * @param TValue|(callable(TValue,TKey): bool) $value - * @param bool $strict + * @param TValue|(callable(TValue,TKey): bool) $value + * @param bool $strict * @return TValue|null */ public function before($value, $strict = false) @@ -1114,8 +1114,8 @@ public function before($value, $strict = false) /** * Get the item after the given item. * - * @param TValue|(callable(TValue,TKey): bool) $value - * @param bool $strict + * @param TValue|(callable(TValue,TKey): bool) $value + * @param bool $strict * @return TValue|null */ public function after($value, $strict = false) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 063f3421ea9d..0b1a0f6fcb67 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -3816,7 +3816,7 @@ public function testAfterReturnsNullWhenItemOnTheLastItem($collection) $this->assertNull($c->after('bar')); $this->assertNull($c->after(function ($value) { - return $value > 4 && !is_numeric($value); + return $value > 4 && ! is_numeric($value); })); $c = new $collection(['foo' => 'bar', 1, 2, 3, 4, 5]); From 44ec589bb345c579bdcb563c7ba0cea220aecd06 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 11 Jun 2024 08:26:29 -0500 Subject: [PATCH 10/10] Update Collection.php --- src/Illuminate/Collections/Collection.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php index 4192d8210cf7..ee48d37daff0 100644 --- a/src/Illuminate/Collections/Collection.php +++ b/src/Illuminate/Collections/Collection.php @@ -1128,16 +1128,13 @@ public function before($value, $strict = false) return null; } - // Find the key position to cater for the case when the collection is an associative array. $position = $this->keys()->search($key); if ($position === 0) { return null; } - $previousKey = $this->keys()->get($position - 1); - - return $this->get($previousKey); + return $this->get($this->keys()->get($position - 1)); } /** @@ -1155,16 +1152,13 @@ public function after($value, $strict = false) return null; } - // Find the key position to cater for the case when the collection is an associative array. $position = $this->keys()->search($key); if ($position === $this->keys()->count() - 1) { return null; } - $nextKey = $this->keys()->get($position + 1); - - return $this->get($nextKey); + return $this->get($this->keys()->get($position + 1)); } /**