3

I'm looking for a function that can create a hierarchical array but only for some childs.

this example seems to be good : Recursive function to generate multidimensional array from database result

But I want parents just for some IDs. For example :

+-------+---------------+---------------------------+
|   id  |   parent_id   |           title           |
+-------+---------------+---------------------------+
|   1   |       0       |   Parent Page             |
|   2   |       1       |   Sub Page                |
|   3   |       2       |   Sub Sub Page            |
|   4   |       0       |   Another Parent Page     |
|   5   |       1       |   Sub Page 2              |
+-------+---------------+---------------------------+

I want only hierarchy for id 2, 4 and 5.

And return me something like this :

Array
(
    [0] => Array
        (
            [id] => 1
            [parent_id] => 0
            [title] => Parent Page
            [children] => Array
                        (
                            [0] => Array
                                (
                                    [id] => 2
                                    [parent_id] => 1
                                    [title] => Sub Page                                                    
                                ),
                            [1] => Array
                                (
                                    [id] => 5
                                    [parent_id] => 1
                                    [title] => Sub Page 2                                                     
                                )
                        )
        )
    [1] => Array
        (
            [id] => 4
            [parent_id] => 0
            [title] => Another Parent Page
        )
)

2, 4 and 5 should be smallest childrens and nothing under them.

To resume, what I want is exactly the same than linked post, but my smallest leafs should be only leaf's id present in an array [2,4,5]

I don't know if someone understand my problem...

Thanks a lot

Edit: I have update and add example with id = 5.

MathAng
  • 222
  • 1
  • 15

1 Answers1

1

Yes, your question is pretty clear. You want to recreate the tree from the bottom to the top, only for specific leaf's ids.

You can achieve it by filtering out all unnecessary categories from the initial array, and then just build the tree with the function that you find earlier.

//Assuming you have this array with mysql result of all possible categories
$mysqlRows = [
    ["id" => 1, "parent_id" => 0, "title" => "Parent Page"],
    ["id" => 2, "parent_id" => 1, "title" => "Sub Page"],
    ["id" => 3, "parent_id" => 2, "title" => "Sub Sub Page"],
    ["id" => 4, "parent_id" => 0, "title" => "Another Parent Page"],
    ["id" => 5, "parent_id" => 1, "title" => "Sub Page 2"]
];

/*
 * Fill $participatingIds array with id of categories that related to our needs
 * Be aware that $participatingIds has & sign - it means
 * that it will be passed by reference
 */
function collectAllParentsId($id, $mysqlRows, &$participatingIds)
{
    if (!in_array($id, $participatingIds)) {
        $participatingIds[] = $id;
    }
    if ($mysqlRows[$id]["parent_id"] !== 0) {
        collectAllParentsId($mysqlRows[$id]["parent_id"], $mysqlRows, $participatingIds);
    }
}

//Initial function to build a tree from a flat category array
function buildTree(array $elements, $parentId = 0) {
    $branch = array();

    foreach ($elements as $element) {
        if ($element['parent_id'] == $parentId) {
            $children = buildTree($elements, $element['id']);
            if ($children) {
                $element['children'] = $children;
            }
            $branch[] = $element;
        }
    }

    return $branch;
}


/* START */

/*
 * Make array indexes equals to the category's "id",
 * so we can access category like this $mysqlRows[$category_id]
*/
$mysqlRows = array_column($mysqlRows, null, "id");

//Array of ids for which you want create a tree
$someIds = [2, 4, 5];

/*
 * Create one flat array with all Ids that will participating in the tree
 * (leaf id and all of it parents id)
 * Order of ids is doesn't matter here
 * $ids will looks like this:
 * [ 1, 2, 4, 5 ]
 */

$ids = [];
foreach ($someIds as $id) {
    collectAllParentsId($id, $mysqlRows, $ids);
}

//Now filter out all categories that doesn't participating in out tree
$filteredRows = array_filter(
    $mysqlRows,
    function ($key) use ($ids) {
        return (in_array($key, $ids));
    },
    ARRAY_FILTER_USE_KEY
);

//Now we have only desired categories - create the tree from it:
$tree = buildTree($filteredRows);

var_dump($tree);

krylov123
  • 739
  • 8
  • 15
  • 1
    Hello ! Thanks a lot for your answer! It works fine but not exactly what i'm looking for. When i added a leaf ["id" => 5, "parent_id" => 1, "title" => "Sub Page 2 "] it recreate an array from id 1 and not add in array already created. In your case, I haven't a multidimentionnal array.. Look this result's screen : https://www.casimages.com/i/200827030552125794.png.html Do you understand what I mean? – MathAng Aug 27 '20 at 13:05
  • 1
    Something like this : https://www.casimages.com/i/200827032524459014.png.html should be better maybe but I don't know how to do.. – MathAng Aug 27 '20 at 13:24
  • 1
    @MathAng that's even easier, take a look for my updated solution – krylov123 Aug 27 '20 at 15:39
  • Woo It seems to work perfectly !! I will update this to work in my case! I let you know. And I'll ask if i have a problem ahaha Thanks a lot !! Do you think this algorithme is optimized? In my case I have 50.000 rows and not 5 aahah But more often, only 3 level hierarchy – MathAng Aug 27 '20 at 15:56
  • It will take a few seconds to complete. Depending on your server capabilities, sometimes it could be faster to find all parents ids via database queries. Just make tests, there is good chances current solution will be good enough. – krylov123 Aug 27 '20 at 17:41