如何将层次结构树转换为父子关系


How can I convert a hierarchical tree to parent-child relationships?

目前,我正在创建一个动态菜单为我自己的CMS(练习)在PHP,但我不知道保存在我的数据库中的数据。

数据库结构:

menuitem_id
menu_id
menuitem_order
menuitem_name
menuitem_page_id
parent_menuitem_id

我确实得到了一个层次树的输出,但这并不是将其存储到数据库中的所需格式:

Array
(
    [0] => Array
        (
            [id] => 2
        )
    [1] => Array
        (
            [id] => 1
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 3
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 4
                                        )
                                    [1] => Array
                                        (
                                            [id] => 5
                                        )
                                )
                        )
                    [1] => Array
                        (
                            [id] => 6
                        )
                )
        )
)

然而,我想将其转换为具有新的新ID的父ID数组(我将截断表并插入新数据)。像这样:

Array
(
    [0] => 0
    [1] => 0
    [2] => 2
    [3] => 3
    [4] => 3
    [5] => 2
)

如何做到这一点?

注意:我已经阅读了这篇文章,但我需要它的相反的代码

您需要一个递归函数:

function flattenHierarchicalArray($arr, $parentId = null) {
    $items = array();
    foreach ($arr as $item) {
        $items[] = array('id' => $item['id'], 'parentId' = $parentId);
        if (isset($item['children'])) $items = array_merge($items, flattenHierarchicalArray($item['children'], $item['id']));
    }
    return $items;
}

我想我有解决方案结合AlliterativeAlice的PHP代码。

我正在使用Nestable插件。该扩展创建了我的层次树,并将其设置在表单的隐藏字段中(由JavaScript完成)。我通过添加以下代码来更新此代码以创建新的id:

var nestable_update = function(e){
    //added for updating old IDs
    $(".dd-item").each(function(index){
        $(this).data("id", index+1);
    });
    var list   = e.length ? e : $(e.target),
        output = list.data("output");
    if (window.JSON) {
        output.val(window.JSON.stringify(list.nestable("serialize")));
    } else {
        output.val("JSON browser support required for this demo.");
    }
};
$(".dd").nestable({
    maxDepth:5
}).on("change", nestable_update);
nestable_update($(".dd").data("output", $("#nestable_output")));

我使用您的PHP代码来获取parentID(非常感谢AlliterativeAlice,因为它比我原来的PHP代码更有效):

function flatten_hierarchical_tree($arr, $parent_id=0) {
    $items = array();
    foreach ($arr as $item) {
        $items[] = array('id' => $item['id'], 'parent_id' => $parent_id);
        if (isset($item['children'])) $items = array_merge($items, flatten_hierarchical_tree($item['children'], $item['id']));
    }
    return $items;
}

对于那些对我的最终代码感兴趣的人。它用于将数据存储在数据库中,并将其再次构建为HTML的分层树+可打印树。

嵌套插件的JavaScript代码:

var nestable_update = function(e){
    $(".dd-item").each(function(index){
        $(this).data("id", index+1);
    });
    var list   = e.length ? e : $(e.target),
        output = list.data("output");
    if (window.JSON) {
        output.val(window.JSON.stringify(list.nestable("serialize")));
    } else {
        output.val("JSON browser support required for this demo.");
    }
};
$(".dd").nestable({
    maxDepth:5
}).on("change", nestable_update);
nestable_update($(".dd").data("output", $("#nestable_output")));

数据库结构:

menuitem_id
menu_id
menuitem_order
menuitem_name
menuitem_page_id
parent_menuitem_id

构建树的PHP函数(在数据库中存储数据的格式+从数据库获取数据的格式):

function create_flatten_hierarchical_tree($tree, $parent_id=0) {
    $items = array();
    foreach ($tree as $item) {
        $items[] = array("id" => $item["id"], "parent_id" => $parent_id);
        if (isset($item["children"])) $items = array_merge($items, create_flatten_hierarchical_tree($item["children"], $item["id"]));
    }
    return $items;
}
function create_hierarchical_tree($tree, $root=0) {
    $return = array();
    foreach($tree as $child => $parent) {
        if($parent["parent_menuitem_id"] == $root) {
            if(isset($tree[$child]["menuitem_id"]) === true){
                $parent['children'] = create_hierarchical_tree($tree, $tree[$child]["menuitem_id"]);
            }
            unset($tree[$child]);
            $return[] = $parent;
        }
    }
    return empty($return) ? null : $return;    
}
function print_hierarchical_tree($tree, $rows_pages) {                                  
    if(!is_null($tree) && count($tree) > 0) {
        $return .= "<ol class='dd-list'>";
        foreach($tree as $item){
            $options = "";
            foreach($rows_pages as $row_pages){
                $selected = "";
                if($row_pages["page_id"] == $item["menuitem_page_id"]){
                    $selected = "selected";
                }
                $options .= "<option value='".$row_pages["page_id"]."' $selected>".$row_pages["friendly_url"]."</option>";
            }
            $return .= "<li class='dd-item' data-id='".$item["menuitem_id"]."'><div class='dd-handle'>drag</div><div class='item_wrapper'><div class='item'><div class='item_title'>".$item["menuitem_name"]."</div></div><div class='item_sub'><div class='label_input'><label for='menuitem_name".$item["menuitem_id"]."'>Menuitem name</label><input type='text' id='menuitem_name".$item["menuitem_id"]."' name='menuitem_name[]' value='".$item["menuitem_name"]."' /></div><div class='label_input'><label for='page_link".$item["menuitem_id"]."'>Page link</label><label class='select'><select id='page_link".$item["menuitem_id"]."' name='menuitem_page_id[]'>".$options."</select></label></div> <a onClick='delete_menuitem(".$item["menuitem_id"].");' class='button red_bg delete'>Delete</a></div></div>";
            $return .= print_hierarchical_tree($item["children"], $rows_pages);
            $return .= "</li>";
        }
        $return .= "</ol>";
    }
    return empty($return) ? null : $return; 
}

menu_edit.php页面核心代码:

<?php
$stmt_menuitems = $dbh->prepare("SELECT * FROM inno_mw_thurs_menuitems mi WHERE mi.menu_id=:menu_id");
$stmt_menuitems->bindParam(":menu_id", $_GET["menu_id"]);
$stmt_menuitems->execute();
if (!empty($stmt_menuitems->rowCount())) {
?>
    <div class="dd">
            <?php
            $result = $stmt_menuitems->fetchAll();
            $tree = create_hierarchical_tree($result);
            $stmt_pages = $dbh->prepare("SELECT * FROM inno_mw_thurs_pages");
            $stmt_pages->execute();
            $rows_pages = $stmt_pages->fetchAll();
            $tree = print_hierarchical_tree($tree, $rows_pages);
            echo $tree;
            ?>
    </div> 
<?php
}

menu_edit_process.php页面核心代码:

if(isset($_POST["menu_id"])){
    $menu_id = $_POST["menu_id"];
    $nestable_output = json_decode($_POST["nestable_output"], true);
    $parent_menuitem_ids_arr = create_flatten_hierarchical_tree($nestable_output);
    $stmt = $dbh->prepare("TRUNCATE TABLE inno_mw_thurs_menuitems");
    $stmt->execute();
    $stmt = $dbh->prepare("INSERT INTO inno_mw_thurs_menuitems (menu_id, menuitem_order, menuitem_name, menuitem_page_id, parent_menuitem_id) VALUES (:menu_id, :menuitem_order, :menuitem_name, :menuitem_page_id, :parent_menuitem_id)");
    $menuitem_order_arr = array();
    foreach($_POST["menuitem_name"] as $f => $name){
        $menuitem_name = $_POST["menuitem_name"][$f];
        $menuitem_page_id = $_POST["menuitem_page_id"][$f];
        $parent_menuitem_id = $parent_menuitem_ids_arr[$f]["parent_id"];
        if(array_key_exists($parent_menuitem_id, $menuitem_order_arr) && $parent_menuitem_id != 0){
            $menuitem_order_arr[$parent_menuitem_id] += 1;
        }
        else{
            $menuitem_order_arr[$parent_menuitem_id] = 0;
        }
        $stmt->bindParam(":menu_id", $menu_id);
        $stmt->bindParam(":menuitem_order", $menuitem_order_arr[$parent_menuitem_id]);
        $stmt->bindParam(":menuitem_name", $menuitem_name);
        $stmt->bindParam(":menuitem_page_id", $menuitem_page_id);
        $stmt->bindParam(":parent_menuitem_id", $parent_menuitem_id);
        $stmt->execute();
    }
    header("location: menus_list.php");
}

请随时改进此代码