diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php index 129921d7f1c7..50823ba6481a 100644 --- a/src/Illuminate/Collections/Traits/EnumeratesValues.php +++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php @@ -319,6 +319,33 @@ public function firstWhere($key, $operator = null, $value = null) return $this->first($this->operatorForWhere(...func_get_args())); } + /** + * Returns the first value that is not null from the given callback. + * + * @template TCallbackValue + * @template TValueDefault + * + * @param callable(TValue, TKey): TCallbackValue|null $callback + * @param TValueDefault|(\Closure(): TValueDefault) $default + * @return TCallbackValue|TValueDefault + */ + public function firstValue($callback, $default = null) + { + $value = null; + + $this->each(function ($item, $key) use (&$value, $callback) { + $result = $callback($item, $key); + + if (! is_null($result)) { + $value = $result; + + return false; + } + }); + + return $value ?? value($default); + } + /** * Get a single key's value from the first matching item in the collection. * diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 0e246dc8f3d5..50d7887e7e11 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -73,6 +73,58 @@ public function testFirstWithDefaultAndWithoutCallback($collection) $this->assertSame('foo', $result); } + #[DataProvider('collectionClassProvider')] + public function testFirstValueReturnsValue($collection) + { + $data = new $collection([ + ['index' => 1, 'value' => 'foo'], + ['index' => 2, 'value' => 'bar'], + ['index' => 3, 'value' => 'baz'], + ]); + + $result = $data->firstValue(function ($item) { + if ($item['index'] === 3) { + return $item['value']; + } + }); + + $this->assertSame('baz', $result); + + $result = $data->firstValue(function ($item) { + if ($item['index'] === 4) { + return $item['value']; + } + }); + + $this->assertNull($result); + } + + #[DataProvider('collectionClassProvider')] + public function testFirstValueWithDefaultReturnsValue($collection) + { + $data = new $collection([ + ['index' => 1, 'value' => 'foo'], + ['index' => 2, 'value' => 'bar'], + ['index' => 3, 'value' => 'baz'], + ]); + + $result = $data->firstValue(function ($item) { + if ($item['index'] === 3) { + return $item['value']; + } + }, 'default'); + + $this->assertSame('baz', $result); + + $result = $data->firstValue(function ($item) { + if ($item['index'] === 4) { + return $item['value']; + } + }, 'default'); + + $this->assertSame('default', $result); + } + #[DataProvider('collectionClassProvider')] public function testSoleReturnsFirstItemInCollectionIfOnlyOneExists($collection) {