Recursively convert an array and its children to a Collection in Laravel

November 13th, 2021

If you're dealing with plain array data, it often makes sense to convert it to a Laravel Collection so you can make use of the myriad helpers on the Collection class

Whether you're using new Collection([]) or collect([]), I'm going to show you how to not only create a collection, but also iterate recursively and include children.

A bit of background on this first. Let's say you have the following array.

['nike', 'adidas', 'under armour']

If you convert this to a collection, you'll end up with the following.

Illuminate\Support\Collection {#386
    #items: array:3 [
    0 => "nike"
    1 => "adidas"
    2 => "under armour"
    ]
}

But what if the array was multi-dimensional (i.e. had children)?

['brands' => ['nike', 'adidas', 'under armour']]

You'd still end up with native arrays inside the collection.

Illuminate\Support\Collection {#386
    #items: array:1 [
    "brands" => array:3 [
        0 => "nike"
        1 => "adidas"
        2 => "under armour"
    ]
    ]
}

This is fine for most cases, but if you need the power of collections to iterate and work through a multidimensional array, you'll need to add a macro!

The macro

Luckily, Laravel's Collection class is macroable, meaning we can add our own methods.

So let's add a recursive macro to deal with this recursive functionality.

use Illuminate\Support\Collection;

Collection::macro('recursive', function () {
    return $this->map(function ($value) {
        if (is_array($value) || is_object($value)) {
            return collect($value)->recursive();
        }

        return $value;
    });
});

Add this to the boot method of a service provider (like AppServiceProvider).

To use this new method, just chain it on when creating a new collection from an array.

collect(['brands' => ['nike', 'adidas', 'under armour']])->recursive();

Taking this for a spin with the multidimensional example from earlier, here's what we end up with.

Illuminate\Support\Collection {#390
    #items: array:1 [
    "brands" => Illuminate\Support\Collection {#393
        #items: array:3 [
        0 => "nike"
        1 => "adidas"
        2 => "under armour"
        ]
    }
    ]
}

Now the inner brands key is also a collection!

Because it's recursive, this functionality works for any level deep.

Happy recursing!

Author
Alex Garrett-Smith

Comments

No coments, yet. Be the first to leave a comment.