将 PHP MYSQL 中的类别 Table 中的所有热门类别作为 Optgroup

Putting All Top Categories as Optgroup from Category Table in PHP MYSQL

我几乎无法将所有顶级类别放入 Optgroup,尝试了几种方法,从 Whosebug 中获取了很多参考资料,但未能按照我的要求实现。

参考了 here 并构建了我的嵌套类别:

function fetchCategoryTree($parent = 0, $spacing = '', $user_tree_array = '') {
    global $conn;

    if (!is_array($user_tree_array)) {
        $user_tree_array = array();
    }

    $sql = "SELECT `id`, `name`, `parent_id` FROM `acct_categs` WHERE `parent_id` = '".$parent."' ORDER BY `name` ASC";
    $query = $conn->Execute($sql);

    if (count($query) > 0) {
        $current_parent = '';
        while ($row = $query->FetchRow()) {
            $user_tree_array[] = array("catid" => $row['id'], "catname" => $spacing . $row['name']);
            $user_tree_array = fetchCategoryTree($row['id'], $spacing . '- ', $user_tree_array);
        }
    }
    return $user_tree_array;
}

function categoryoption(){
    $categoryList = fetchCategoryTree();
    $dropdown = '<select name="category_id">';
    foreach($categoryList as $cl) {
        $dropdown .= "\n<option value=\"".$cl["catid"]."\">".$cl["catname"]."</option>";
    }

    $dropdown .= "</select>";
    return $dropdown;
}

echo categoryoption();

所以当我回应这个时,我得到以下下拉列表:

<select name="category_id">
<option value="91">Assets</option>
<option value="3">-&nbsp;Capital Assets</option>
<option value="23">-&nbsp;-&nbsp;Accum. Amort. -Furn. &amp; Equip.</option>
<option value="25">-&nbsp;-&nbsp;Accum. Amort. -Vehicle</option>
<option value="22">-&nbsp;-&nbsp;Office Furniture &amp; Equipment</option>
<option value="24">-&nbsp;-&nbsp;Vehicle</option>
<option value="1">-&nbsp;Current Assets</option>
<option value="15">-&nbsp;-&nbsp;Accounts Receivables</option>
<option value="16">-&nbsp;-&nbsp;Allowance for doubtful accounts</option>
<option value="13">-&nbsp;-&nbsp;Checking Account</option>
....</select>

我想要的是这样的,https://jsfiddle.net/sbnzp1wL/

<select name="category_id">
<optgroup label="Assets"></optgroup>
<optgroup label="Capital Assets"></optgroup>
<option value="23">-&nbsp;-&nbsp;Accum. Amort. -Furn. &amp; Equip.</option>
<option value="25">-&nbsp;-&nbsp;Accum. Amort. -Vehicle</option>
<option value="22">-&nbsp;-&nbsp;Office Furniture &amp; Equipment</option>
<option value="24">-&nbsp;-&nbsp;Vehicle</option>
<optgroup label="Current Assets"></optgroup>
<option value="15">-&nbsp;-&nbsp;Accounts Receivables</option>
<option value="16">-&nbsp;-&nbsp;Allowance for doubtful accounts</option>
<option value="13">-&nbsp;-&nbsp;Checking Account</option>
<option value="14">-&nbsp;-&nbsp;Petty Cash</option>
....</select>

我读到它在 Whosebug 中的嵌套查询中是不可能的,但我也从 here 中了解到它是可能的。

但是有了 link 的帮助,我的顶级类别列出了二级类别,二级类别列出了它的子类别。不知何故,我也没有达到我想要的。

我的 table 值是 here


终于按照我的需要让它工作了,如果有人需要它,我把它贴在这里...非常感谢@stj(答案被接受并投票)

$sql = "SELECT `id`, `name`, `parent_id` FROM `acct_categs` ORDER BY `name` ASC";
$query = $conn->Execute($sql);
// build a lookup array with all elements
$all = array();
$hasChildren = array();
while ($row = $query->FetchRow()) {
    $all[$row["id"]] = $row;
    $hasChildren[$row["parent_id"]] = true;
}

// recursive processing function
function process($rows, $hasChildren, $parentId, $level = 0) {
    foreach ($rows as $id => $row) {

        if ($row["parent_id"] === $parentId) {
            // this is the element we are looking for
            $pad = str_repeat("  ", $level);

            if (isset($hasChildren[$id])) {
                // the element has children
                $line = "\n<optgroup label=\"{$row["name"]}\"></optgroup>";
                //$line = $pad . $row["id"] . " - " . $row["name"] . " (has children)";
            } else {
                // the element does not have any children
                $line = "\n<option value=\"{$row["id"]}\">{$row["name"]}</option>";
                //$line = $pad . $row["id"] . " - " . $row["name"] . " (no children)";
            }
            // print it
            print $line . "\n";
            // finally process the children

            if (isset($hasChildren[$id])) {
                process($rows, $hasChildren, $id, $level + 1);
            }
        }
    }
}

echo '<select name="category_id">';
// start processing    
$print = process($all, $hasChildren, "0");
echo $print;
echo '</select>';

获取所有带有 parent_id = 0 的猫,然后循环它,并得到 child。 Parent <optgroup></optgroup> 中的类别 wrapp,<option></option> 中的 child。

尝试将 parent ID 检查添加到您的 $categoryList 循环中:

function fetchCategoryTree($parent = 0, $spacing = '', $user_tree_array = '') {
    global $conn;

    if (!is_array($user_tree_array)) {
        $user_tree_array = array();
    }

    $sql = "SELECT `id`, `name`, `parent_id` FROM `acct_categs` WHERE `parent_id` = '".$parent."' ORDER BY `name` ASC";
    $query = $conn->Execute($sql);

    if (count($query) > 0) {
        $current_parent = '';
        while ($row = $query->FetchRow()) {
            $user_tree_array[] = array("catid" => $row['id'], "catname" => $spacing . $row['name'], "parentid" => $row['parent_id']);
            $user_tree_array = fetchCategoryTree($row['id'], $spacing . '-&nbsp;', $user_tree_array);
        }
    }
    return $user_tree_array;
}

function categoryoption(){
    $categoryList = fetchCategoryTree();
    $dropdown = '<select name="category_id">';
    foreach($categoryList as $cl) {
        if ($c1["parentid"] == '0') {
            $dropdown .= "\n<optgroup label=\"".$cl["catname"]."\"></optgroup>";
        } else {
            $dropdown .= "\n<option value=\"".$cl["catid"]."\">".$cl["catname"]."</option>";
        }
    }

    $dropdown .= "</select>";
    return $dropdown;
}

echo categoryoption();

您可能正在寻找的是呈现嵌套数据的深度优先递归。

我建议使用单个查询从数据库中查询所有值并在 PHP 中处理它们。这样可以避免发出大量单独的数据库查询(每个元素一个)。

查询完所有相关行后,您可以递归地遍历它们 PHP。 这是一些可以做到这一点的代码。

$sql = "SELECT `id`, `name`, `parent_id` FROM `acct_categs` ORDER BY `name` ASC";
$query = $conn->Execute($sql);

// build a lookup array with all elements
$all = array();
$hasChildren = array();

while ($row = $query->FetchRow()) {
  $all[$row["id"]] = $row;
  $hasChildren[$row["parent_id"]] = true;
}

// recursive processing function
function process($rows, $hasChildren, $parentId, $level = 0) {
  foreach ($rows as $id => $row) {
    if ($row["parent_id"] === $parentId) {
      // this is the element we are looking for
      $pad = str_repeat("  ", $level);
      if (isset($hasChildren[$id])) {
        // the element has children
        $line = $pad . $row["id"] . " - " . $row["name"] . " (has children)";
      }
      else {
         // the element does not have any children
        $line = $pad . $row["id"] . " - " . $row["name"] . " (no children)";
      }

      // print it
      print $line . "\n";

      // finally process the children
      if (isset($hasChildren[$id])) {
        process($rows, $hasChildren, $id, $level + 1);
      }
    }
  }
}

// start processing    
process($all, $hasChildren, 0);

请注意,它不会打印嵌套的 optgroup。原因是我不确定 optgroups 应该去哪里。我认为 optgroup 元素不应该嵌套。但是,如果您真的想这样做,请继续。

此外,您可能需要根据需要调整填充 $line 的代码部分。

我喜欢一次查询所有值并使用合并对它们进行排序。这是我用过的最简单的选项。

<label>Category<br>
    <select name="category_id">
        <option value="0"> -- Choose Category -- </option>
<? 
        //All Categories
        $sql = "SELECT id, parent_id, name FROM acct_categs ORDER BY COALESCE((SELECT NULLIF(parent_id,0)), id), NULLIF(parent_id,0)";
        $catQuery = $conn->Execute($sql);
        if($catQuery->num_rows > 0) { 
            while($cat = $catQuery->fetch_object()){ 

                if($cat->parentId == 0){

                    echo '<optgroup label="'.$cat->title.'"></optgoup>';

                } else { 

                    echo '<option value="'.$cat->id.'">'.$cat->title.'</option>'; 

                }
            }
        }    
?>
    </select>
</label>