8000 [12.x] Add `Closure`-support to `$key`/`$value` in Collection `pluck()` method by ralphjsmit · Pull Request #56188 · laravel/framework · GitHub
[go: up one dir, main page]

Skip to content

[12.x] Add Closure-support to $key/$value in Collection pluck() method #56188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 1, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
WIP
  • Loading branch information
ralphjsmit committed Jul 1, 2025
commit c666c977041d7353e62b0240c76182be83e57d97
19 changes: 12 additions & 7 deletions src/Illuminate/Collections/Arr.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use ArgumentCountError;
use ArrayAccess;
use Closure;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Support\Traits\Macroable;
Expand Down Expand Up @@ -686,8 +687,8 @@ public static function select($array, $keys)
* Pluck an array of values from an array.
*
* @param iterable $array
* @param string|array|int|null $value
* @param string|array|null $key
* @param string|array|int|Closure|null $value
* @param string|array|Closure|null $key
* @return array
*/
public static function pluck($array, $value, $key = null)
Expand All @@ -697,15 +698,19 @@ public static function pluck($array, $value, $key = null)
[$value, $key] = static::explodePluckParameters($value, $key);

foreach ($array as $item) {
$itemValue = data_get($item, $value);
$itemValue = $value instanceof Closure
? $value($item)
: data_get($item, $value);

// If the key is "null", we will just append the value to the array and keep
// looping. Otherwise we will key the array using the value of the key we
// received from the developer. Then we'll return the final array form.
if (is_null($key)) {
$results[] = $itemValue;
} else {
$itemKey = data_get($item, $key);
$itemKey = $key instanceof Closure
? $key($item)
: data_get($item, $key);

if (is_object($itemKey) && method_exists($itemKey, '__toString')) {
$itemKey = (string) $itemKey;
Expand All @@ -721,15 +726,15 @@ public static function pluck($array, $value, $key = null)
/**
* Explode the "value" and "key" arguments passed to "pluck".
*
* @param string|array $value
* @param string|array|null $key
* @param string|array|Closure $value
* @param string|array|Closure|null $key
* @return array
*/
protected static function explodePluckParameters($value, $key)
{
$value = is_string($value) ? explode('.', $value) : $value;

$key = is_null($key) || is_array($key) ? $key : explode('.', $key);
$key = is_null($key) || is_array($key) || $key instanceof Closure ? $key : explode('.', $key);

return [$value, $key];
}
Expand Down
10 changes: 7 additions & 3 deletions src/Illuminate/Collections/LazyCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -777,12 +777,16 @@ public function pluck($value, $key = null)
[$value, $key] = $this->explodePluckParameters($value, $key);

foreach ($this as $item) {
$itemValue = data_get($item, $value);
$itemValue = $value instanceof Closure
? $value($item)
: data_get($item, $value);

if (is_null($key)) {
yield $itemValue;
} else {
$itemKey = data_get($item, $key);
$itemKey = $key instanceof Closure
? $key($item)
: data_get($item, $key);

if (is_object($itemKey) && method_exists($itemKey, '__toString')) {
$itemKey = (string) $itemKey;
Expand Down Expand Up @@ -1869,7 +1873,7 @@ protected function explodePluckParameters($value, $key)
{
$value = is_string($value) ? explode('.', $value) : $value;

$key = is_null($key) || is_array($key) ? $key : explode('.', $key);
$key = is_null($key) || is_array($key) || $key instanceof Closure ? $key : explode('.', $key);

return [$value, $key];
}
Expand Down
5 changes: 3 additions & 2 deletions src/Illuminate/Database/Eloquent/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Illuminate\Database\Eloquent;

use Closure;
use Illuminate\Contracts\Queue\QueueableCollection;
use Illuminate\Contracts\Queue\QueueableEntity;
use Illuminate\Contracts\Support\Arrayable;
Expand Down Expand Up @@ -717,8 +718,8 @@ public function partition($key, $operator = null, $value = null)
/**
* Get an array with the values of a given key.
*
* @param string|array<array-key, string>|null $value
* @param string|null $key
* @param string|array<array-key, string>|Closure|null $value
* @param string|Closure|null $key
* @return \Illuminate\Support\Collection<array-key, mixed>
*/
public function pluck($value, $key = null)
Expand Down
20 changes: 20 additions & 0 deletions tests/Database/DatabaseEloquentCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,26 @@ public function testWithNonScalarKey()
$this->assertSame($bar, $collect 8000 ion->except($fooKey)->first());
}

public function testPluck()
{
$model1 = (new TestEloquentCollectionModel)->forceFill(['id' => 1, 'name' => 'John', 'country' => 'US']);
$model2 = (new TestEloquentCollectionModel)->forceFill(['id' => 2, 'name' => 'Jane', 'country' => 'NL']);
$model3 = (new TestEloquentCollectionModel)->forceFill(['id' => 3, 'name' => 'Taylor', 'country' => 'US']);

$c = new Collection;

$c->push($model1)->push($model2)->push($model3);

$this->assertInstanceOf(BaseCollection::class, $c->pluck('id'));
$this->assertEquals([1, 2, 3], $c->pluck('id')->all());

$this->assertInstanceOf(BaseCollection::class, $c->pluck('id', 'id'));
$this->assertEquals([1 => 1, 2 => 2, 3 => 3], $c->pluck('id', 'id')->all());
$this->assertInstanceOf(BaseCollection::class, $c->pluck('test'));

$this->assertEquals(['John (US)', 'Jane (NL)', 'Taylor (US)'], $c->pluck(fn (TestEloquentCollectionModel $model) => "{$model->name} ({$model->country})")->all());
}

/**
* Helpers...
*/
Expand Down
22 changes: 22 additions & 0 deletions tests/Support/SupportCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2323,6 +2323,28 @@ public function testPluckWithDotNotation($collection)
$this->assertEquals([['php', 'python'], ['php', 'asp', 'java']], $data->pluck('skill.backend')->all());
}

#[DataProvider('collectionClassProvider')]
public function testPluckWithClosure($collection)
{
$data = new $collection([
[
'name' => 'amir',
'skill' => [
'backend' => ['php', 'python'],
],
],
[
'name' => 'taylor',
'skill' => [
'backend' => ['php', 'asp', 'java'],
],
],
]);

$this->assertEquals(["amir (verified)", "taylor (verified)"], $data->pluck(fn (array $row) => "{$row['name']} (verified)")->all());
$this->assertEquals(["php/python" => "amir", "php/asp/java" => "taylor"], $data->pluck('name', fn (array $row) => implode('/', $row['skill']['backend']))->all());
}

#[DataProvider('collectionClassProvider')]
public function testPluckDuplicateKeysExist($collection)
{
Expand Down
0