В общем есть такой вариант решения:
Допустим у нас есть БД 'test' в ней таблица 'tree' с полями: ID, parentID и title (ID узла, ID родительского узла и название соответственно)
функуии вывода структуры дерева и удаления узла вместе со всем поддеревом:
//выводим дерево
function showTree ($parentID = 0) {
$result = ($parentID == 0)? "ROOT <a href=\"/?do=child&ID=0\" ><img src=\"/pic/child.gif\" width=\"16\" height=\"16\" border=\"0\" align=\"absmiddle\" alt=\"Добавить дочернее значение\" /></a>" : '';
$sql = "SELECT * FROM tree WHERE parentID='$parentID' ORDER BY title";
$res = mysql_query($sql);
if (mysql_num_rows($res) > 0) {
$result .= "<ul>";
while ($row = mysql_fetch_array($res)) {
$result .= "<li>".$row['title']."
<a href=\"/?do=edit&ID=".$row['ID']."\"><img src=\"pic/edit.gif\" width=\"16\" height=\"16\" border=\"0\" align=\"absmiddle\" alt=\"Редактировать название\"/></a>
<a href=\"/?do=child&ID=".$row['ID']."\"><img src=\"/pic/child.gif\" width=\"16\" height=\"16\" border=\"0\" align=\"absmiddle\" alt=\"Добавить дочернее значение\" /></a>
<a href=\"/?do=del&ID=".$row['ID']."&sessID=".session_id()." \"><img src=\"/pic/del.gif\" width=\"16\" height=\"16\" border=\"0\" align=\"absmiddle\" alt=\"Удалить узел (удалит и все вложенные поддеревья)\" onClick=\"return Delete_confirm()\" /></a>
</li>";
$result .= showTree ($row['ID']);
}
$result .= '</ul>';
//$result = trim($result," ");
}
return $result;
}
//удаляем ветку(вместе с поддеревьями)
function deleteSubTree($ID){
$sql = "SELECT ID FROM tree WHERE parentID='$ID'";
$res = mysql_query($sql);
if (mysql_num_rows($res) > 0) {
while ($row = mysql_fetch_array($res)) {
if (!deleteSubTree($row["ID"])) return false;
}
}
$sql = "DELETE FROM tree WHERE ID='$ID' LIMIT 1";
mysql_query($sql);
if (mysql_affected_rows() < 1) return false;
else return true;
return false;
}
$do = (!empty($_POST['do'])) ? $_POST['do'] : "";
if (empty($_POST['do']) && (!empty($_GET['do']))) $do = $_GET['do'];
$error = "";
$out1 = "";
И в зависимости от принятого запроса выполняем те или иные действия
switch ($do) {
// редактирование узла
case "edit":
$sql = "SELECT * FROM tree WHERE ID='".$_GET["ID"]."' LIMIT 1";
$res = mysql_query($sql);
if (mysql_num_rows($res) > 0) {
$row = mysql_fetch_assoc($res);
$out1 .= "<form method=\"post\" action=\"\">
Введите новое название для «".$row["title"]."»:
<input type=\"text\" name=\"title\" />
<input type=\"hidden\" name=\"do\" value=\"save\" />
<input type=\"hidden\" name=\"ID\" value=".$_GET["ID"]." />
<input type=\"hidden\" name=\"sessId\" value=\"".session_id()."\" />
<input type=\"submit\" value=\"Сохранить\" />
</form>";
}
break;
// сохранение отредактированного
case "save":
if ($_POST["sessId"] != session_id()) exit("Ошибка: попытка передачи данных с другого хоста");
$_POST["title"] = sql_prep(trim (htmlspecialchars($_POST["title"], ENT_QUOTES)));
$sql = "UPDATE tree SET title='".$_POST["title"]."' WHERE ID='".$_POST["ID"]."' LIMIT 1";
mysql_query($sql);
if (mysql_affected_rows() < 1) $error .= "<strong>Ошибка сохранения названия узла</strong>";
break;
// Удаление узла с поддеревом
case "del":
if ($_GET["sessID"] != session_id()) exit("Ошибка: попытка передачи данных с другого хоста");
if (!deleteSubTree($_GET["ID"])) $error .= "<strong>Ошибка удаления узла</strong>";
break;
// Форма ввода нового узла
case "child":
$out1 .= "<form method=\"post\" action=\"\">
Введите название нового узла:
<input type=\"text\" name=\"title\" />
<input type=\"hidden\" name=\"do\" value=\"saveChild\" />
<input type=\"hidden\" name=\"ID\" value=".$_GET["ID"]." />
<input type=\"hidden\" name=\"sessId\" value=\"".session_id()."\" />
<input type=\"submit\" value=\"Сохранить\" />
</form>";
break;
// удаление дерева
case "saveChild":
if ($_POST["sessId"] != session_id()) exit("Ошибка: попытка передачи данных с другого хоста");
$_POST["title"] = sql_prep(trim (htmlspecialchars($_POST["title"], ENT_QUOTES)));
$_POST["ID"] = sql_prep(trim (htmlspecialchars($_POST["ID"], ENT_QUOTES)));
$_POST["title"] = sql_prep(trim (htmlspecialchars($_POST["title"], ENT_QUOTES)));
$sql = "INSERT INTO tree (parentID, title) VALUES ('".$_POST['ID']."', '".$_POST['title']."')";
mysql_query($sql);
if (mysql_affected_rows() < 1) $error .= "<strong>Ошибка сохранения узла</strong>";
break;
//
}
Осталось организовать вывод в браузер и все
З.Ы. Единственное, что тут в рекурсии отправляется SQL запрос. При большом дереве это не очень хорошо, т.к. будет много SQL запросов. Лучше считать дерево в переменную одним запросом и обрабатывать получившийся массив. 8)
Есть миры, не здесь, там, где небеса горят, и моря засыпают, и реки дремлют; люди сделаны из дыма, а города – из песен. Где-то опасность, где-то несправедливость, даже где-то остыл чай. Идем Эйс, у нас много работы!