我尝试创建一系列<ul>
和<li>
来创建目录/文件结构,以导航从dB中的表创建的某些文件。表(tb_lib_manual)包含文件和文件夹。
如果记录的fileID为空条目,则它是文件夹而不是文件。每条记录都有一个parentID来显示哪个文件夹是父文件夹,对于根目录中的文件和文件夹是0。
php代码因此:
class library_folders extends system_pageElement
{
private $html = '';
private $i = 0;
private $stmtArray = array();
private $objectArray = array();
function __construct()
{
parent::__construct();
$this->nextList();
}
function nextList($parentID = 0)
{
$qSQL = 'SELECT * FROM tb_lib_manual WHERE parentID=:parentID';
$stmtArray[$this->i] = $this->dbConnection->prepare($qSQL);
$stmtArray[$this->i]->bindValue(':parentID', $parentID, PDO::PARAM_INT);
$stmtArray[$this->i]->execute();
if($stmtArray[$this->i]->rowCount() > 0)
{
$display ='';
if($parentID != 0)
{
$display = ' style="display:none"';
}
$this->html .= '<ul' . $display . '>';
}
while ($this->objectArray[$this->i] = $stmtArray[$this->i]->fetchObject())
{
$this->html .= '<li>' . $this->objectArray[$this->i]->title;
if($this->objectArray[$this->i]->fileID == null)
{
//we have a folder!
$manualID = $this->objectArray[$this->i]->manualID;
$this->i ++;
$this->nextList($manualID);
$this->i--;
}
$this->html .= '</li>';
}
if($stmtArray[$this->i]->rowCount() > 0)
{
$this->html .= '</ul>';
}
echo $this->html;
}
function __destruct()
{
parent::__destruct();
}
}
问题是当代码在调用自身之后返回到while循环时它重新启动循环而不是继续它停止的地方,导致子文件夹中的重复。有没有更好的方法来做到这一点,或者我做错了什么!?
表格如下:
输出如下: &#39;
答案 0 :(得分:1)
修正了代码,非常愚蠢的错误,在错误的地方回声......
class library_folders extends system_pageElement
{
private $html = '';
private $i = 0;
private $stmtArray = array();
private $objectArray = array();
function __construct()
{
parent::__construct();
$this->nextList();
echo $this->html;
}
function nextList($parentID = 0)
{
$qSQL = 'SELECT * FROM tb_lib_manual WHERE parentID=:parentID';
//echo $this->i;
$stmtArray[$this->i] = $this->dbConnection->prepare($qSQL);
$stmtArray[$this->i]->bindValue(':parentID', $parentID, PDO::PARAM_INT);
$stmtArray[$this->i]->execute();
if($stmtArray[$this->i]->rowCount() > 0)
{
$this->html .= '<ul>';
}
while ($this->objectArray[$this->i] = $stmtArray[$this->i]->fetchObject())
{
$this->html .= '<li>' . $this->objectArray[$this->i]->title;
if($this->objectArray[$this->i]->fileID == null)
{
//we have a folder!
$manualID = $this->objectArray[$this->i]->manualID;
$this->i ++;
$this->nextList($manualID);
$this->i--;
}
$this->html .= '</li>';
}
if($stmtArray[$this->i]->rowCount() > 0)
{
$this->html .= '</ul>';
}
}
function __destruct()
{
parent::__destruct();
}
}
答案 1 :(得分:0)
是的,有更好的方法可以做到这一点。
如果你每次都获取整个树,你也可以将所有节点加载到一个大数组(对象)中,将每个节点的id作为索引,然后在数组上循环一次例如,通过
创建父引用// create a fake root node to start your traversal later on
// only do this if you don't have a real root node
// which I assume you don't
$root = (object) ["children" => []];
// loop over all nodes
foreach ($nodes as $node)
{
// if the node has a parent node that is not root
if ($node->parentId > 0)
{
// put it into it's parent's list of children
$nodes[ $node->parentId ]->children[] = $node;
}
else
{
// otherwise put it into root's list of children
$root->children[] = $node;
}
}
复杂性:您执行一个查询,并且必须迭代所有节点一次。
为此,您的节点需要是对象。否则,对$node->children
的每个分配都将创建您想要引用的已分配节点的副本。
<强> 如果您不想获取所有节点,则可以通过创建上一级别的节点ID列表逐级浏览树。
function fetchLevel ($nodes, $previousLevelIds)
{
// get all children from the previous level's nodes
// I assume $previousLevelIds to be an array of integers. beware of sql injection
// I refrained from using prepared statements for simplicity
$stmt = $pdo->query("SELECT id, parentId FROM nodes WHERE parentId IN (".implode(",",$previousLevelIds).")");
// fetch nodes as instances of stdclass
$currentLevelNodes = $stmt->fetchAll(PDO::FETCH_OBJ);
$nextLevelIds = [];
foreach ($currentLevelNodes as $node)
{
// ids for next level
$nextLevelIds[] = $node->id;
// parent <-> child reference
$nodes[ $node->parentId ]->children[] = $node;
}
// fetch the next level only if we found any nodes in this level
// this will stop the recursion
if ($nextLevelIds)
fetchLevel($nodes, $nextLevelIds);
}
// start by using a fake root again
$root = (object) ["id" => 0, "children" => []];
$nodes = [0 => $root];
fetchLevel($nodes, [0]);
// or start with a specific node in the tree
$node = $pdo->query("SELECT id, parentId FROM nodes WHERE id = 1337")->fetch(PDO::FETCH_OBJ);
$nodes = [$node->id => $node];
fetchLevel($nodes, [$node->id]);
// or a number of nodes which don't even have to
// be on the same level, but you might fetch nodes multiple times
// if you it this way
复杂性:查询数&lt; =树的高度。您只迭代每个获取的节点一次。
要将树显示为html列表,您需要再次迭代:
class Foo {
public $html;
public function getList ($nodes)
{
// outer most ul
$this->html = '<ul>';
$this->recurseList($nodes);
$this->html .= '</ul>';
}
protected function recurseList ($nodes)
{
foreach ($nodes as $node)
{
$this->html .= "<li><span>".$node->name."</span>";
if ($node->children)
{
if ($node->parentId > 0)
$this->html .= '<ul style="display:none">';
else
$this->html .= '<ul>';
$this->recurseList($node->children);
$this->html .= "</ul>";
}
$this->html .= "</li>";
}
}
}
一些不相关的评论:
style="display:none"
您只需使用ul li ul {display:none}
等css规则隐藏根目录下的所有列表