Virtueller Verzeichnisbaum mittels rekursiver Abfrage

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Virtueller Verzeichnisbaum mittels rekursiver Abfrage

    Hi,

    ich möchte mit Hilfe einer Datenbank einen virtuellen Verzeichnisbaum aufbauen (jedes Bild liegt pysikalisch im gleichen Verzeichnis)
    Dazu werden Ordner (Datensätze in der DB) angelegt, in die man dann die Bilder verteilen kann. Alles auf der Basis von id und parent_id.

    Als erstes habe ich jetzt einmal eine Funktion geschrieben, die mir den ganzen Verzeichnisbaum abruft:

    PHP-Code:
    function get_tree($table$pid=0$path_name='') {
        global 
    $auth$mysql_sys;
        
    $sql 'SELECT id, name, pid
            FROM ' 
    DB_PREFIX $table '
            WHERE pid = ' 
    $pid '
            ORDER BY name'
    ;
        
    $result $mysql_sys->query($sql);
        while (
    $data mysql_fetch_array($resultMYSQL_BOTH)) {
            if (
    $pid == $data['pid']) {
                
    $path_name $path_name '/' $data['name'];
                
    $output .= $path_name '<br>';
                
    $output .= get_tree($table$data['id'], $path_name);
            }    
        }
        return 
    $output;

    Leider schaukelt sich die Ausgabe durch $path_name hoch, dass ich zu folgendem Ergebnis komme:

    Code:
    /1985
    /1985/Tobi
    /1985/1990
    /1985/1990/Judy
    Richtig wäre aber

    Code:
    /1985
    /1985/Tobi
    /1990
    /1990/Judy
    Gibts da irgenteine Möglichkeit mit Arrays oder muss die Funktion anders aufgebaut sein?

  • #2
    einmal auf die finger klopfen und 100 mal an die tafel schreiben:
    * ich werde nie wieder rekursive datenbank-abfragen schreiben
    * ich werde nie wieder rekursive datenbank-abfragen schreiben

    und dann nach "Nested Sets" oder "adjacency list" oder nach "xml" suchen.

    niemand zwingt dich, eine verschachtelte struktur in einer datenbank abzulegen.

    grüße
    axo

    Kommentar


    • #3
      problem: nested sets sind beim verschieben sehr kompliziert und bei meiner anwendung brauch ich die rekursive abfrage eigentlich nur einmal:
      beim Aufbauen des Verzeichnisbaums.

      Sonst wird immer nur der Ordner angezeigt, dessen inhalt nur mittels $pid gefilter werden muss.

      hast du nicht trotz meines schlimmen php und db missbrauchs einen tipp für mich?

      Kommentar


      • #4
        $output mal am Anfang der Funktion initialisieren ...?
        I don't believe in rebirth. Actually, I never did in my whole lives.

        Kommentar


        • #5
          Original geschrieben von TobiasKa
          [B]problem: nested sets sind beim verschieben sehr kompliziert und bei meiner anwendung brauch ich die rekursive abfrage eigentlich nur einmal:
          beim Aufbauen des Verzeichnisbaums.
          auch das eine mal kann zu viel sein, und das bereits wenn deine tabelle 80-100 einträge beinhaltet.

          nested sets programmiert man auch nicht selbst, und ein paar methoden aufzurufen ist nie zu viel.
          egal.



          hast du nicht trotz meines schlimmen php und db missbrauchs einen tipp für mich?
          du fährst besser, wenn du alle einträge, die du benötigst auf einmal mit einem einzigen select aus der datenbank liest und das array dann zu fuß per php in eine baumstruktur packst.

          grüße
          axo

          Kommentar


          • #6
            Original geschrieben von axo
            auch das eine mal kann zu viel sein, und das bereits wenn deine tabelle 80-100 einträge beinhaltet.
            und warum soll er das machen?
            für eine einmalige Ausführung und cachen von ergebnisen muss man nicht unbedingt nestedset nehmen.
            ausserdem mit 100 abfragen wird er in 2 sekunden fertig.
            ausser dem das ist doch Adjacency List Model mit ausname, dass er für parent_id keine extra tabelle gemacht hat.

            versuch bitte so
            PHP-Code:
            while ($data mysql_fetch_array($resultMYSQL_BOTH)) {
                
            $output .= $path_name '/' $data['name']. '<br>';
                
            $output .= get_tree($table$data['id'], $path_name '/' $data['name']);

            Zuletzt geändert von Slava; 17.10.2006, 13:43.
            Slava
            bituniverse.com

            Kommentar


            • #7
              jo, ist eine gute idee.

              irgentwelche Tipps dazu? zumindest eine Idee für ein Konzept wie man das ganze angehen könnte?

              Kommentar


              • #8
                okay, jetzt hab ich mal die Lösung von Slava genommen:

                Es wird das richtige ausgegeben. Wieviele DB Abfragen macht er jetzt insgesamt? 6 Stück oder? Denn er muss ja immer schauen, ob da noch was untergeordnetes existiert.

                Bei error-reporting e_all kommen jetzt noch 5 Fehler, die von der nicht definirten output variable herrühren: "Notice: Undefined variable: output...."

                dreimal wo diese zuerst angegeben wird: $output .= usw
                und zweimal beim returnaufruf

                das passiert doch, wenn nix untergeornetes mehr gefunden werden kann.

                Wie kann ich das vermeiden?

                Noch eine interessante idee für die array zu fuß lösung?

                UPDATE: mit if (empty($output)) $output = ''; hab ich die notice Meldungen wegbekommen? verwendet man da lieber !isset() oder ist empty okay?
                Zuletzt geändert von TobiasKa; 17.10.2006, 13:21.

                Kommentar


                • #9
                  du muss einfach dein $output einfach declarieren
                  $output =""; irgendwo am anfang von function.
                  es ist aber zu empfehlen, dass diese function nur bei änderung von verzeichnisstruktur ausgeführt wird und die ausgabe einfach in eine datei abspeichert, die du in deiner seite einbinden muss.
                  Slava
                  bituniverse.com

                  Kommentar


                  • #10
                    ich habe mal was ähnliches mit nested sets gelöst - ist zwar auf den ersten Blick etwas kompliziert, dafür kann man aber sehr viel mit einer einzelnen Abfrage erledigen. Auch das Verschieben ist relativ simple. Diese Seite hat mir beim Einstieg echt geholfen http://groups.google.com/group/micro...afe=off&rnum=4

                    Kommentar


                    • #11
                      Zum ermitteln des Pfades brauchte ich noch eine rek. Abfrage, womit ich jetzt ein Problem habe:

                      ich muss die Ausgabe in der ungekehren Reihenfolge ordnen.
                      Leider bekomm ichs einfach nicht hin:


                      PHP-Code:
                      function get_path($table$id$path='') {
                          global 
                      $auth;
                          if (
                      $id=='0') return; //reached root level
                          
                      if (empty($output)) $output '';
                          
                      $sql 'SELECT pid, name
                              FROM ' 
                      DB_PREFIX DB_PREFIX_C $table '
                              WHERE id = ' 
                      $id '
                              AND id_c = ' 
                      ID_C;
                          
                      $data $auth->mysql->query($sql'array');
                          
                      $output .= '/' $data['name'];
                          
                      $output .= get_path($table$data['pid'], $data['name']);
                          return 
                      $output;

                      Jemand eine idee?

                      danke schonmal!

                      Kommentar


                      • #12
                        die Problemstellung ist mir leider nicht ganz klar.

                        ich möchte aber gerne wissen, warum du $output wie vorgeschlagen nicht deklariert hast?
                        also @wahsaga als auch ich haben dich darauf aufmerksam gemacht.
                        Außerdem wenn ich jemandem ein Antwort oder Vorschlag schreibe, erwarte ich wenigstens eine kurze Bestätigung oder Meinung zum meinem Vorschlag bevor ich einem Fragesteller weiterhelfen versuche.
                        Slava
                        bituniverse.com

                        Kommentar


                        • #13
                          @Slava: Das hat er doch jetzt gemacht - wenn auch in einem überflüssigen IF gekapselt. (Da $output eine lokale Variable ist, ist sie am Anfang der Funktion immer undefiniert - kann also dort ohne weitere Bedingung initialisiert werden.)

                          Original geschrieben von TobiasKa
                          ich muss die Ausgabe in der ungekehren Reihenfolge ordnen.
                          Leider bekomm ichs einfach nicht hin
                          Was machst du bisher? Bisherigen Inhalt nehmen, neues anhängen:
                          PHP-Code:
                          $output .= ergebnis_von_funktionsaufruf(); 
                          Das ist das gleiche wie
                          PHP-Code:
                          $output $output.ergebnis_von_funktionsaufruf(); 
                          Wenn du's jetzt andersherum haben willst - neues nehmen, bisherigen Inhalt anhängen - dann könnte man da vielleicht mal was umdrehen ...?
                          I don't believe in rebirth. Actually, I never did in my whole lives.

                          Kommentar


                          • #14
                            funktioniert - wunderbar.

                            Frag mich nur warum ich da nicht selbst draufgekommen bin...

                            PHP-Code:
                            $output .= get_path($table$data['pid'], $data['name']) . '/' $data['name']; 
                            @slava: Sorry, dass ich keine Rückmeldung gegeben habe, wie du in der 2. funktion siehst, habe ich es eingebaut.

                            @wahsaga: wie soll ich es ohne if machen? denn wenn sie schon existiert, würde sie ja sonst gelöscht.
                            und ich kann sie ja nicht wie in einer klasse mit public $output; registrieren.
                            wenn cih sie aber einfach so verwende, bring e_all eine meldung

                            Kommentar


                            • #15
                              Original geschrieben von TobiasKa
                              wie soll ich es ohne if machen? denn wenn sie schon existiert, würde sie ja sonst gelöscht.
                              Dein "denn wenn" ist überhaupt nicht erfüllt.
                              Sie existiert zu Beginn deiner Funktion nicht, also kannst du sie dort einfach mit einem Leerstring initialisieren.

                              Wenn dir das nicht klar ist, mach dir klar, wie rekursive Funktionen funktionieren.
                              I don't believe in rebirth. Actually, I never did in my whole lives.

                              Kommentar

                              Lädt...
                              X