3

问题:

我试图通过使用一个类来删除一个类别的所有子级别。目前我只能让它删除两个子级别,而不是三个。

数据库表:

CREATE TABLE betyg_category (
  CID int(11) NOT NULL AUTO_INCREMENT,
  Item varchar(100) NOT NULL,
  Parent int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (CID)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

PHP 类:

<?php
class ItemTree 
{ 
   var $itemlist = array();

   function ItemTree($query)
   {
      $result = mysql_query($query) or die ('Database Error (' . mysql_errno() . ') ' . mysql_error());

      while ($row = mysql_fetch_assoc($result)) 
      {
         $this->itemlist[$row['CID']] = array(
           'name'   => $row['Name'],
           'parent' => $row['Parent']
         );
      }
   }

   function get_tree($parent, $with_parent=0)
   {
      $item_tree = array();

      if ($with_parent == 1 && $parent != 0) 
      {
         $item_tree[$parent]['name'] = $this->itemlist[$parent]['name'];
         $item_tree[$parent]['parent'] = $this->itemlist[$parent]['parent'];
         $item_tree[$parent]['child'] = $this->get_tree($parent);

         return $item_tree;
      }

      foreach ($this->itemlist as $key => $val) 
      {
         if ($val['parent'] == $parent) 
         {
               $item_tree[$key]['name'] = $val['name'];
               $item_tree[$key]['parent'] = $val['parent'];
               $item_tree[$key]['child'] = $this->get_tree($key);
         }
      }

      return $item_tree;
   }

   function make_optionlist ($id, $class='', $delimiter='/')
   {
      $option_list = '';

      $item_tree = $this->get_tree(0);

      $options = $this->make_options($item_tree, '', $delimiter);

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

      foreach($options as $row) 
      {
         list($index, $text) = $row;
         $selected = in_array($index, $id) ? ' selected="selected"' : '';
         $option_list .= "<option value=\"$index\" class=\"$class\"$selected>$text</option>\n";
      }

      return $option_list;
   }

   function make_options ($item_tree, $before, $delimiter='/')
   {
      $before .= empty($before) ? '' : $delimiter;

      $options = array();

      foreach ($item_tree as $key => $val) 
      {
         $options[] = array($key, '-&nbsp;'.$before.$val['name']);
         if (!empty($val['child'])) {
            $options = array_merge($options, $this->make_options($val['child'], $before.$val['name'], $delimiter));
         }
      }

      return $options;
   }

   function get_navlinks ($navid, $tpl, $startlink='', $delimiter=' &raquo; ')
   {
      // $tpl typ: <a href="index.php?id={id}" class="navlink">{name}</a>

      $search = array('{id}', '{name}');

      $navlink = array();

      while (isset($this->itemlist[$navid])) 
      {
         $replace = array($navid, $this->itemlist[$navid]['name']);
         $navlink[] = str_replace($search, $replace, $tpl);
         $navid = $this->itemlist[$navid]['parent'];
      }

      if (!empty($startlink)) 
      {
         $navlink[] = str_replace($search, array(0, $startlink), $tpl);
      }

      $navlink = array_reverse($navlink);

      return implode($delimiter, $navlink);
   }

   function show_tree ($parent=0, $tpl='%s', $ul_class='', $li_class='')
   {
      $item_tree = $this->get_tree($parent);

      return $this->get_node($item_tree, $parent, $tpl, $ul_class, $li_class);
   }

   function get_node ($item_tree, $parent, $tpl, $ul_class, $li_class)
   {
      // $tpl typ: <a href="item.php?id={id}" class="treelink" style="color:blue">{name}</a>

      $search = array('{id}', '{name}'); 

      $output = "\n<ul class=\"$ul_class\">\n";

      foreach ($item_tree as $id => $item) 
      {
         $replace = array($id, $item['name']);
         $output .= "<li class=\"$li_class\">".str_replace($search, $replace, $tpl);
         $output .= !empty($item['child']) ? "<br />".$this->get_node ($item['child'], $id, $tpl, $ul_class, $li_class) : '';
         $output .= "</li>\n";
      }

      return $output . "</ul>\n"; 
   }

   function get_id_in_node ($id)
   {
      $id_list = array($id);

      if (isset($this->itemlist[$id])) 
      {
         foreach ($this->itemlist as $key => $row) 
         {
            if ($row['parent'] == $id) 
            {
               if (!empty($row['child'])) 
               {
                 $id_list = array_merge($id_list, get_id_in_node($key));
               } else 
               {
                 $id_list[] = $key;
               }
            }
         }

      }
      return $id_list;
   }

   function get_parent ($id)
   {
      return isset($this->itemlist[$id]) ? $this->itemlist[$id]['parent'] : false;
   }

   function get_item_name ($id)
   {
      return isset($this->itemlist[$id]) ? $this->itemlist[$id]['name'] : false;
   }
}
?>

设想:

假设您在 a 中有以下结构:

  • 文学
  • -- 资源整合
  • ---- 测试一

它将在数据库表中产生以下结果:

类别

当我尝试删除此子级别时,它将保留数据库中的最后一个子级别,而应将其删除。结果将是:

已删除的类别

PHP代码:

//Check if delete button is set
if (isset($_POST['submit-deletecategory'])) 
{
    //Get $_POST variables for category id
    $CategoryParent = intval($_POST['CategoryList']);

    //Check if category is selected
    if ($CategoryParent != "#") 
    {
        //Get parent category and subsequent child categories
        $query = "SELECT CID, Item AS Name, Parent FROM " . TB_CATEGORY . " ORDER BY Name";
        $items = new ItemTree($query);

        if ($items->get_item_name($_POST['CategoryList']) !== false) 
        {
            //Build up erase list
            $CategoryErase = $items->get_id_in_node($CategoryParent);
            $CategoryEraseList = implode(", ", $CategoryErase);
        } 
        else 
        {
            $CategoryEraseList = 0;
        }

        //Remove categories from database
        $query = "DELETE FROM " . TB_CATEGORY . " WHERE CID IN ($CategoryEraseList)";
        $result = mysql_query($query) or die ('Database Error (' . mysql_errno() . ') ' . mysql_error());

       //Return a confirmation notice
       header("Location: settings.php");
       exit;
    }
}

预先感谢您为我提供解决问题的任何指导。

4

3 回答 3

3

这是一种方法:使用递归函数,它将首先查找叶项(树中最深的项)。您首先删除子项,然后是父项。对于每个孩子,您首先删除孩子的孩子,等等......

deleteSub(1);

function deleteSub($cat_id) {
    $request = "SELECT * FROM ". TB_CATEGORY ." WHERE Parent = ".$cat_id;
    $results = mysql_query($request);
    while($child = mysql_fetch_array($results)) 
    {
        deleteSub($child["CID"]);
    }
    $request = "DELETE FROM ". TB_CATEGORY ." WHERE CID = ".$cat_id;
    return mysql_query($request);
}

更好的方法是使用这种递归函数将 CID 存储在数组中,然后发出单个 DELETE 请求,但我认为您将能够调整此代码。

于 2012-06-03T10:03:35.263 回答
2

我不会阅读或尝试理解整个代码,但在我看来,您需要某种递归函数。我基本上会做的是创建一个在层次结构中上升和下降的函数。

注意:我已经有一段时间没有在procedural mysql中写任何东西了,所以请检查mysql_num_rows(),mysql_fetch_array等是否以正确的方式写入

编辑:我刚刚注意到您只想向下删除,因此 zessx 的答案更有效

<?php
function recursiveParent($id) {
    $sql = 'SELECT parent FROM betyg_category WHERE CID=' . $id;
    $result = mysql_query($sql);

    if(mysql_num_rows($result) > 0) {
        while($r = mysql_fetch_array($result,MYSQLI_ASSOC)) {
            recursiveParent($r['parent']);
        }
    }

    $sql = 'DELETE FROM betyg_category WHERE CID=' . $id;
    mysql_query($sql);
}

function recursiveChild($parent) {
    $sql = 'SELECT CID FROM betyg_category WHERE parent=' . $parent;
    $result = mysql_query($sql);

    if(mysql_num_rows($result) > 0) {
        while($r = mysql_fetch_array($result,MYSQLI_ASSOC)) {
            recursiveChild($r['CID']);
        }
    }

    $sql = 'DELETE FROM betyg_category WHERE parent=' . $parent;
    mysql_query($sql);
}

function delete($id) {
    recursiveParent($id);
    recursiveChild($id);
}
?>
于 2012-06-03T10:10:42.190 回答
1

这是我的做法。我不是递归运行查询,而是先获取所有孩子的 id,然后只运行查询。这里的代码是指: -

首先,将一个名为 $delete_node_list 的变量定义为数组。(存储所有需要删除的节点ID)

function delete_child_nodes($node_id)
{           
    $childs_node = $this->edirectory_model->get_child_nodes($node_id);


    if(!empty($childs_node))
    {
        foreach($childs_node as $node)
        {
            $this->delete_child_nodes($node['id']);
        }   
    }

    $this->delete_node_list[] = $node_id;
}

在 mysql..

 $sql = 'DELETE FROM betyg_category WHERE CID IN '.$this->delete_node_list;
 mysql_query($sql);
于 2015-04-10T03:43:47.093 回答