Reputation: 19
i need a function to convert a Collection in Laravel to an multi-dimensional array, maybe someone have something like this.
What i have is this collection of permissions:
Illuminate\Support\Collection {#1190 ▼
#items: array:10 [▼
0 => "admin.users.view"
1 => "admin.roles.create"
2 => "admin.roles.view"
3 => "admin.roles.edit"
4 => "admin.roles.delete"
5 => "admin.roles.set"
6 => "admin.whitelist.edit"
7 => "admin.ticket.view"
8 => "admin.ticket.edit"
9 => "admin.ticket.create"
]
}
Now i want to split it by every dot the result should look like this:
[
"admin" => [
"users" => [
"view"
],
"roles" => [
"create",
"view",
"edit",
"delete",
"set"
],
"whitelist" => [
"edit"
],
"ticket" => [
"view",
"edit",
"create"
]
]
]
I know it should be possible to work with mapping or create a function for it and make a foreach and stuff like this, but before spending hours to get the solution i would ask if someone have any snipped for it.
Thank you in advance for your support.
Greetings from Germany Patrick
Upvotes: 1
Views: 1771
Reputation: 15786
Using this collection as base:
$collection = collect([
"admin.users.view",
"admin.roles.create",
"admin.roles.view",
"admin.roles.edit",
"admin.roles.delete",
"admin.roles.set",
"admin.whitelist.edit",
"admin.ticket.view",
"admin.ticket.edit",
"admin.ticket.create"
]);
EDIT After struggling for awhile, I reached a different way to do it adapting the Arr::set
function.
$collection->reduce(function ($carry, $item) {
list($key, $value) = [Str::beforeLast($item, '.'), Str::afterLast($item, '.')];
$keys = explode('.', $key);
foreach ($keys as $i => $key) {
if (count($keys) === 1)
break;
unset($keys[$i]);
if (! isset($array[$key]) || ! is_array($array[$key]))
$array[$key] = [];
$array = &$carry[$key];
}
$array[array_shift($keys)][] = $value;
return $carry;
}, []);
Upvotes: 0
Reputation: 807
There might be a more Laravel way of doing this. However, the following code would create a nested array based on the strings you provided.
$result = [];
foreach ($strings as $string) {
// Assign back to the root (new start for current string)
$previous = &$result;
$pieces = explode('.', $string);
$piecesCount = count($pieces);
$lastIndex = $piecesCount - 1;
for ($i = 0; $i < $piecesCount; $i++) {
// Only interested in pushing the last piece as value.
if ($i == $lastIndex) {
$previous[] = $pieces[$i];
continue;
}
if (!key_exists($pieces[$i], $previous)) {
$previous[$pieces[$i]] = [];
}
// Go down the nested array by assigning its reference.
$previous = &$previous[$pieces[$i]];
}
}
Result:
Array
(
[admin] => Array
(
[users] => Array
(
[0] => view
)
[roles] => Array
(
[0] => create
[1] => view
[2] => edit
[3] => delete
[4] => set
)
[whitelist] => Array
(
[0] => edit
)
[ticket] => Array
(
[0] => view
[1] => edit
[2] => create
)
)
)
Upvotes: 1