如何根据parent_id获取与其他行对应的行,这些行都来自同一个表

时间:2014-06-01 14:45:01

标签: php html mysql

我认为这不是一个简单的方法,但这是我的家庭任务,所以请耐心等待。

我在Mysql 'menu'中有一个表,其结构如下:

id - number  
parent_id - number (0 for root)   
title - string  
link - string  

parent_id与某一行的ID相关联,在这种情况下product1products

example :  

1 | 0 | about    | about.html  
2 | 0 | products | products.html  
3 | 2 | product1 | product1.html  
4 | 2 | product2 | product2.html  
5 | 2 | product3 | product3.html  

我的目标是制作一组看起来像这样的ul

<ul>
    <li><a href="about.html"> about </a></li>
    <li><a href="products.html"> products </a> 
            <ul>
                    <li> <a href="product1.html"> product 1 </a></li>
                    <li> <a href="product1.html"> product 1 </a></li>
                    ...
            </ul>
    </li>
    ...
</ul>

到目前为止,我只做了一个ul

<?php
function getAll() {

 DBconnect();

 $result = mysql_query("SELECT * FROM `menu`");
 $listitems = array();

 while ($li = mysql_fetch_array($result)) {
    $listitems[] = $li;
 }
 return $listitems;
 }

?>
<ul>
        <?php
        include_once 'functions.php';
        $listitems = getAll();
        foreach ($listitems as $listitem) {
        ?>
            <li><a href="<?php print $listitem['link']; ?>"><?php print   $listitem['title']; ?></a></li>

        <?php } ?>
</ul>

这是问题的开始,我无法弄清楚如何制作第二个函数或如何调整它以使“子菜单”行成为ul中的ul

3 个答案:

答案 0 :(得分:2)

如果表中没有大量元素,则很容易解决这个问题。正如Syed Qarib用户所说,你可以检查当前项目是否有一些孩子。

关键是使用parent_id使html的绘制递归。

这是您需要的代码:

<?php
function getElementsByParentId($parent_id) {

     DBconnect();

     $query = sprintf("SELECT * FROM `menu` WHERE parent_id=%s",
     mysql_real_escape_string($parent_id));

     $result = mysql_query($query);

             <!-- Alternative using concat
             $result = mysql_query("SELECT * FROM `menu` WHERE parent_id=".$parent_id);
             -->
     $listitems = array();

     while ($li = mysql_fetch_array($result)) {
        $listitems[] = $li;
     }
     return $listitems;
 }

 function paintChildrens($parent_id) {

    $listitems = getElementsByParentId($parent_id);

    if (count($listitems) > 0) {

        ?>
        <ul>
        <?php       
        foreach($listitems as $listitem) {
            ?>
                <li><a href="<?php print $listitem['link']; ?>"><?php print   $listitem['title']; ?></a></li>
            <?php 
            paintChildrens($listitem['id']);
        }           
        ?>
        </ul>
        <?php
    }       
 }

include_once 'functions.php';
paintChildrens(null) ?>

我不是PHP开发人员,因此有可能此代码存在一些错误,例如空值检查。

答案 1 :(得分:1)

有两种方法可以解决这个问题:
1.递归地从数据库中选择数据(上面提出了这种方法)。这在加载和数据库查询的数量方面是不好的。但是这种方法在代码方面更简单。
2.从表中选择所有记录,并在PHP上形成一个查询树。下面我举例说明如何操作(PHP版本&gt; = 5.4)



    <?php

    function itemsCmd($a, $b)
    {
        return strnatcmp($a['path'], $b['path']);
    }

    function getAll()
    {
        // fetch all from DB
        $itemsRaw = [
            ['id' => 1, 'parent_id' => 0, 'title' => 'about',  'link' => 'about.html'],
            ['id' => 2, 'parent_id' => 0, 'title' => 'products', 'link' => 'products.html'],
            ['id' => 3, 'parent_id' => 2, 'title' => 'product1', 'link' => 'product1.html'],
            ['id' => 4, 'parent_id' => 2, 'title' => 'product2', 'link' => 'product2.html'],
            ['id' => 5, 'parent_id' => 3, 'title' => 'product11', 'link' => 'product11.html'],
            ['id' => 6, 'parent_id' => 4, 'title' => 'product21', 'link' => 'product21.html'],
            ['id' => 7, 'parent_id' => 4, 'title' => 'product22', 'link' => 'product22.html'],
        ];

        // get path for each item (like /1/2/4) and item level from 0 to N
        $items = [];
        foreach ($itemsRaw as $key => $item) {
            $item['path']  = [$item['id']];
            $item['level'] = 0;
            $parentId         = $item['parent_id'];
            while ($parentId) {
                foreach ($itemsRaw as $row) {
                    if ($row['id'] == $parentId) {
                        $newParentId = $row['parent_id'];
                        $item['path'][] = $row['id'];
                        break;
                    }
                }
                $parentId = $newParentId;
                $item['level']++;
            }
            $item['path'] = implode('/', array_reverse($item['path']));
            $items[]     = $item;
        }

        // order items by path
        usort($items, 'itemsCmd');

        return $items;
    }
    ?>

    <ul>
        <? $currentLevel = 0; ?>
        <? foreach (getAll() as $index => $item) :?>
            <?php if ($currentLevel < $item['level']) : ?>
                <ul>
                    <li>
                        <?=$item['title']?>
            <?php elseif ($currentLevel > $item['level']) : ?>
                <? for($i = 0; $i < $currentLevel; $i++) : ?>
                        </li>
                    </ul>
                <? endfor ?>
                <li>
                    <?=$item['title']?>
            <?php else : ?>
                <? if ($index) :?>
                    </li>
                <? endif ?>
                <li>
                    <?=$item['title']?>
            <?php endif ?>
            <? $currentLevel = $item['level']?>
        <? endforeach ?>
        <? for($i = 0; $i < $currentLevel; $i++) : ?>
                </li>
            </ul>
        <? endfor ?>


答案 2 :(得分:1)

尝试:

function menu ( $p )
{
     $hdr = 0;
     foreach ($li in $listitems)
     {
          if ( $li['parent_id'] == $p )
          {
               if ( !$hdr ) { $hdr++; echo "<UL>";
               echo "<LI>...";
               menu( $li['id'] );
          }
     }
     if ( $hdr ) echo "</UL>";
}

使用:

menu( 0 );

代替现有的html生成代码。

这应该适用于任意数量的子菜单级别。