php.de

Zurück   php.de > Webentwicklung > PHP-Fortgeschrittene

PHP-Fortgeschrittene Arbeiten mit PHP ohne Einschränkungen

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 07.07.2009, 16:11   #1 (permalink)
Erfahrener Benutzer
 
Registriert seit: 20.08.2008
Beiträge: 117
sharp befindet sich auf einem aufstrebenden Ast
Standard Nested Set

Hallo,
ich habe vor einpaar Tagen die "Nested Sets" entdeckt und wollte damit nur ma zum Test was kleines ausprobieren. Da ich Probleme beim einlesen des Baumes hatte habe ich erst ma Google abgegrast, jedoch dort nur Beispiele gefunden wo bereits Daten vorhanden sind.
Linkliste:
dev.iordanov.net
http://www.tutorials.de/
http://www.traum-projekt.com/

http://reeg.junetz.de/
http://phpperformance.de/
http://www.php-resource.de/


Und natürlich ha ich auch die Forums Suche verwendet leider auch ohne erfolg.

Mein Problem ist nun das beim einlesen der Daten falsche lft(Links) und rgt(rechts) werte erzeugt werden.
Hier mein Script:
PHP-Code:
function mySQLCon(){
    
$host="localhost";
    
$user="xxxxxxxxxxx";
    
$pass="xxxxxxxxxxx";
    
$db="test";        
    
$con=mysqli_connect($host,$user,$pass);
    
mysqli_select_db($con,$db);    
    return 
$con;
}

function 
setRoot($root,$lft=1,$rgt=2){
    
#mysqli_query(mySQLCon(),"TRUNCATE TABLE `test`;");
    
$sql2="INSERT INTO tree (name,lft,rgt) VALUES ('$root',$lft,$rgt);";    
    
mysqli_query(mySQLCon(),$sql2);     
}
function 
createTree($tree,$lft=1,$rgt=1,$first=1){
    
$root=$tree;
    echo 
$root."<br>";

    if(
is_dir($root)){
        
$inserts=0;
        if(
$dh=opendir($root)){
            while ((
$item readdir($dh)) !== false){
                if(
$item!="."&&$item!=".."){
                    
$rgt++;
                    
$lft++;
                    echo 
"<b>$rgt</b><br>";
                    if(
$first){                                                      
                        
$sql="UPDATE tree SET rgt=rgt+2 WHERE rgt >= $rgt;";
                        
$sql.="INSERT INTO tree (name,lft,rgt) VALUES ('$item', $rgt, $rgt+1);";
                    }else{                    
                        
$sql="UPDATE tree SET rgt=rgt+2 WHERE rgt >= $rgt;";
                        
$sql.="UPDATE tree SET lft=lft+2 WHERE lft > $rgt;";
                        
$sql.="INSERT INTO tree (name,lft,rgt) VALUES ('$item', $rgt, $rgt +1); ";
                    }
                    echo 
"<pre>";var_dump($sql,$rgt);echo "</pre>";
                    
mysqli_multi_query(mySQLCon(),$sql);
                    
$inserts++;
                    if(
is_dir("$root/$item")&&"$root/$item"!=$root){                   
                        
$count=createTree("$root/$item",$lft,$rgt,0);
                        
$sql2="UPDATE tree SET rgt=rgt+($count+1) WHERE name='$item';";
                        
mysqli_query(mySQLCon(),$sql2);
                    }
                }
            }
        }
    }
}
setRoot("Saeugetiere");
createTree("Saeugetiere"); 
Ich wer wende aus dem Beispiel von "http://www.klempert.de/nested_sets/" die Baumstruktur:
Code:
Saeugetiere
---Nagetiere
---Primaten
------Affen
------Halbaffen
Welche soweit auch funktioniert:
Code:
+------+-------------+-------+------+
|  id  |     name    |  lft  |  rgt |
+------+-------------+-------+------+
|  1   | Saeugetiere |   1   |  10  |
|  2   | Nagetiere   |   2   |   3  |
|  3   | Primaten    |   3   |   7  |
|  4   | Affe        |   4   |   5  |
|  5   | Halbaffe    |   5   |   6  |
+------+-------------+-------+------+
Wenn ich jedoch in Nagetiere nun "Maus" hinzufüge zerhaut es das ganze Konstrukt
Code:
+------+-------------+-------+------+
|  id  |     name    |  lft  |  rgt |
+------+-------------+-------+------+
|  1   | Saeugetiere |   1   |  12  |
|  2   | Nagetiere   |   2   |   9  |
|  3   | Maus        |   3   |   4  |
|  4   | Primaten    |   4   |   5  |
|  5   | Affe        |   3   |   7  |
|  6   | Halbaffe    |   5   |   6  |
+------+-------------+-------+------+
Man beachte das nun "Nagetiere" auch "Primaten" als Kinderelement enthält sowie das "Affe" zum Elternelement von "Primaten" wird. Hat jemand ne Idee wo das Problem hier liegt?

Gruß
sharp
sharp ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 07.07.2009, 17:13   #2 (permalink)
Benutzer
 
Registriert seit: 07.12.2007
Beiträge: 71
PHP-Kenntnisse:
Fortgeschritten
Varon
Standard

Puh ich muss gestehen mit Nested Set bin ich nie richtig warm geworden. Da ich für die viele Anwendung für zu umfangreich und kompliziert halte.

Aber wenn ich das noch richtig in Erinnerung habe ist schon deine erste Tabelle falsch da in dieser zweimal die 3 auftaucht was nicht sein kann.

Zudem solltest erstmal Versuchen deine Funktionen kleiner und einfach zu gestalten in deiner Funktion passiert viel auf einmal.

Am besten du legst dir einen Saubernbaum an und schreibst dir eine Funktion hast die dir gezielt ein weiteres Element anlegen. Im grunde müsste da die Information name,lft und ob es auf der gleichen ebene sein soll oder ein unter elment reichen.
__________________
Ich mag Schildkröten!
Varon ist offline   Mit Zitat antworten
Alt 07.07.2009, 17:27   #3 (permalink)
Erfahrener Benutzer
 
Registriert seit: 21.12.2004
Beiträge: 3.978
PHP-Kenntnisse:
Fortgeschritten
mepeisen ist einfach richtig nettmepeisen ist einfach richtig nettmepeisen ist einfach richtig nettmepeisen ist einfach richtig nett
mepeisen eine Nachricht über ICQ schicken mepeisen eine Nachricht über Skype™ schicken
Standard

Wie oben schon steht. Per Definition ist es falsch, dass du zweimal lft 3 drin stehen hast. Die Methode habe ich mir nicht angeschaut, aber irgendwo ein ">" durch ein ">=" austauschen.

Und ja, der erste Baum ist auch schon falsch. Im Grunde darf keine Zahl in lft oder rgt doppelt vorkommen, denn über diese Zahlen wird eindeutig sortiert. Gucke dir bei Abbildung 3 in deinem Link einmal an, wie es auszusehen hat. Das passt schon nicht auf deine Ursprungstabelle, von der du ausgehst, bevor du die Maus dazutust.
__________________
Entwickler aus Leidenschaft und ein Zahnrad in einem der größten Java-Projekte der Welt.
Kostenlos-Webspace zu Weihnachten
mepeisen ist offline   Mit Zitat antworten
Alt 07.07.2009, 17:31   #4 (permalink)
Moderator
 
Benutzerbild von Chriz
 
Registriert seit: 11.05.2008
Beiträge: 3.846
Chriz ist ein sehr geschätzer MenschChriz ist ein sehr geschätzer MenschChriz ist ein sehr geschätzer MenschChriz ist ein sehr geschätzer Mensch
Standard

Hallo,

falls du wegen der Performance auf Nested Set umgestiegen bist, ich hatte hier:
Wert aus Datei lesen + anordnen - Forum: phpforum.de
mal ein Beispiel gepostet, wie du mithilfe von PHPs Objektreferenzierung einen Baum aus einer id | parent_id Datenbanktabelle/CSV-Datei erzeugen kannst, bei einer einzigen Abfrage. Allerdings duerfen dann nicht mehrere Baeume in der Tabelle untergebracht werden, bzw. muessen sie explizit unterscheidbar sein (sich also nicht implizit durch die Zuordnungen ergeben), z.B. durch eine zusaetzliche Spalte.
__________________

Chriz ist offline   Mit Zitat antworten
Alt 07.07.2009, 17:33   #5 (permalink)
Moderator
 
Benutzerbild von robo47
 
Registriert seit: 03.09.2004
Beiträge: 11.637
PHP-Kenntnisse:
Fortgeschritten
robo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblick
Standard

Bevor da man vielleicht das Rad neu erfindet wird, es gibt einige fertige Systeme und Ansätze für Systeme die Nested-Sets in Datenbanken abbilden können:

DB_NestedSet
[url=http://dev.iordanov.net/archives/8]dev.iordanov.net
robo47 ist offline   Mit Zitat antworten
Alt 07.07.2009, 18:51   #6 (permalink)
Moderator
 
Benutzerbild von Chriz
 
Registriert seit: 11.05.2008
Beiträge: 3.846
Chriz ist ein sehr geschätzer MenschChriz ist ein sehr geschätzer MenschChriz ist ein sehr geschätzer MenschChriz ist ein sehr geschätzer Mensch
Standard

Ich hab meinen Ansatz gerade nochmal getestet:

Beispiele erzeugen:
PHP-Code:
<?php
function getFSTree($baseDir, &$stream$parentId 0)
{
    static 
$id 0;
    ++
$id;
    foreach (
glob("$baseDir/*") as $file) {
        if (
$file == "." || $file == "..") {
            continue;
        }
        
fputs($stream$id ";" basename($file) . ";" $parentId PHP_EOL);
        if (
is_dir($file)) {
            
getFSTree($file$stream$id);
        }
        ++
$id;
        if (
$id 25000) {
            break;
        }
    }
}

$file "./fs.csv";
$stream fopen($file"w");
getFSTree("E:/"$stream);
fclose($stream);
$file str_replace("\\""/"realpath($file));

mysql_connect("localhost""***""***");
mysql_select_db("***");

$sqlDrop "DROP TABLE IF EXISTS `my_filesystem`";
$resDrop mysql_query($sqlDrop) or die(mysql_error() . PHP_EOL $sqlDrop);

$sqlCreate "
    CREATE TABLE `my_filesystem` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
    `name` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL ,
    `parent_id` INT UNSIGNED NOT NULL
    ) ENGINE = InnoDB;"
;
$resCreate mysql_query($sqlCreate) or die(mysql_error() . PHP_EOL $sqlCreate);

$sqlLoadData "
    LOAD DATA INFILE '$file' INTO TABLE `my_filesystem`
    FIELDS TERMINATED BY ';'"
;
$resLoadData mysql_query($sqlLoadData) or die(mysql_error() . PHP_EOL $sqlLoadData);

$sqlCount "SELECT COUNT(*) FROM `my_filesystem`";
$resCount mysql_query($sqlCount) or die(mysql_error() . PHP_EOL $sqlCount);
echo 
mysql_result($resCount00) . " Datensaetze";
?>
Alle knapp 23.000 (!) Datensätze auslesen, Baum erzeugen, und davon einen zufällig auswählen und mit Name, Kinderanzahl und Breadcrumb anzeigen. Dauer: 0.3 bis 0.4 Sekunden.
PHP-Code:
<?php
mysql_connect
("localhost""***""***");
mysql_select_db("***");

$microStart explode(" "microtime());

class 
Tree
{
    public 
$id;
    public 
$parent;
    public 
$parentId;
    public 
$children = array();
    public 
$name;
}

$trees     = array();
$sqlSelect "SELECT * FROM `my_filesystem`";
$resSelect mysql_query($sqlSelect) or die(mysql_error() . PHP_EOL $sqlSelect);

while(
$data mysql_fetch_array($resSelect)) {
    
$tree = new Tree();
    
$tree->id $data["id"];
    
$tree->parentId $data["parent_id"];
    
$tree->name $data["name"];
    
$trees[$tree->id] = $tree;
}
$randomIndex mt_rand(0count($trees));
$random null;
while (
$tree current($trees)) {
    if (
$tree->parentId) {
        
$parent $trees[$tree->parentId];
        
$parent->children[] = $tree;
        
$tree->parent $parent;
    }
    if (--
$randomIndex == 0) {
        
$random $tree;
    }
    
next($trees);
}
assert('$random instanceof Tree');
// show element
echo "FS: "$random->name"<hr />""Childcount: "count($random->children), "<hr />";
// breadcrumbs
$tree $random;
$breadcrumbs = array();
do {
    
$breadcrumbs[] = $tree;
    
$tree $tree->parent;
} while (
$tree instanceof Tree);
echo 
implode(" &raquo; "array_map(create_function('$tree''return $tree->name;'), array_reverse($breadcrumbs))), "<hr />";

$microClose explode(" "microtime());
echo 
"required: ", ($microClose[1] - $microStart[1]) + ($microClose[0] - $microStart[0]), "s";
?>
Ausgabe:
Code:
FS: DSCN0420.JPG
Childcount: 0
Backup » 2005-01-01 » c » g » localhost » public_html » ling » img » gallery » 2 » th » DSCN0420.JPG
required: 0.390646s
Zugegeben die Tree-Klasse ist ziemlich schlank und viele Datenspalten enthält das Beispiel jeweils nicht, aber immerhin, für ein parent_id System find ich das akzeptabel.

@Threadstarter:
Sorry für OT, falls du wirklich nur auf Nested Set eingehen wolltest.
__________________

Chriz ist offline   Mit Zitat antworten
Alt 08.07.2009, 09:18   #7 (permalink)
Erfahrener Benutzer
 
Registriert seit: 20.08.2008
Beiträge: 117
sharp befindet sich auf einem aufstrebenden Ast
Standard

Hallo,
danke für eure Anregungen werde mir das heute im laufe des nachmittags ma anschauen.

Gruß
Sharp
sharp ist offline   Mit Zitat antworten
Alt 09.07.2009, 12:48   #8 (permalink)
Erfahrener Benutzer
 
Registriert seit: 20.08.2008
Beiträge: 117
sharp befindet sich auf einem aufstrebenden Ast
Standard

Hi,
Ich hab mir die PEAR "DB_NestedSet" angeschaut die ja schon recht mächtig ist. Jedoch is mir auf gefalle das in den Test datein ein fehler sein könnte da die erzeugt tabell komische lefts und rights erzeugt.

(Das bild stammt aus dem Anhang)

@Chriz ich würde das ganze doch lieber per Nested Set Lösen und nicht per Parent ID Methode, wobei dien Ansatz dafür schon recht gut daher kommt.

@robo47 zu dev.iordanov.net dort war ich bereits schon es schaut auch recht gut aus, nur hab ich mit dem Zend Framework noch nichts gemacht. Wobei is das nicht etwas zu mächtig für nur den einen Teil?

Gibt es sonst vllt noch ein Lösungsansatz?

Gruß
Sharp
sharp ist offline   Mit Zitat antworten
Alt 09.07.2009, 13:12   #9 (permalink)
Moderator
 
Benutzerbild von robo47
 
Registriert seit: 03.09.2004
Beiträge: 11.637
PHP-Kenntnisse:
Fortgeschritten
robo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblickrobo47 ist ein wunderbarer Anblick
Standard

Zitat:
Zitat von sharp Beitrag anzeigen
@robo47 zu dev.iordanov.net dort war ich bereits schon es schaut auch recht gut aus, nur hab ich mit dem Zend Framework noch nichts gemacht. Wobei is das nicht etwas zu mächtig für nur den einen Teil?


Das ist ne Geschmackssache, das ZF muss man ja auch nicht komplett einsetzen, man kann immer versuchen alles neu zu erfinden oder halt auf fertige Frameworks oder Komponenten aufsetzen.
Imho seh ich grad dass oben mein Link wieder vom Forum gekillt wurde, da Stand auch noch Doctrine (ein PHP-ORM-System) zur Wahl.
Doctrine ORM for PHP - NestedSet.

Egal ob Zend_Db, Doctrine oder PEAR, overhead hat man damit immer, spart aber unter Umständen eine Menge Zeit, vermeidet eventuelle Bugs und setzt auf geteste Systeme, ob man das will muss man für sich selbst entscheiden. Ich würde heute z.b. nicht mehr mit mysql_* arbeiten, schon allein weil man sich darum auch wieder nen vernünftigen wrapper fürs errorhandling basteln muss, weil man sonst nur sehr umständlich ordentliche Fehlerbehandlung machen kann.

Ich selbst nutze jetzt seit einiger Zeit das Zend-Framework mit Doctrine für die Datenbank-Sachen und klar ist das einiges an Overhead und man muss sich damit auseinandersetzen, aber es nimmt einem viel Arbeit ab, hat teilweise Lösungen die besser sind als auf was man selbst kommen würde und sie werden halt meist von mehr als nur einer Person genutzt haben also auch eine etwas bessere Qualitätskontrolle.

Den Overhead der sich in der Ausführzeit und Speicherverbrauch niederschlägt kann man an vielen Stellen mit ordentlichem Caching wieder rausholen.
robo47 ist offline   Mit Zitat antworten
Alt 13.07.2009, 16:31   #10 (permalink)
Neuer Benutzer
 
Registriert seit: 12.08.2008
Beiträge: 7
stefant42 befindet sich auf einem aufstrebenden Ast
Standard

Hallo zusammen.

@Varon : Nested Sets sind super, man muss sich nur ein wenig damit beschäftigen.

@sharp : Dein Codeschnipsel scheint mir nicht vollständig. Wenn du deine einfüge Operation bzw. den SQL Query dazu posten würdest, könnte ich dir sicher sagen wo der Fehler liegt.

Einen guten Artikel hat Arne Klemplert unter www.klempert.de veröffentlicht. Hatte ich auch mal vor, nur Herrn Klemplerts Artikel ist super und warum das Rad erneut erfinden.

Beste Grüße,

Stefan

-----------------

http://www.stefan-neuser.eu

Geändert von stefant42 (13.07.2009 um 16:36 Uhr).
stefant42 ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
nested sets update und insert auf eine tabelle in einer aktion litterauspirna Datenbanken 9 09.11.2008 13:57
Nested Sets und viele Fragen... BartTheDevil89 Datenbanken 7 13.08.2008 10:18
nested set dbmodell subtrees verschieben raffnix Datenbanken 12 08.06.2008 13:27
Nested Sets oder Rekursion? litterauspirna PHP Tipps 2008 8 06.06.2008 16:57
Nested Sets in ein Mehrdimensionales Array Simon9990 PHP-Fortgeschrittene 2 29.10.2007 17:38
Nested Sets Query GSJLink Datenbanken 12 08.09.2007 10:55
menü, nested set oder ähnliches? Promaetheus PHP Tipps 2007 13 15.02.2007 22:37
Nested Sets und Silbings nightfreak Datenbanken 10 06.01.2006 13:58
Nested Sets History Sirke PHP-Fortgeschrittene 1 21.10.2005 08:50
erklärung gesucht: nested set query! Sirke Datenbanken 0 19.09.2005 17:24
Alternative zu Nested Sets fantast Datenbanken 1 16.08.2005 01:14
Nested Sets mit Berechtigungen? daniel987 Datenbanken 3 07.06.2005 22:18
Frage zu nested sets... PHP-Fortgeschrittene 2 04.03.2005 09:57
Nested Set Trees und Pfade Datenbanken 0 16.12.2004 16:51
NESTED SETS dieses Thema sollte abgehakt werden PHP Tipps 2004 0 12.10.2004 18:18

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
nested sets java, zend framework nested set, doctrine nested set, zend breadcrumb erste root, zend framework nested sets, nested sets breadcrumps, doctrine::loaddata kein utf8, nested sets breadcrumb, zend nested sets, nested set klasse, \nested set\ populate tree, doctrine tree nested set to array, nestedset.php, zend framework doctrine nested set, doctrine nested set get root, function tree set mysql php, nested set mit zend framework, doctrine tree nestedset, \nested set\ children name, nested set in zend

Alle Zeitangaben in WEZ +2. Es ist jetzt 17:53 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum