使用 PHP 将 Mysql Select 转换为独立于级别的目录结构的多维数组
Converting Mysql Select to Multidimensional Array of Directory Structure independent of levels using PHP
所以我有一个 select 语句,其中 returns 3 个来自数据库的值:
- 文件夹 ID,
- 文件夹名称,
- 家长 ID。
如果文件夹没有父文件夹,它 returns 父 ID 为空。
使用这些数据,我将结果分成了 2 个数组。
一个名为$tree
,将用作"directory 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] =>
)
)
我认为这应该可行。我更改为 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);
}
}
}
我最终通过不将菜单项放在多维数组中解决了这个问题。
我正在寻找的最终结果是将数据库查询转换为 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;
}
所以我有一个 select 语句,其中 returns 3 个来自数据库的值:
- 文件夹 ID,
- 文件夹名称,
- 家长 ID。
如果文件夹没有父文件夹,它 returns 父 ID 为空。
使用这些数据,我将结果分成了 2 个数组。
一个名为$tree
,将用作"directory 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] =>
)
)
我认为这应该可行。我更改为 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);
}
}
}
我最终通过不将菜单项放在多维数组中解决了这个问题。
我正在寻找的最终结果是将数据库查询转换为 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;
}