Repository: laravel/framework (php)

Issue:
After LazyCollection calls the unique method and then calls the isEmpty method, a piece of data will be lost.
<!-- DO NOT THROW THIS AWAY -->
<!-- Fill out the FULL versions with patch versions -->

- Laravel Version: 6.20.34
- PHP Version: 7.4.2
- Database Driver & Version:
mysql 5.7.34-log

### Description:
After LazyCollection calls the unique method and then calls the isEmpty method, a piece of data will be lost.

### Steps To Reproduce:

<!-- If possible, please provide a GitHub repository to demonstrate your issue -->
<!-- laravel new bug-report --github="--public" -->
```php
// The offending code snippet:
$items = \Illuminate\Support\LazyCollection::make(fn () => yield from [['id' => '1'], ['id' => '2'], ['id' => '4']]);
dump($items->toArray()); // Output: [['id' => '1'], ['id' => '2'], ['id' => '4']]
$unique_items = $items->unique('id');
// If the output is here, there is no problem, but `LazyCollection::isEmpty()` will return true.
// dump($unique_items->toArray()); // Output: [['id' => '1'], ['id' => '2'], ['id' => '4']]
if (!$unique_items->isEmpty()) {
    // When I judge whether it is a null value, I lost a value.
    dump($unique_items->toArray()); // Output: [['id' => '2'], ['id' => '4']]
}

// Everything is normal for this part of the code.
$items = \Illuminate\Support\Collection::make([['id' => '1'], ['id' => '2'], ['id' => '4']]);
dump($items->toArray());
$items = $items->unique('id');
if (!$items ->isEmpty()) {
    dump($items ->toArray());
}
```

Pull request:
[8.x] Fix LazyCollection#unique() double enumeration
Fixes #38817

Patch:
diff --git a/src/Illuminate/Collections/Collection.php b/src/Illuminate/Collections/Collection.php
index fae1dcf856..6884de8d8a 100644
--- a/src/Illuminate/Collections/Collection.php
+++ b/src/Illuminate/Collections/Collection.php
@@ -1411,6 +1411,28 @@ public function transform(callable $callback)
         return $this;
     }
 
+    /**
+     * Return only unique items from the collection array.
+     *
+     * @param  string|callable|null  $key
+     * @param  bool  $strict
+     * @return static
+     */
+    public function unique($key = null, $strict = false)
+    {
+        $callback = $this->valueRetriever($key);
+
+        $exists = [];
+
+        return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {
+            if (in_array($id = $callback($item, $key), $exists, $strict)) {
+                return true;
+            }
+
+            $exists[] = $id;
+        });
+    }
+
     /**
      * Reset the keys on the underlying array.
      *
diff --git a/src/Illuminate/Collections/LazyCollection.php b/src/Illuminate/Collections/LazyCollection.php
index 09f6114fb9..9250518d7a 100644
--- a/src/Illuminate/Collections/LazyCollection.php
+++ b/src/Illuminate/Collections/LazyCollection.php
@@ -1352,6 +1352,30 @@ public function tapEach(callable $callback)
         });
     }
 
+    /**
+     * Return only unique items from the collection array.
+     *
+     * @param  string|callable|null  $key
+     * @param  bool  $strict
+     * @return static
+     */
+    public function unique($key = null, $strict = false)
+    {
+        $callback = $this->valueRetriever($key);
+
+        return new static(function () use ($callback, $strict) {
+            $exists = [];
+
+            foreach ($this as $key => $item) {
+                if (! in_array($id = $callback($item, $key), $exists, $strict)) {
+                    yield $key => $item;
+
+                    $exists[] = $id;
+                }
+            }
+        });
+    }
+
     /**
      * Reset the keys on the underlying array.
      *
diff --git a/src/Illuminate/Collections/Traits/EnumeratesValues.php b/src/Illuminate/Collections/Traits/EnumeratesValues.php
index 19f32a322e..db53543d44 100644
--- a/src/Illuminate/Collections/Traits/EnumeratesValues.php
+++ b/src/Illuminate/Collections/Traits/EnumeratesValues.php
@@ -773,28 +773,6 @@ public function reject($callback = true)
         });
     }
 
-    /**
-     * Return only unique items from the collection array.
-     *
-     * @param  string|callable|null  $key
-     * @param  bool  $strict
-     * @return static
-     */
-    public function unique($key = null, $strict = false)
-    {
-        $callback = $this->valueRetriever($key);
-
-        $exists = [];
-
-        return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {
-            if (in_array($id = $callback($item, $key), $exists, $strict)) {
-                return true;
-            }
-
-            $exists[] = $id;
-        });
-    }
-
     /**
      * Return only unique items from the collection array using strict comparison.
      *


Test patch:
diff --git a/tests/Support/SupportLazyCollectionTest.php b/tests/Support/SupportLazyCollectionTest.php
index c671830029..f3007934a8 100644
--- a/tests/Support/SupportLazyCollectionTest.php
+++ b/tests/Support/SupportLazyCollectionTest.php
@@ -203,4 +203,13 @@ public function testTapEach()
         $this->assertSame([1, 2, 3, 4, 5], $data);
         $this->assertSame([1, 2, 3, 4, 5], $tapped);
     }
+
+    public function testUniqueDoubleEnumeration()
+    {
+        $data = LazyCollection::times(2)->unique();
+
+        $data->all();
+
+        $this->assertSame([1, 2], $data->all());
+    }
 }