PHP tree depending list only for some childrens

Viewed 87

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.

1 Answers

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);

Related