Skip to content

Conversation

@rafaelqueiroz
Copy link
Contributor

@rafaelqueiroz rafaelqueiroz changed the title EnumerateValues::value() support and return negative values if exists EnumerateValues::value() support and return negative values if exists #54910 Oct 28, 2025
@taylorotwell taylorotwell merged commit d158526 into laravel:12.x Oct 28, 2025
66 checks passed
@GrahamCampbell GrahamCampbell changed the title EnumerateValues::value() support and return negative values if exists #54910 [12.x] EnumerateValues::value() support and return negative values if exists #54910 Oct 28, 2025
@rodrigopedra
Copy link
Contributor

@rafaelqueiroz I don't think this fixes the expected behavior.

The last code assertion is this:

$c = new $collection([['id' => 1], ['id' => 2, 'balance' => 200]]);

$this->assertEquals(200, $c->value('balance'));

If we change the input data to

$c = new $collection([['id' => 1], ['id' => 2, 'balance' => 0]]);

dump($c->value('balance'));

It outputs:

$ php artisan local:test
null // routes/local.php:33

Ignoring the balance with a 0 value.

Or:

$c = new $collection([
    ['id' => 1], 
    ['id' => 2, 'balance' => 0],
    ['id' => 3, 'balance' => 200],
]);


dump($c->value('balance'));

Which outputs:

$ php artisan local:test
200 // routes/local.php:33

And also ignores the balance with a 0 value.

It just fixes the very first element.

@rafaelqueiroz
Copy link
Contributor Author

@rodrigopedra you're right, probably it would be impossible use firstWhere(), I will try iterate with the cursor of the collection, thank you.

@rodrigopedra
Copy link
Contributor

@rafaelqueiroz I tried this, and it seems to work for the test cases on your PR and the ones I added in my comment:

public function value($key, $default = null) {
    if ($value = $this->first(fn ($v) => Arr::accessible($v) && Arr::exists($v, $key))) {
        return data_get($value, $key, $default);
    }

    return value($default);
}

It grabs the first item where the key exists and returns whatever value it has, even null.

@rafaelqueiroz
Copy link
Contributor Author

rafaelqueiroz commented Oct 29, 2025

    public function value($key, $default = null)
    {
        $value = $this->first(function ($value) use ($key) {
            return Arr::exists($value, $key);
        });

        return $value ? data_get($value, $key) : value($default);
    }

@rodrigopedra we are at the same page :)

@rodrigopedra
Copy link
Contributor

@rafaelqueiroz there is still a problem with a collection of objects... I am looking into it.

@rafaelqueiroz
Copy link
Contributor Author

rafaelqueiroz commented Oct 29, 2025

@rafaelqueiroz there is still a problem with a collection of objects... I am looking into it.

Really? No make to much sense because the support classes and helper methods will handle that.
I'm going to open the new PR and add test case with objects, feel free for join, thanks.

@rodrigopedra
Copy link
Contributor

Really? No make to much sense because the support classes and helper methods will handle that.

Arr::exists($value, $key) won't work for objects that don't implement ArrayAccess.

@rafaelqueiroz this should do it:

<?php // routes/console.php

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Artisan;

Artisan::command('local:test', function () {
    Collection::macro('myValue', function ($key, $default = null) {
        if ($value = $this->first(fn ($item) => filled(data_get($item, $key)))) {
            return data_get($value, $key, $default);
        }

        return value($default);
    });

    $collection = collect([
        ['id' => 1],
        ['id' => 2, 'balance' => 0],
        ['id' => 3, 'balance' => 200],
    ]);

    dump($collection->myValue('balance'));

    $collection = collect([
        literal(id: 1),
        literal(id: 2, balance: 0),
        literal(id: 3, balance: 200),
    ]);

    dump($collection->myValue('balance'));

    // nested

    $collection = collect([
        ['id' => 1],
        ['id' => 2, 'balance' => ['currency' => 'USD', 'value' => 0]],
        ['id' => 3, 'balance' => ['currency' => 'USD', 'value' => 200]],
    ]);

    dump($collection->myValue('balance.value'));

    $collection = collect([
        literal(id: 1),
        literal(id: 2, balance: literal(currency: 'USD', value: 0)),
        literal(id: 3, balance: literal(currency: 'USD', value: 200)),
    ]);

    dump($collection->myValue('balance.value'));

    // collection of scalars => should return null, as no matching record

    $collection = collect([1, 2, 3]);

    dump($collection->value('balance'));
});

Outputs:

$ php artisan local:test
0 // routes/local.php:22
0 // routes/local.php:30
0 // routes/local.php:40
0 // routes/local.php:48
null // routes/local.php:54

Note that I used a macro to test it out.

@rafaelqueiroz
Copy link
Contributor Author

@rodrigopedra I got it, let's move for #57570

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants