Reputation: 644
I have problem formatting array to become fancytree format, below array output from db:
array(44) {
[0]=>
array(3) {
["id"]=>
string(2) "35"
["title"]=>
string(28) "ROOT1"
["path"]=>
string(28) "ROOT1"
}
[1]=>
array(3) {
["id"]=>
string(2) "36"
["title"]=>
string(27) "SUB_A"
["path"]=>
string(56) "ROOT1>SUB_A"
}
[2]=>
array(3) {
["id"]=>
string(2) "39"
["title"]=>
string(12) "SUB_A_1"
["path"]=>
string(69) "ROOT1>SUB_A>SUB_A_1"
}
[3]=>
array(3) {
["id"]=>
string(2) "37"
["title"]=>
string(28) "SUB_A_2"
["path"]=>
string(85) "ROOT1>SUB_A>SUB_A_2"
}
[4]=>
array(3) {
["id"]=>
string(2) "40"
["title"]=>
string(30) "SUB_A_3"
["path"]=>
string(87) "ROOT1>SUB_A>SUB_A_3"
}
[5]=>
array(3) {
["id"]=>
string(2) "43"
["title"]=>
string(19) "SUB_A_4"
["path"]=>
string(76) "ROOT1>SUB_A>SUB_A_4"
}
[6]=>
array(3) {
["id"]=>
string(2) "41"
["title"]=>
string(12) "SUB_A_5"
["path"]=>
string(69) "ROOT1>SUB_A>SUB_A_5"
}
[7]=>
array(3) {
["id"]=>
string(1) "1"
["title"]=>
string(20) "ROOT2"
["path"]=>
string(20) "ROOT2"
}
[8]=>
array(3) {
["id"]=>
string(2) "30"
["title"]=>
string(37) "ROOT3"
["path"]=>
string(37) "ROOT3"
}
[9]=>
array(3) {
["id"]=>
string(2) "34"
["title"]=>
string(21) "SUB_B"
["path"]=>
string(59) "ROOT3>SUB_B"
}
[10]=>
array(3) {
["id"]=>
string(2) "31"
["title"]=>
string(15) "SUB_C"
["path"]=>
string(53) "ROOT3>SUB_C"
}
I want to format values of path
become structured array, here is what I try:
function format(array $data) : array
{
$single = [];
// format to single data
foreach ($data as $value) {
$single[] = $value['path'];
}
$result = [];
foreach ($single as $path) {
$parts = explode('>', $path);
$section = &$result;
$sectionName = '';
foreach ($parts as $part) {
$sectionName = $part;
if (array_key_exists($sectionName, $section) === FALSE) {
$section[$sectionName] = [];
}
$section = &$section[$sectionName];
}
}
return $result;
}
result:
array(3) {
["ROOT1"]=>
array(1) {
["SUB_A"]=>
array(5) {
["SUB_A_1"]=>
array(0) {
}
["SUB_A_2"]=>
array(0) {
}
["SUB_A_3"]=>
array(0) {
}
["SUB_A_4"]=>
array(0) {
}
["SUB_A_5"]=>
array(0) {
}
}
}
["ROOT2"]=>
array(0) {
}
["ROOT3"]=>
array(2) {
["SUB_B"]=>
array(0) {
}
["SUB_C"]=>
array(0) {
}
}
i need to include values of id
and title
to each path as expected result:
array(3) {
[0]=>
array(3) {
["title"]=>
string(5) "ROOT1"
["id"]=>
int(35)
["children"]=>
array(1) {
[0]=>
array(3) {
["title"]=>
string(5) "SUB_A"
["id"]=>
int(36)
["children"]=>
array(5) {
[0]=>
array(2) {
["title"]=>
string(7) "SUB_A_1"
["id"]=>
int(39)
}
[1]=>
array(2) {
["title"]=>
string(7) "SUB_A_2"
["id"]=>
int(37)
}
[2]=>
array(2) {
["title"]=>
string(7) "SUB_A_3"
["id"]=>
int(40)
}
[3]=>
array(2) {
["title"]=>
string(7) "SUB_A_4"
["id"]=>
int(43)
}
[4]=>
array(2) {
["title"]=>
string(7) "SUB_A_5"
["id"]=>
int(41)
}
}
}
}
}
[1]=>
array(2) {
["title"]=>
string(5) "ROOT2"
["id"]=>
int(1)
}
[2]=>
array(3) {
["title"]=>
string(5) "ROOT3"
["id"]=>
int(30)
["children"]=>
array(2) {
[0]=>
array(2) {
["title"]=>
string(5) "SUB_B"
["id"]=>
int(34)
}
[1]=>
array(2) {
["title"]=>
string(5) "SUB_C"
["id"]=>
int(31)
}
}
}
}
I would be grateful for any help you are able to provide.
Upvotes: 1
Views: 57
Reputation: 4011
Here's how I would do it. Test
I used arrow functions to reduce the amount of lines and there are inline comments to explain what I did.
<?php
$data = [["id"=> "35", "title"=> "ROOT1", "path"=> "ROOT1"], ["id"=> "36", "title"=> "SUB_A", "path"=> "ROOT1>SUB_A"], ["id"=> "37", "title"=> "SUB_A_1", "path"=> "ROOT1>SUB_A>SUB_A_1"], ["id"=> "38", "title"=> "SUB_A_2", "path"=> "ROOT1>SUB_A>SUB_A_2"], ["id"=> "39", "title"=> "SUB_A_3", "path"=> "ROOT1>SUB_A>SUB_A_3"], ["id"=> "40", "title"=> "SUB_A_4", "path"=> "ROOT1>SUB_A>SUB_A_4"], ["id"=> "41", "title"=> "SUB_A_5", "path"=> "ROOT1>SUB_A>SUB_A_5"], ["id"=> "1", "title"=> "ROOT2", "path"=> "ROOT2"], ["id"=> "30", "title"=> "ROOT3", "path"=> "ROOT3"], ["id"=> "34", "title"=> "SUB_B", "path"=> "ROOT3>SUB_B"], ["id"=> "31", "title"=> "SUB_C", "path"=> "ROOT3>SUB_C"]];
// The path is defaulted to an empty string, so the regex would return the highest level elements only because they don't have any `>`
function get_children($data, $path = '')
{
$results = array_values(array_filter($data, fn($item) => preg_match("/^{$path}[^>]+$/", $item['path'])));
// This regex, uses the passed path (e.g ROOT1) and searches for elements with anything but another `>`, because `>` signifies an inner directory.
// So this would return elements with a path like `ROOT1>SUB_A, ROOT1>SUB_B` but not `ROOT1>SUB_A>SUB_A_1`
foreach($results as $i => $result) {
// then I iterate through the result to get the element's children
$children = array_values(get_children($data, "{$result['path']}>"));
if (count($children)) $results[$i]['children'] = $children;
unset($results[$i]['path']); // Removing the path key from the array
}
return $results;
}
$format = fn($data) => get_children($data);
print_r($format($data));
Upvotes: 1