代码之家  ›  专栏  ›  技术社区  ›  David

使用PHP将Mysql Select转换为独立于级别的目录结构多维数组

  •  2
  • David  · 技术社区  · 8 年前

    所以我有一个select语句,它从DB返回3个值:

    • 文件夹ID,
    • 文件夹名称,
    • 父ID。

    如果文件夹没有父文件夹,则返回空作为父ID。

    使用这些数据,我将结果拆分为两个数组。

    一个名为 $tree ,将用作“目录树”,首先将包含所有父文件夹,这些父文件夹的父Id设置为空。。。 还有一个叫 $children ,其中包含所有其他子文件夹。

    有了这些,我试图创建一个多维的 array($tree) 我将使用它来使用PHP/HTML向用户显示文件结构。理想情况下,这将使用递归来允许不知道目录的实际深度。

    我目前正在尝试以下操作,但没有成功,在思考了一整天之后,我觉得自己被卡住了(函数find Children被函数getDirTree进一步调用):

        // should be recursive function. Takes 2 arrays as an argument.
        // returns $tree() which will be a multiple dimension array  
        function findChildren($tree, $children){
        // tree has 2 parents in first run
        foreach($tree as $folder){
            $tempArray = array();
            // children has 4
            foreach($children as $child){
                if ($child['parentId'] === $folder['folderId']){
                    array_push($tempArray, $child);
                    if(($childKey = array_search($child, $children)) !== false) {
                        unset($children[$childKey]);
                    }
                }
            }
            if(($parentKey = array_search($tree, $folder)) !== false) {
                array_push($children[$parentKey],$tempArray);
            }
        }
    // Need to have some sort of recursion in this function
    //    if (!empty($children)){
    //        findChildren($tree, $children);
    //    }
    }
    
    // takes userId as int and returns a multi dimensional array representing the users folder structure.
    function getDirTree($userId){
        global $mysqli;
    
        $children = array();
        $tree = array();
    
        if($folders = $mysqli->prepare("SELECT folders.id, folders.name, child_of_folder.parent_id
                                        FROM child_of_folder
                                        RIGHT JOIN folders
                                        ON  (child_of_folder.child_id = Folders.id)
                                        WHERE folders.user_id = ?;")) {
            // Bind the parameters...  s for String and the variable $name to be bound.
            if ($folders->bind_param("i", $userId)) {
                // execute the query
                if ($folders->execute()) {
                    // store the results
                    if($folders->store_result()){
                        // bind the results
                        if($folders->bind_result($folderId, $folderName, $parentId)) {
                            // Fetch the results
                            while ($folders->fetch()) {
                                if ($parentId === null) {
                                    array_push($tree, array('folderId' => $folderId, 'folderName' => $folderName, 'parentId' => $parentId));
                                } else {
                                    array_push($children, array('folderId' => $folderId, 'folderName' => $folderName, 'parentId' => $parentId));
                                }
                            }
    
                        } else {
                            $hasFolder = null;
                        }
                    } else {
                        // if there were no values to store return false
                        $hasFolder = null;
                    }
                } else {
                    // if there was a problem executing the statement return null
                    $hasFolder = null;
                }
            } else {
                // if there was a problem binding the statement return null
                $hasFolder = null;
            }
        } else {
            // if there was a problem preparing the statement return null
            $hasFolder = null;
        }
    
        if(!empty($children)){
            findChildren($tree, $children);
        }
        $folders->free_result();
        $mysqli->close();
    
        return $tree;   
    }
    

    的输出 $树 $儿童 在传递给 findChildren() :

    Children Array Before findChildren
    
    Array
    (
        [0] => Array
            (
                [folderId] => 2
                [folderName] => home
                [parentId] => 1
            )
    
        [1] => Array
            (
                [folderId] => 3
                [folderName] => account
                [parentId] => 2
            )
    
        [2] => Array
            (
                [folderId] => 4
                [folderName] => bill
                [parentId] => 2
            )
    
        [3] => Array
            (
                [folderId] => 6
                [folderName] => work
                [parentId] => 2
            )
    
    )
    
    Tree Array Before findChildren
    
    Array
    (
        [0] => Array
            (
                [folderId] => 1
                [folderName] => work
                [parentId] => 
            )
    
        [1] => Array
            (
                [folderId] => 5
                [folderName] => hello
                [parentId] => 
            )
    
    )
    
    2 回复  |  直到 8 年前
        1
  •  0
  •   Nyranith    8 年前

    我认为这应该管用。我改成了xml结构而不是数组,因为xml结构更容易处理,尤其是在递归时。 我做了一些假设,例如$children数组包含数据库中的所有子级。 我希望这是你想要的东西。

     function getFolderStructure($userId) 
     {
       //global variable
       $xml = new DOMDocument(); 
       $xml->formatOutput = true; 
    
       $element = $xml->createElement($userId);
       $element->nodeValue = ''; 
    
       //get the top level folders. 
       getDirTree($userId);
    
       //goes through all the top level folders. 
       foreach($tree as $topLevelFolder)
       {
           findChildren($element, $topLevelFolder); 
       }
    
       $xml->appendChild($element); 
    
       return $xml; 
    
      }
    
    
     //prob need to use $this->xml 
     function findChildren(&$element, $folder)
     {
          if(is_array($folder) && isset($folder["folder_name"]) && isset($folder["folderId"]))
       {
           $folder = $xml->createElement($folder["folder_name"], ""); 
    
           $folderIdAttribute = $xml->createAttribute("FolderId"); 
    
           $folderIdAttribute->value = $folder["folderId"]; 
    
           $folder-appendChild($folderIdAttribute);
    
           if(isset($folder["parentId"]) && !empty($folder["parentId"]))
           {
               $parentIdAttribute = $xml->createAttribute("ParentId"); 
    
               $parentIdAttribute->value = $folder["parentId"]; 
    
               $folder->appendChild($folder);
           }
    
    
           foreach(findChildrenArray($folder['folderId']) as $child)
           {
               findChildren($folder, $child); 
           }
    
           $element->appendChild($folder); 
       }
    }
    
    function findChildrenArray($folderId)
    {
       $retArray = array(); 
    
       foreach($children as $child)
       {
           if(isset($child["parentId"]) && $child["parentId"] == $folderId)
           {
               array_push($retArray, $child); 
           }
       }
    }
    
        2
  •  0
  •   David    8 年前

    我最终通过不将菜单项放入多维数组来解决这个问题。

    我所寻找的最终结果是将DB查询转换为HTML,因此有了父数组和子数组,我创建了一个递归函数,将菜单项连接到一个带有标记的无序列表中。

    到目前为止,我已经用3个深度测试了它,但从我所能看到的情况来看,它不应该随着深度的加深而破裂。

    // returns a string value of an HTML built multi-level list ready to display in HTML
    // requires 2 arrays. $tree array contains the top parent folders
    //  and $children array contains all other folders which are not the top parents i.e. all the children
    // and grandchildren and so on.  
    function findChildren($tree, $children){
        $message = "";
    
        foreach($tree as $folder){
            $parent = array();
            if($folder['parentId'] === null) {
                $message .= "<li id='" . $folder['folderId'] . "'>" . $folder['folderName'] . " " . $folder['folderId'];
            }
            $i = 0;
            foreach ($children as $child) {
                if ($child['parentId'] === $folder['folderId']) {
                    if (($childKey = array_search($child, $children)) !== false) {
                        if($i === 0){
                            $message .= "<ul>";
                        }
                        $message .= "<li>" . $child['folderName'] . " " . $child['folderId'];
                        $parent[$i] = $children[$childKey];
                        unset($children[$childKey]);
                        $message .= "</li>";
                    }
                    $i++;
                }
            }
            if(isset($parent[0])) {
                $message .= findChildren($parent, $children);
            }
            if($i > 0){
                $message .= "</ul>";
            }
            if($folder['parentId'] === null) {
                $message .= "</li>";
            }
        }
        return $message;
    }
    
    // Searches through DB for user folders and returns whatever findChildren() returns.
    // requires a $userID as int
    function getDirTree($userId){
        global $mysqli;
    
        $children = array();
        $tree = array();
    
        if($folders = $mysqli->prepare("SELECT folders.id, folders.name, child_of_folder.parent_id
                                                FROM child_of_folder
                                                RIGHT JOIN folders
                                                ON  (child_of_folder.child_id = Folders.id)
                                                WHERE folders.user_id = ?;")) {
            // Bind the parameters...  s for String and the variable $name to be bound.
            if ($folders->bind_param("i", $userId)) {
                // execute the query
                if ($folders->execute()) {
                    // store the results
                    if($folders->store_result()){
                        // bind the results
                        if($folders->bind_result($folderId, $folderName, $parentId)) {
                            // Fetch the results
                            while ($folders->fetch()) {
                                if ($parentId === null) {
                                    array_push($tree, array('folderId' => $folderId, 'folderName' => $folderName, 'parentId' => $parentId));
                                } else {
                                    array_push($children, array('folderId' => $folderId, 'folderName' => $folderName, 'parentId' => $parentId));
                                }
                            }
                        } else {
                            $hasFolder = null;
                        }
                    } else {
                        // if there were no values to store return false
                        $hasFolder = null;
                    }
                } else {
                    // if there was a problem executing the statement return null
                    $hasFolder = null;
                }
            } else {
                // if there was a problem binding the statement return null
                $hasFolder = null;
            }
        } else {
            // if there was a problem preparing the statement return null
            $hasFolder = null;
        }
        // Call findChildren
        $message = findChildren($tree, $children);
    
        // Add the surrounding block elements which would ideally be placed in the template to separate php logic and html 
        if ($message != ""){
            $message = "<ul>" . $message;
            $message .= "</ul>";
        } else {
            $message .= "No Folders Created";
        }
    
        $folders->free_result();
        $mysqli->close();
    
        return $message;
    }