我试图在<select>
元素中实现以下输出。
Mouses
Logitech
Red
White
Microsoft
Black
Keyboards
Logitech
Small size
Red
Green
Medium size
Black
正如您所看到的,可能存在不定级别。 在我的MySQL数据库中,我创建了一个表类别:
id
description
category_parent_id
输入非常简单。
1 Mouses null
2 Logitech 1
3 Red 2
4 White 2
5 Keyboards null
6 Logitech 5
等等。正如您所看到的那样,第一个类别被设置为null
以识别原点。
// Disables duplicated categories
$alreadyOutput = array();
foreach($categories as $category)
{
if(in_array($category->id, $alreadyOutput) == FALSE)
{
echo '<option value="' . $category->id . '">';
echo $category->description;
echo '</option>';
}
foreach($categories as $subCategory)
{
if($subCategory->category_parent_id == $category->id &&
in_array($subCategory->id, $alreadyOutput) == FALSE)
{
echo '<option value="' . $subCategory->id . '">';
echo ' ' . $subCategory->description;
echo '</option>';
}
}
}
使用此代码我的输出是:
Mouses
Logitech
Red
White
Microsoft
Black
Keyboards
Logitech
Small size
Red
Green
Medium size
Black
我明白为什么。
首先,空格   
只进行一次,并应根据级别递增。我试图通过创建两个函数来提出解决方案。第一个确定了为达到原点而需要执行的步骤数量。
function stepsToJump($categories, $id, $category_parent_id)
{
$parentPosition = 0;
$position = 0;
foreach($categories as $i => $category)
{
if($category->id == $category_parent_id)
$parentPosition = $i;
if($category->id == $id)
$position = $i;
}
return $position - $parentPosition;
}
function htmlSpaces($amount)
{
$html = ' '; // default
for($i = 0; $i < $amount; $i++)
$html .= ' ';
return $html;
}
有了这个,我就用这种方式实现了:
echo htmlSpaces(stepsToJump($categories,
$subCategory->id,
$category->id)) . $subCategory->description;
不幸的是我的输出错了。
Mouses
Logitech
Red
White
Microsoft
Black
Keyboards
Logitech
Small size
Red
Green
Medium size
Black
答案 0 :(得分:0)
我发现从头开始编写比调试代码更容易。以下代码按预期工作。
$dbh = new PDO('---connection string---');
$stmt_categories = $dbh->prepare("SELECT * FROM categories");
$stmt_categories->execute();
$categories = $stmt_categories->fetchAll(PDO::FETCH_ASSOC);
$allCategories = $categories;
$lastParent = NULL; // we will use this variable to place categories under their parents.
print '<select>';
while (count($categories) > 0) { // we use this control, because we will unset elements from $categories. until $categories array is empty, following foreach loop will run continously.
foreach ($categories as $i => $category) {
if ($category['category_parent_id'] == $lastParent) { // by using this control, we will be sure output starts with a top level category.
if ($category['category_parent_id'] == NULL) {
$indent = 0; // since this is a top level category, indent is 0.
}
print '<option value="' . $category['id'] . '">';
print str_repeat(' ', ($indent)) . $category['description'];
print '</option>';
if (hasChildren($categories, $category['id']) == TRUE) {
$lastParent = $category['id'];
$indent++; // this is a parent category. so, one of its children is coming on the next iteration. we incremented $indent to be inherited by the child.
}
unset($categories[$i]);
} else {
// ok, this category is not a child of our $lastParent. if all the children of $lastParent are unset from $categories array, this loop will continue forever. so, we are going to control if there are other children of $lastParent.
if (hasChildren($categories, $lastParent) == TRUE) {
continue; // there is still at least one child of $lastParent. it is ok to continue to next iteration.
} else {
// there are no (more) children of $lastParent. so, we need to manipulate this variable. let's check parent of $lastParent on the next iteration.
$lastParent = parentCategory($allCategories, $lastParent);
$indent--;
}
}
}
}
print '</select>';
function hasChildren($categories, $categoryID) {
foreach($categories as $i => $category) {
if ($category['category_parent_id'] === $categoryID) {
return TRUE;
}
}
return FALSE;
}
function parentCategory($categories, $categoryID) {
foreach ($categories as $i => $category) {
if ($category['id'] === $categoryID) {
return $category['category_parent_id'];
}
}
}