Ankündigung

Einklappen
Keine Ankündigung bisher.

[Erledigt] Problem bei PHP-Menü mit Parent-Modell

Einklappen

Neue Werbung 2019

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

  • [Erledigt] Problem bei PHP-Menü mit Parent-Modell

    Ich habe mir einen code für ein dynamisches Menü gebaut, dass auf Mysql aufgebaut ist. Hier ist einmal der code:
    PHP-Code:
    <?php
    //zuerst wird hier die aktuelle Seite aus einer Datenbank abgefragt.
    //Wichtige Teile sind hier: 
    //$row->parentid = Die id der übergeordneten Seite.
    //$row->id = Die id der aktuellen Seite.

    error_reporting(E_ALL);

    define('MYSQL_HOST''localhost');
    define('MYSQL_USER''bn');
    define('MYSQL_PASS''pw');
    define('MYSQL_DATABASE''db');

    //connect to database
    function connect_to_sql(){

    @
    mysql_pconnect(MYSQL_HOSTMYSQL_USERMYSQL_PASS) OR
    die(
    "Keine Verbindung zur Datenbank. Fehlermeldung:".mysql_error());
    mysql_select_db(MYSQL_DATABASE) OR
    die(
    "Konnte Datenbank nicht benutzen, Fehlermeldung: ".mysql_error());

    }
    function 
    getLevel($iIdParent$test) {

    $sQuery 'SELECT id, titel, link, parentid, content_id FROM `datenbank`.`seiten` WHERE parentid = "'.$iIdParent.'" ORDER BY content_id;';
    $rResult mysql_query($sQuery);
    while (
    $aLine mysql_fetch_object($rResult)) {

    echo(
    '<a href="'.$aLine->link.'.htm">'.$aLine->titel.'</a><br/>');

    if (
    $test == $aLine->id) {
    $test=$aLine->parentid;
    getLevel($aLine->id$test); 
    }

    }

    }
    $obid=$row->parentid;
    $test2=$row->id;
    connect_to_sql();
    getLevel($obid$test2);
    ?>
    Es funktioniert soweit, leider werden immer nur 2 Ebenen ausgegeben. Ich habe aber vier. Wenn man bei der zweiten Ebene auf einen Link klickt, sieht man nur noch die 2. und die 3. Ebene. Die erste verschwindet einfach.

    Hoffe Ihr könnt mir helfen.
    Vielen Dank schon im Voraus

  • #2
    Du machst Deine Rekursion ja auch nur für alle Nodes unterhalb der angegebenen. Du wirst schon die darüber liegenden auch mit in die Rekursion einbinden müssen.

    Gruß Jens

    Kommentar


    • #3
      Beim kurzen überfliegen fällt mir auf, daß Du nur die aktuell angeklickte Ebene und deren Parent-Ebene lädst.
      Kein Wunder, daß nur die beiden angezeigt werden...


      Uuups ganze 6min Unterschied, trotzdem nicht gesehen!
      Jens hat sich vorgeschlichen

      Kommentar


      • #4
        Danke erst mal für die schnelle Antwort.

        Stimmt. Wenn ich jetzt aber die Funktion mit 0 anfange:
        PHP-Code:
        $obid=$row->parentid;
        $test2=$row->id;
        connect_to_sql();
        getLevel(0$test2); 
        Dann klappt nur noch die 2. Ebene auf.
        Was muss ich Verändern?

        Kommentar


        • #5
          Du musst den gesamten Pfad aller offenen Ebenen übergeben.

          Gruß Jens

          Kommentar


          • #6
            Wie mach ich das genau?

            Kommentar


            • #7
              Nimm mal an, Dein Menü hat die folgende Struktur:
              • Punkt 1
                • Punkt 1.1
                  • Punkt 1.1.1
                  • Punkt 1.1.2
                    • Punkt 1.1.2.1
                    • Punkt 1.1.2.1
                    • Punkt 1.1.2.1
                  • Punkt 1.1.3
              • Punkt 2
              • Punkt 3
                • Punkt 3.1
                  • Punkt 3.1.1
                  • Punkt 3.1.2
                    • Punkt 3.1.2.1
                    • Punkt 3.1.2.1
                    • Punkt 3.1.2.1
                  • Punkt 3.1.3


              Wenn Du jetzt nur 1.1.2 kennst und 1.1.2.X anzeigen möchtest, dann weißt Du mit den zur Verfügung stehenden Informationen nie, ob Du - sagen wir 3.1.1 und 3.1.2 anzeigen musst. Du musst also von oben nach unten alle offenen Menüpunkte mit übertragen, um PHP-Seitig darüber entscheiden zu können. Du brauchst also eher sowas 1/1.1/1.1.2. Damit weißt Du, welche Nodes angezeigt werden müssen und welche nicht - im Pfad sind schließlich immer die Parent-Elemente der anzuzeigenden Nodes enthalten

              Diesen Pfad kannst Du natürlich in Kenntnis der tiefsten Node auch PHP-Seitig ermitteln, bevor Du zur Darstellung schreitest - innerhalb dieser einen Rekursion geht das aber nicht.

              Übrigens: Grad bei kleinen Bäumen bietet es sich an, die Rekursion nicht mittels mehrerer Queries zu machen, sondern indem Du den kompletten Baum erst einmal in einen Speicher lädst. Der Aufwand für einen DB-Zugriff ist um Längen höher, als der für einen Array-Zugriff.

              Gruß Jens

              Kommentar


              • #8
                Zitat von Jens Clasen Beitrag anzeigen
                Wenn Du jetzt nur 1.1.2 kennst und 1.1.2.X anzeigen möchtest, dann weißt Du mit den zur Verfügung stehenden Informationen nie, ob Du - sagen wir 3.1.1 und 3.1.2 anzeigen musst.
                Ich will immer nur die Unterpunkte eines Hauptpunktes anzeigen:
                Also wenn ich auf 1.2 klicke sollte folgendes angezeigt werden.

                1.
                1.1
                1.2
                1.2.1
                1.2.2
                1.3
                2.
                3.
                4.

                Die Unterpunkte von 2./3./4. usw müssen nicht angezeigt werden.

                Kommentar


                • #9
                  Und was ist mit dem Beispiel hier:
                  1.
                  1.1
                  1.2
                  1.2.1
                  1.2.1.1
                  1.2.1.2
                  1.2.2
                  1.3
                  1.3.1
                  1.3.2
                  2.
                  3.
                  3.1
                  4.


                  Woher willst Du nur mit der Information 1.2.1 entscheiden, ob Du nun 1.3 anzeigst?

                  Du musst immer alle Elemente neben denen der Teile Deiner Pfadangabe ausgeben, sowie alle Kinder besagter Information komplett.

                  Wenn Du also als Pfad das hier hast:
                  1/1.2/1.2.1

                  dann kannst Du daraus folgern, dass Du

                  -1 bis 4 anzeigen musst (alle mit Elter "null")
                  - 1.1 bis 1.3 anzeigen musst (alle mit Elter 1, also erstes Element d. Pfades)
                  - 1.2.1 bis 1.2.2 (also alle mit Elter 1.2, bzw. zweites Element d. Pfades)
                  - 1.2.1.1 bis 1.2.1.2 (also alle mit Elter 1.2.1, bzw. letztes Element d. Pfades)

                  Nicht anzeigen musst Du 1.3.1, 1.3.2 und 3.1 weil deren Elter-Elemente kommen nicht in der Pfadangabe vor.

                  Gruß Jens

                  Kommentar


                  • #10
                    So ein Beispiel gibts ja nicht.
                    Es gibt nur solche :

                    1.
                    1.1
                    1.2
                    1.2.1
                    1.2.2
                    1.3
                    2.
                    3.
                    4.

                    oder solche:
                    1.
                    2.
                    3.
                    3.1
                    3.2
                    3.3
                    3.3.1
                    3.3.2
                    3.4
                    4.

                    aber nicht:
                    1.
                    2.
                    2.1
                    2.2
                    2.2.1
                    2.2.2
                    2.3
                    3.
                    4.
                    4.1
                    4.2
                    4.2.1
                    4.3

                    Kommentar


                    • #11
                      Die Objektreferenzierung in PHP könnte für dich interessant sein, falls es eine überschaubare Anzahl an Menüpunkten ist. Dann brauchst du Rekursion nur in der Ausgabe, nicht mal mehr bei der Abfrage oder Zuweisung:
                      PHP-Code:
                      <?php
                      class Menu {
                          public 
                      $id;
                          public 
                      $parent;
                          public 
                      $name;
                      }

                      mysql_connect("localhost""root");
                      mysql_select_db("test");

                      $result mysql_query("SELECT * FROM menu");
                      $menus  = array();
                      while (
                      $line mysql_fetch_assoc($result)) {
                          
                      $menu = new Menu();
                          
                      $menu->id     $line['id'];
                          
                      $menu->parent $line['parent_id'];
                          
                      $menu->name   $line['name'];
                          
                          
                      $menus[$menu->id] = $menu;
                      }
                      foreach (
                      $menus as $menu) {
                          if (
                      $menu->parent === null) {
                              continue;
                          }
                          
                      $menu->parent $menus[$menu->parent]; // Eltern-ID durch Eltern-Objekt ersetzen
                      }

                      // Funktion zur Ausgabe als Breadcrumbs (siehe Ausgabe unten)
                      function breadcrumbs(Menu $menu) {
                          if (
                      $menu->parent === null) {
                              return array(
                      $menu->name);
                          }
                          return 
                      array_merge(breadcrumbs($menu->parentfalse), array($menu->name));
                      }
                      // Darstellung als Navigation
                      function nav(array $menus$parent null)
                      {
                          
                      $html   = array();
                          
                      $html[] = '<ul>';
                          foreach (
                      $menus as $menu) {
                              if (
                      $menu->parent !== $parent) {
                                  continue;
                              }
                              
                      $html[] = '<li>';
                              
                      $html[] = $menu->name;
                              
                      $html[] = nav($menus$menu);
                              
                      $html[] = '</li>';
                          }
                          
                      $html[] = '</ul>';
                          if (
                      count($html) == 2) {
                              
                      $html = array(); // keine Untermenüpunkte
                          
                      }
                          return 
                      implode(PHP_EOL$html);
                      }

                      echo 
                      '<h1>Alle</h1>';
                      echo 
                      nav($menus);

                      // mischen, um das Breadcrumbs-Feature zu veranschaulichen
                      shuffle($menus);
                      $menu array_pop($menus);

                      echo 
                      '<hr />';
                      echo 
                      '<h1>' $menu->name '</h1>';
                      echo 
                      implode(' &raquo; 'breadcrumbs($menu));
                      Ausgabe:
                      Alle
                      • Entwicklung
                        • PHP
                          • PHP 4
                          • PHP 5
                        • MySQL
                      • Sport
                        • Fußball
                        • Handball


                      MySQL

                      Entwicklung » PHP » PHP 4
                      Wenn du neben den Eltern auf gleiche Weise auch die Kind-Objekte speicherst, kannst du selbst bei mehreren hundert Menüpunkten eine sehr gute Performance erreichen.

                      Kommentar


                      • #12
                        Danke erst mal für dieses script, das fehlerfrei funktioniert!

                        Das sieht schon sehr gut aus. Es wurden alle Seiten richtig aufgelistet. Leider zeigt dieses Script alle Seiten auf einmal an. Muss ich mal genauer hinschauen, wie ich das ändern kann.

                        Danke nochmal

                        Kommentar


                        • #13
                          Zitat von MadMax Beitrag anzeigen
                          So ein Beispiel gibts ja nicht.
                          Doch - zumindest in Deiner DB. Du musst die Daten Deiner DB halt in eine der beiden gültigen Formen überführen, nämlich ohne die nicht anzuzeigenden Äste.

                          Das Problem löst übrigens auch das Beispielskript nicht. In dem Beispiel wird immer nur der komplette Baum aus der DB gelesen. Du möchtest ja aber nur einen Teilbaum darstellen. Die Brotkrümel könnten allerdings als Hilfsfunktion dazu hilfreich sein.

                          Gruß Jens

                          Kommentar


                          • #14
                            Einen Teilbaum kannst du damit trotzdem ausgeben, wenn du den zweiten Parameter von nav() entsprechend setzt. Aber zugegeben müssen dafür trotzdem alle Menüpunkte aus der DB geholt werden.

                            Kommentar


                            • #15
                              Ja, aber eben nicht den Teilbaum, den er haben möchte. Eigentlich möchte der TE nur wissen, wie er bei Klick auf einen Link dafür sorgt, dass nur der jeweils passende Teilbaum ausgelesen wird. Sprich: Wenn er auf Unterpunkt 1 klickt, dann soll alles unterhalb von 1 aufgehen, nicht aber alles unterhalb von 2. Bis zu einer Tiefe von zwei funktioniert sein Skript da schon. Schwierig wird es dann, wenn der übergebene Wert aus dem Link den betroffenen Bereich des Menüs nicht mehr direkt (via ID oder Elter-Zeige) adressieren kann.

                              Um das zu erreichen benötigt man alle Eltern der ID aus dem angesprochenen Link. Entweder kann man die im Link übermitteln oder eben - wie Du, Chriz, in Deiner Breadcrumbs-Funktion - per PHP ermitteln.

                              Der Zugriff auf die Daten, also ob nun einmal der komplette Baum sequentiell in ein Array oder einen Objektbaum eingelesen wird oder ob ein rekursiver Zugriff auf die Datenbank erfolgt, spielt für das Problem aus der Eingangsfrage eigentlich keine Rolle.

                              Btw.: Die Foreach-Schleife hinter der Ausleseschleife für die DB kannst Du in Deinem Code auch noch eliminieren, Chriz.

                              PHP-Code:
                              $result mysql_query("SELECT * FROM menu");
                              $menus  = array();
                              while (
                              $line mysql_fetch_assoc($result)) {
                                  
                              $menu = new Menu();
                                  
                              $menu->id     $line['id'];

                                  
                              $menu->parent = &$menus[$line['parent_id']]; // Referenz erspart zweite Schleife

                                  
                              $menu->name   $line['name'];
                                  
                                  
                              $menus[$menu->id] = $menu;

                              Gruß Jens

                              Kommentar

                              Lädt...
                              X