【问题标题】:How to fetch menu and sub-menu from database using nested do while loop?如何使用嵌套的 do while 循环从数据库中获取菜单和子菜单?
【发布时间】:2019-10-19 08:11:03
【问题描述】:

我希望有人帮助我编写 php 代码。我想要做的是使用嵌套的 do while 循环从两个表中从数据库中获取菜单和子菜单,以便它显示一个下拉导航栏。导航表包含菜单项,类别表包含子菜单。但是它在获取所有菜单项和第一个菜单项的第一个子菜单项之后在循环的第一次迭代时停止,然后它只显示空结果。

-- Table structure for table `category`
--

CREATE TABLE `category` (
  `cat_id` int(11) NOT NULL,
  `nav_id` int(11) NOT NULL,
  `cat_eng` varchar(256) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `category`
--

INSERT INTO `category` (`cat_id`, `nav_id`, `cat_eng`) VALUES
(1, 1, 'Technology'),
(2, 1, 'Science'),
(3, 1, 'Mathemathics'),
(4, 1, 'Computer'),
(5, 2, 'Geography'),
(6, 2, 'Environment'),
(7, 2, 'Weather'),
(8, 2, 'World'),
(9, 3, 'Sport'),
(10, 3, 'Food'),
(11, 3, 'Health'),
(12, 4, 'Mens'),
(13, 4, 'Womens');

-- --------------------------------------------------------

--
-- Table structure for table `navigation`
--

CREATE TABLE `navigation` (
  `nav_id` int(11) NOT NULL,
  `nav_eng` varchar(256) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `navigation`
--

INSERT INTO `navigation` (`nav_id`, `nav_eng`) VALUES
(1, 'Educational'),
(2, 'General-Knowlege'),
(3, 'Life-style'),
(4, 'Fashion');

连接.php

<?php 
  session_start();

  $host = 'localhost';
  $user = 'root';
  $password = '';
  $dbname = 'test';

  $connection = @mysqli_connect($host, $user, $password, $dbname);

  if (!$connection) {
    die("Connection failed: " . mysqli_connect_error());
  }

  mysqli_set_charset($connection, 'utf8');
 ?>

<div class="collapse navbar-collapse" id="navbarSupportedContent">
          <ul class="navbar-nav mr-auto">

            <!-- FETCHING NAVIGATION LIST ALONG WITH DROPDOWN MENU FROM DATABASE  -->
            <?php
                //SETTING GET PAGES
                if (isset($_GET['nav'])) {
                    $pageid = $_GET['nav'];
                }else {
                    $pageid = 1;
                }

                //NAVIGATION TABLE QUERY
                 $nav_sql = "SELECT * FROM navigation";
                 $nav_query = mysqli_query($connection, $nav_sql);
                 $nav_result = mysqli_fetch_assoc($nav_query);

                 //CATEGORY TABLE QUERY
                  $cat_sql = "SELECT category.*, navigation.nav_id AS id FROM category JOIN navigation ON (category.nav_id = navigation.nav_id) WHERE category.nav_id = " .$pageid;
                  $cat_query = mysqli_query($connection, $cat_sql);
                  $cat_result = mysqli_fetch_assoc($cat_query);
                do {
                  ?> 
                  <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="?nav=<?php echo $nav_result['nav_id'] ?>"> <?php echo $nav_result['nav_eng']; ?></a>
                    <ul class="dropdown-menu">
                      <?php 
                        do { ?>
                          <li>
                            <a class="dropdown-item" href="?nav=<?php echo $cat_result['cat_id']; ?>"><?php echo $cat_result['cat_eng'] ?></a>
                          </li> <?php 
                        } while ($cat_result = mysqli_fetch_assoc($cat_query));
                       ?>
                    </ul>
                  </li> <?php
                } while ($nav_result = mysqli_fetch_assoc($nav_query));

             ?>
          </ul>
         </div>

【问题讨论】:

  • 由于您的$cat_query 在任一循环运行之前执行,因此内部循环的第一轮将从数据库中读取所有记录。第二次周围没有记录可供阅读。您需要在外部循环内执行此查询 - 选择特定项目,或者将 SQL 光标重新定位在开头并重新读取。
  • 嘿奈杰尔!因为我是编码新手,所以我被卡住了。你能提供给我正确的查询吗?!
  • 不确定应该是什么,您在 SQL 末尾有 category.nav_id = " .$pageid,但 $pageid 与您尝试显示的每个单独的菜单有什么关系。如果这是来自navigation 表,则在第一个循环中,获取特定值并使用每个菜单的正确值执行此category 查询。
  • 我设置category.nav-is = .$pageid是因为每个菜单项在导航表中都有它的nav_id,并且类别表的子菜单也有nav_id,所以当点击每个菜单时我希望它根据传递的nav_id动态获取子菜单通过,$_GET[] 方法。所以我设置了这一行 ->``` //SETTING GET PAGES if (isset($_GET['nav'])) { $pageid = $_GET['nav']; }else { $pageid = 1; }```以上
  • 我能否澄清一下:最初您希望将nav_eng 的内容从navigation 表中显示为菜单项。单击时,将获取相关子菜单并显示在该类别标题下。这或多或少是正确的吗?

标签: php mysql nested-loops


【解决方案1】:

使用问题中的表定义和数据,我在让菜单系统在没有嵌套查询的情况下工作并使用DOMDocument 确保正确编写和关闭元素以避免无效 HTML 方面发挥了一些作用。

您可以将自己的值替换为数据库凭据来测试以下内容 - 它应该可以正常工作。我很欣赏这与原版有很大不同,并且还有其他方法可以实现您的目标 - 这只是我在玩游戏,但它可能有用。

<?php

    ob_start();
    ob_implicit_flush();


    /* modify as appropriate */
    $dbhost =   'localhost';
    $dbuser =   'root'; 
    $dbpwd  =   'xxx'; 
    $dbname =   'xxx';

    /* create the db connection */
    try{
        mysqli_report( MYSQLI_REPORT_STRICT );
        $db = new mysqli( $dbhost, $dbuser, $dbpwd, $dbname );
        $db->set_charset( 'utf8' );
    }catch( Exception $e ){
        exit( $e->getMessage() );
    }


    /* a utility function that greatly speeds adding DOM elements with attributes and values */
    function create( $dom, $type, $attr=array(), $parent=NULL ){
        if( $dom && is_object( $dom ) && $type && !empty( $type ) && is_array( $attr ) ){
            $node = $dom->createElement( $type );
            foreach( $attr as $key => $value ){
                if( strtolower( $key )=='text' or strtolower( $key )=='nodevalue' or strtolower( $key )=='value' && $node->tagName!='input' ){
                    if( !is_object( $value ) )$node->nodeValue=$value;
                } else {
                    if( !is_null( $value ) && !is_object( $value ) ) $node->setAttribute( $key, $value );
                }
            }
            if( isset( $parent ) && is_object( $parent ) ) $parent->appendChild( $node );
            return $node;
        }
    }   

?>
<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8' />
        <title>PHP & mySQL Database driven menu</title>
        <style>
            html *{font-family:verdana,arial;}
            a{text-decoration:none;}
            .active_cat{text-decoration:underline;font-style:italic}
            .active_subcat{color:red;font-style:italic}
        </style>
    </head>
    <body>
        <div class='collapse navbar-collapse' id='navbarSupportedContent'>
            <ul class='navbar-nav mr-auto'>
            <!-- this will be populated later -->
            </ul>
        </div>
    </body>
</html>
<?php

    /* capture & filter querystring variables */
    $nav_id=filter_input( INPUT_GET, 'nav', FILTER_SANITIZE_NUMBER_INT );
    $sub_nav_id=filter_input( INPUT_GET, 'subnav', FILTER_SANITIZE_NUMBER_INT );


    /* Create the basic menu of main headings based upon this simple query */
    $sql='select nav_id, nav_eng from navigation order by nav_eng asc';
    $results=$db->query( $sql );



    if( $results ){

        /* Create a new instance of DOMDocument and DOMXPath */
        libxml_use_internal_errors( true );
        $dom=new DOMDocument;
        $dom->loadHTML( ob_get_contents() );
        $xp=new DOMXPath( $dom );
        $col=$xp->query( '//div[ @id="navbarSupportedContent" ]/ul' );

        /* We have loaded the buffer - now clear the old version */
        ob_clean();

        /* We will write new DOM elements to this fragment */
        $fragment=$dom->createDocumentFragment();

        /* Maintain an array of menu items that become parent nodes for child menus */
        $nav=array();


        while( $rs=$results->fetch_object() ){

            /* create the list elemet for this category and add the link and a child `UL` element */
            $li=create( $dom, 'li', array( 'class'=>'nav-item dropdown' ), $fragment );

            /* set the attributes for the hyperlink */
            $options=array( 'class'=>'nav-link dropdown-toggle ', 'text'=>$rs->nav_eng, 'role'=>'button', 'data-toggle'=>'dropdown', 'aria-haspopup'=>'true', 'aria-expanded'=>'false', 'href'=>sprintf( '?nav=%d', $rs->nav_id ) );
            if( $rs->nav_id==$nav_id )$options['class'] .= 'active_cat';
            /* append the hyperlink to the li element */
            $a=create( $dom, 'a', $options, $li );

            /* create the child UL element and assign a reference in the $nav array for later use */
            $ul=create( $dom, 'ul', array( 'data-category'=>$rs->nav_eng, 'data-navid'=>$rs->nav_id, 'class'=>'dropdown-menu' ), $li );

            $nav[ $rs->nav_id ]=$ul;
        }
        /* Add the fragment to the main UL*/
        $col->item(0)->appendChild( $fragment );





        /* If there is a querystring variable `nav` then we query to find child menu items */
        if( $nav_id ){

            $sql='select
                    c.cat_eng, 
                    c.cat_id,
                    c.nav_id
                from category c
                    join navigation n on c.nav_id = n.nav_id
                where c.nav_id=?
                    order by c.cat_eng';
            /* create a prepared statement and bind the nav_id value as input */
            $stmt=$db->prepare( $sql );
            $stmt->bind_param('i', $nav_id );
            $res=$stmt->execute();

            if( $res ){
                /* The query succeeded, generate child menu items */
                $stmt->store_result();
                $stmt->bind_result( $cat, $cid, $nid ); # arbitrary names to correspond to fields in recordset

                /* Find the correct parent node from the array created earlier */
                $parent=$nav[ $nav_id ];


                /* iterate through the recordset & add menu items */
                while( $stmt->fetch() ) {
                    $options=array( 'class'=>'dropdown-item ', 'href'=>sprintf( '?nav=%d&subnav=%d', $nid, $cid ), 'text'=>$cat );
                    if( $cid==$sub_nav_id )$options['class'] .= 'active_subcat';

                    create( $dom, 'a', $options, create( $dom, 'li', array(), $parent ) );
                }

                $stmt->free_result();
                $stmt->close();
            }
        }

        /* render new DOM - the output buffer will now be flushed */
        exit( $dom->saveHTML() );
    }
?>

【讨论】:

猜你喜欢
  • 2019-02-24
  • 1970-01-01
  • 2019-02-18
  • 2014-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-26
  • 1970-01-01
相关资源
最近更新 更多