轉自:PHP在無限分類時註意的一些問題(http://lxiaoke.cn) (註意:代碼使用的是原生PHP,旨在提供解決思路)1 無限分類的查找(獲取所有節點) 代碼: /** * 無限分類查詢,預設 pid 為 0 * @param $pid * @return array $res */ pr ...
轉自:PHP在無限分類時註意的一些問題(http://lxiaoke.cn) (註意:代碼使用的是原生PHP,旨在提供解決思路)
1 無限分類的查找(獲取所有節點)
代碼:
/** * 無限分類查詢,預設 pid 為 0 * @param $pid * @return array $res */ protected function selectTree($pid = 0) { $res = []; $sql = "SELECT * FROM " . $this->tbname . " WHERE pid=" . $pid; $result = @mysqli_query($this->link, $sql); if ($result) { $count = mysqli_num_rows($result); if ($count > 0) { while ($rows = mysqli_fetch_assoc($result)) { $rows['children'] = $this->selectTree($rows['id']); $res[] = $rows; } } mysqli_free_result($result); } return $res; }
2 無限分類節點的刪除,不能單純地刪除當前節點,需要查找到當前節點下的所有子節點,一併刪除
代碼:
/** * 刪除目錄樹 * @param $id */ protected function deleteTree($id) { $res = $this->selectTree($id); if (!empty($res)) { foreach ($res as $v) { $this->deleteTree($v['id']); } } $sql = "DELETE FROM " . $this->tbname . " WHERE id=" . $id; mysqli_query($this->link, $sql); }3 **無限分類的編輯,由於在編輯的時候其父級是可選擇的,所以有可能造成用戶選擇到當前節點的子節點(們),所以要進行判斷。雖說是無限分類,但正常情況下目錄深度是會有限度的,如果給定了目錄深度,還要判斷選擇父級之後的目錄深度是否超出範圍。
如果將編輯的元素放在其子元素下,所造成的問題:在查詢的時候無限迴圈!!
id |
pid |
name |
1 |
0 |
test1 |
2 |
1 |
test2 |
修改之後:
id |
pid |
name |
1 |
2 |
test1 |
2 |
1 |
test2 |
如上表所示,在進行無限分類查詢時,就會陷入死迴圈!
所以,針對可能會出現的問題,給出下麵的解決辦法,在用戶修改時進行判斷,通過則可以修改,未通過則給出提示。
3.1 判斷用戶選擇的是否是當前節點(這個只需要判斷選擇的節點和當前編輯節點的ID是否相同即可)
3.2 判斷用戶選擇的是否是子節點(如果是的話返回true)
/** * 判斷id所對應的元素是否是pid所對應元素的子元素,是的話返回true * @param $id * @param $pid * @return boolean $result */ protected function isChild($id, $pid) { $result = false; $sql = "SELECT pid FROM " . $this->tbname . " WHERE id=" . $id; $res = @mysqli_query($this->link, $sql); if ($res) { while ($rows = mysqli_fetch_assoc($res)) { $result = ($pid === $rows['pid']) ? true : (($rows['pid'] !== 0) ? $this->isChild($rows['pid'], $pid) : false); } } return $result; }
3.3 判斷用戶選擇的節點是否已經達到目錄深度
在做完後面的一步之後,這一步就比較好實現了:
/** * 判斷所選元素是否達到目錄深度,達到返回true * @param $id * @return mixed */ protected function isMaxDeep($id) { return $this->deepUp($id) >= $this->maxDeep; }
3.4 判斷修改之後的目錄深度是否超出限定範圍
/** * 修改之後的最終深度,如果深度大於規定深度,返回true * @param $pid * @param $id * @return mixed */ protected function lastDeep($pid, $id) { return ($this->deepUp($pid) + $this->deepDown($id)) > $this->maxDeep; } /** * 向上查找父元素的深度 * @param $id * @param int $k * @return int */ protected function deepUp($id, $k = 1) { $sql = "SELECT pid FROM " . $this->tbname . "WHERE id=" . $id; $res = @mysqli_query($this->link, $sql); if ($res) { while ($rows = mysqli_fetch_assoc($res)) { ($rows['pid'] !== 0) && $k = $this->deepUp($rows['pid'], $k+1); } } return $k; } /** * 向下查找子元素的深度 * @param $id * @param int $k * @return int */ protected function deepDown($id, $k = 0) { $sql = "SELECT * FROM " . $this->tbname . "WHERE pid=" . $id; $res = @mysqli_query($this->link, $sql); if ($res && mysqli_num_rows($res) > 0) { $k++; while ($rows = mysqli_fetch_assoc($res)) { $k = max($k, $this->deepDown($rows['id'], $k)) } } return $k; }
經過上面的判斷之後,根據返回的結果就能判斷是否可以修改,如果返回true,則不可以修改,如果是false則可以進行修改。
(如果不用無限分類查詢,只是普通的查詢,讓前端去實現結果的顯示會怎麼樣呢??不懂那些框架是怎麼實現的,感覺也是在用遞歸)