HTML - PHP - MySQL - SVG

KERNI's SEITE

Das Nested Set Model

Veröffentlicht am


Eintrag ein-/ausrücken

 

Zum Einrücken wird der lft und rgt Wert des Ausgangselements benötigt. Das Element direckt darüber, da das Ausgewählte Element ja ein Unterelement werden soll und die Anzahl der nachfolgenden Elemente. Aus der Anzahl mal zwei errechnet sich der neue rgt Wert des neuen Vaterelements.

 

Beispiel:

id name lft rgt
1 Reptilien 1 6
2 Frosch 2 3
3 Krokodil 4 5
4 Primaten 7 18
5 Schimpanse 8 9
6 Orangutan 10 15
11 OrangMama 11 12
14 OrangPapa 13 14
9 Bonobo 16 17
8 Vögel 19 20

 

Orangutan soll ein Kindelement von Schimpanse werden. Klar, Orangutan gehört nicht zu Schimpanse, ist nur ein Beispiel.
Wir ermitteln lft=10 und rgt=11 (gelbes Element). Das Element darüber (türkis) mit rgt=lft-1 also rgt=9.
Gibt es kein Element darüber ist hier schluss.
Die Anzahl Kindelemente (grün) beträgt 2. Diese 2 mit 2 malnehmen ergibt 4.

Nun den rgt des Schimpansen um die ermittelte Anzahl erhöhen.

Im zweiten Step den lft und rgt aller Elemente die zu Orangutan gehören einschließlich Orangutan um 1 veringern.
( lft = lft - 1 und rgt = rgt - 1 )

Hier erstmal die beiden JS Funktionen zum aufrufen der PHP Funktionen.

JavaScript Code:

	function toLeft(id){
	  $.ajax({
	    type: "POST",
	    url: "php/toleft.php",
	    data: {id:id}
	  })
	  .done(function(data){
	    i++;
	    $("#msg").html(i+"."+data);
	    laden();
	  });
	}
	 
	function toRight(id){
	  $.ajax({
	    type: "POST",
	    url: "php/toright.php",
	    data: {id:id}
	  })
	  .done(function(data){
	    i++;
	    $("#msg").html(i+"."+data);
	    if(data=="Fertig"){
	      laden();
	    }
	  });
	}
	

 

PHP Code: toright.php

	$id = $_REQUEST['id'];
	 
	$ausgabe = "";
	 
	// Ausgangselement suchen
	$sql = "SELECT `id`, `name`, `lft`, `rgt` FROM `menu` WHERE `id`=:id;";
	 
	$rst = $pdo->prepare($sql);
	$rst->execute(array(":id"=>$id));
	$row = $rst->fetch(PDO::FETCH_ASSOC);
	$ae_lft = $row["lft"];
	$ae_rgt = $row["rgt"];
	 
	// Element darüber ermitteln
	$sql = "SELECT `id`, `name`, `lft`, `rgt` FROM `menu` WHERE `rgt`=:ed;";
	 
	$rst = $pdo->prepare($sql);
	$w=$ae_lft-1;
	 
	$rst->execute(array(":ed"=>$w));
	$row = array();
	$row[] = $rst->fetch(PDO::FETCH_ASSOC);
	 
	if(isset($row[0]["id"])){
	  $ed_id = $row[0]["id"];
	 
	  // Anzahl der untergeordneten Elemente des Ausgangselements ermitteln
	  $sql = "SELECT COUNT(*) AS Anzahl FROM menu WHERE lft BETWEEN :ae_lft AND :ae_rgt;";
	 
	  $rst = $pdo->prepare($sql);
	  $rst->execute(array(":ae_lft"=>$ae_lft,":ae_rgt"=>$ae_rgt));
	  $row = $rst->fetch(PDO::FETCH_ASSOC);
	  $anz = $row["Anzahl"]*2;
	 
	  $sql = "UPDATE `menu` SET `rgt`=`rgt`+$anz WHERE `id`=$ed_id;";
	  $sql .= "UPDATE `menu` SET `lft`=`lft`-1, `rgt`=`rgt`-1 WHERE lft BETWEEN $ae_lft AND $ae_rgt;";
	 
	  $rst = $pdo->prepare($sql);
	  $rst->execute();
	 
	  echo "Fertig";
	 
	}else{
	  echo "Nicht möglich";
	}
	

 

Um einen Eintrag und seine Kindelemente nach links zu verschieben müssen wir etwas anders vorgehen.

Ein im Baum auf Ebene Null befindlicher Ast kann nicht weiter nach links verschoben werden. Abfrage 1 ermittelt die Ebene des Eintrages. Ist die Ebene ungleich Null ermitteln wir das Vaterelement. Da sich dieses weiter oben befinden kann genügt es nicht dies durch WHERE Vater rgt = Ausgangs lft-1 zu ermitteln. Dazu muss eine etwas speziellere Abfrage her. Ist der Vater ermittelt müssen die Kinder ermittelt werden. Die Anzahl der Kinder nehmen wir wieder mit 2 mal und zählen 1 dazu. Sind keine Kinder vorhanden fällt die erste UPDATE weg.

Auch hier müssen die IDs aller Einträge ermittel und für die UPDATE Abfragen verwendet werden um ein durcheinanderwürfel zu vermeiden.

PHP Code: toleft.php

	$id = $_REQUEST['id'];
	 
	// Eintrag nach links verschieben
	 
	$ausgabe = "";
	 
	  // Level des Eintrages *********
	  $sql = "SELECT n.id, n.lft, n.rgt, COUNT(*)-1 AS level FROM menu AS n, menu AS p WHERE n.lft BETWEEN p.lft AND p.rgt AND n.id=$id GROUP BY n.lft ORDER BY n.lft;";
	  $rst = $pdo->prepare($sql);
	  $rst->execute();
	  $erg = $rst->fetch(PDO::FETCH_ASSOC);
	  $Level = $erg["level"];
	  $Elem_lft = $erg["lft"];
	  $Elem_rgt = $erg["rgt"];
	  // *****************************
	 
	  // Level '0' kann nicht weiter nach Links verschoben werden
	  if($Level!=0){
	 
	    // Vater ermitteln *************
	    $sql = "SELECT o.id, o.lft, o.rgt FROM menu AS n, menu AS o WHERE o.lft < n.lft AND o.rgt > n.rgt AND n.id=".$id." ORDER BY o.lft DESC LIMIT 1;";
	 
	    $rst = $pdo->prepare($sql);
	    $rst->execute();
	    $ergV = $rst->fetch(PDO::FETCH_ASSOC);
	    // $ergV = Ergebnis Vater
	    $ergVid = $ergV['id'];
	    $ergVlft = $ergV['lft'];
	    $ergVrgt = $ergV['rgt'];
	    // *****************************
	 
	    // Ausgewählter Eintrag (Kind + Enkel)
	    $sql = "SELECT o.id, o.lft, o.rgt FROM menu AS n, menu AS p, menu AS o WHERE o.lft BETWEEN p.lft AND p.rgt AND o.lft BETWEEN n.lft AND n.rgt AND n.id=".$id." GROUP BY o.lft ORDER BY o.lft;";
	 
	    $rst = $pdo->prepare($sql);
	    $rst->execute();
	    // ergK = Ergebnis Kinder
	    $ergK = array();
	    $ergKid = array();
	 
	    while($rowK = $rst->fetch(PDO::FETCH_ASSOC)){
	      $ergK[] = $rowK;
	      $ergKId[] = $rowK["id"];
	    }
	    $anzK = count($ergK)*2;
	    $idK = implode(", ",$ergKId);
	 
	    $lftKalt = $ergK[0]['lft'];
	    $rgtKalt = $ergK[0]['rgt'];
	    // *****************************
	 
	    // Einträge unterhalb der Kinder und Enkel ermitteln
	    $sql = "SELECT o.id, o.lft, o.rgt FROM menu AS o WHERE o.lft BETWEEN ".($rgtKalt)." AND ".$ergVrgt.";";
	 
	    $rst = $pdo->prepare($sql);
	    $rst->execute();
	    // egrKE = Ergebnis Kinder & Enkel
	    $ergKE = array();
	 
	    while($rowKE = $rst->fetch(PDO::FETCH_ASSOC)){
	      $ergKE[] = $rowKE;
	      $ergKEId[] = $rowKE["id"];
	    }
	    // Sind unterhalb Einträge vorhanden diese Zählen, mal 2 nehmen und +1
	    // Um diesen Wert muss die Auswahl und dessen Kinder erhöht werden
	    // Anzahl * 2 + 1
	    $anzKE = count($ergKE);
	 
	    // *****************************
	 
	    $sql = "";
	    // Sind unterhalb keine einträge vorhanden, dann nur um 1 erhöhen
	    $neuVU = 1;
	 
	    // Updates zusammenbauen
	 
	    // Sind unterhalb keine Einträge vorhanden muss dieser Teil übersprungen werden
	    if($anzKE!=0){
	      $idKE = implode(", ",$ergKEId);
	      // neuVU = Neuer rht Vater und neuer lft, rgt unterhalb Auswahl+Kinder der Auswahl
	      $neuVU = $anzKE*2+1;
	      $sql = "UPDATE `menu` SET `lft`=`lft`-".$anzK.", `rgt`=`rgt`-".$anzK." WHERE `id` IN (".$idKE.");";
	    }
	 
	    $sql .= "UPDATE `menu` SET `lft`=`lft`+".$neuVU.", `rgt`=`rgt`+".$neuVU." WHERE `id` IN (".$idK.");";
	    $sql .= "UPDATE `menu` SET `rgt`=`rgt`-".$anzK." WHERE `id`=".$ergVid.";";
	 
	    $rst = $pdo->prepare($sql);
	    $rst->execute();
	 
	    $ausgabe .= "Abgeschlossen<br />".$anzKE;
	 
	  }else{
	    $ausgabe .= "<br />Weiter nach links geht es nicht.<br />";
	  }
	 
	  echo $ausgabe;