【问题标题】:Converting Mysql Select to Multidimensional Array of Directory Structure independent of levels using PHP使用PHP将Mysql Select转换为独立于级别的目录结构的多维数组
【发布时间】:2016-01-07 16:18:16
【问题描述】:

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

  • 文件夹 ID,
  • 文件夹名称,
  • 家长 ID。

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

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

一个名为$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;   
}

$tree$children 在传递给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] => 
        )

)

【问题讨论】:

    标签: php mysql arrays multidimensional-array directory-structure


    【解决方案1】:

    我认为这应该可行。我更改为 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); 
           }
       }
    }
    

    【讨论】:

    • 感谢您的建议。是的,您的假设是正确的,即 $children 包含数据库中的所有子项。但我看不到 $tree, top parent 文件夹在哪里使用。
    • foreach($tree as $topLevelFolder)
    • 在getFolderStructure中使用
    【解决方案2】:

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

    我一直在寻找的最终结果是将 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2014-08-23
      • 1970-01-01
      • 2016-06-23
      • 1970-01-01
      • 1970-01-01
      • 2011-12-18
      • 2013-10-12
      • 2014-02-28
      • 1970-01-01
      相关资源
      最近更新 更多