Реализация дерева

Быстрый переход:
aristarh

aristarh

Member
#1   19 июня 2008 12:50
В общем есть такая необходимость, реализовать дерево на php и MySql

Недвижисость
...|_ Участки
...........|_ Дачи
...........|_Под сельхоз. использование
...........|_Под строительство
...|_ Квартиры
...........|_Однокомнатные
...........|_Двухкомнатные
................|_новостройки
................|_вторичное жилье

Нужно реализовать следующие функции:
• добавление элементов в дерево на любой уровень (для этого выбирается родитель и вписывается имя нового элемента)
• переименование любого элемента дерева, кроме корневого элемента 'Недвижисость'
• удаление любого элемента дерева (c удалением ветки)

Буду рад любым идеям
Отредактировано: aristarh (19.06.2008 13:04, 9 лет назад)
Алексей

Алексей

Administrator
#2   20 июня 2008 12:39
В общем есть такой вариант решения:

Допустим у нас есть БД 'test' в ней таблица 'tree' с полями: ID, parentID и title (ID узла, ID родительского узла и название соответственно)

функуии вывода структуры дерева и удаления узла вместе со всем поддеревом:

//выводим дерево
function showTree ($parentID = 0) { 
	$result = ($parentID == 0)? "ROOT&nbsp;<a href=\"/?do=child&amp;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&amp;ID=".$row['ID']."\"><img src=\"pic/edit.gif\" width=\"16\" height=\"16\" border=\"0\" align=\"absmiddle\" alt=\"Редактировать название\"/></a>
					  <a href=\"/?do=child&amp;ID=".$row['ID']."\"><img src=\"/pic/child.gif\" width=\"16\" height=\"16\" border=\"0\" align=\"absmiddle\" alt=\"Добавить дочернее значение\" /></a>
					  <a href=\"/?do=del&amp;ID=".$row['ID']."&amp;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)

Быстрота и надежность... Ну и красота тоже, конечно