Laravel collection: flattened with full name
Is there a way with Laravel collections to flatten an array with a key "namespace". Something like:
$a = collect([
'id' => 1,
'data' => [
'a' => 2,
'b' => 3
]
]);
$a = $a->flattenWithKeysNamespace(); // <-- this does not exists
// Should returns:
// ['a' => 1, 'data.b' => 2, 'data.c' => 3]; // <-- I would like this.
I know I can do this in raw PHP or with some collection of Collection functions, but sometimes I miss something in the Laravel Collection documentation. So, is there an easy way with Collection functions?
source to share
I think you are correct that there is no "Laravel way" for this. Answers like this show a way to do it in PHP if you're ready to convert yours Collection
to an array, but since you mention raw PHP I assume you've already found this kind of solution.
I think your best bet when using methods Collection
is to write a similar function to the one I linked, but use type functions flatMap()
and recursively call your function when your item is also a collection.
source to share
If you don't want the depth level that gets converted, I think the easiest option for you is a helper function array_dot
. If you want more granular control over how deep the recursion is and whether or not you need to have dot-delimited keys, I've written a collection macro that can do that. Usually collect($array)->collapse()
supports string keys, but non-incrementing numeric keys are still lost even if they are coerced to string. And I recently needed to support them.
Put this in your method AppServiceProvider::boot()
:
/**
* Flatten an array while keeping it keys, even non-incremental numeric ones, in tact.
*
* Unless $dotNotification is set to true, if nested keys are the same as any
* parent ones, the nested ones will supersede them.
*
* @param int $depth How many levels deep to flatten the array
* @param bool $dotNotation Maintain all parent keys in dot notation
*/
Collection::macro('flattenKeepKeys', function ($depth = 1, $dotNotation = false) {
if ($depth) {
$newArray = [];
foreach ($this->items as $parentKey => $value) {
if (is_array($value)) {
$valueKeys = array_keys($value);
foreach ($valueKeys as $key) {
$subValue = $value[$key];
$newKey = $key;
if ($dotNotation) {
$newKey = "$parentKey.$key";
if ($dotNotation !== true) {
$newKey = "$dotNotation.$newKey";
}
if (is_array($value[$key])) {
$subValue = collect($value[$key])->flattenKeepKeys($depth - 1, $newKey)->toArray();
}
}
$newArray[$newKey] = $subValue;
}
} else {
$newArray[$parentKey] = $value;
}
}
$this->items = collect($newArray)->flattenKeepKeys(--$depth, $dotNotation)->toArray();
}
return collect($this->items);
});
Then you can call collect($a)->flattenKeepKeys(1, true);
and return what you expect.
source to share