Avatar billede tipsen Nybegynder
02. november 2003 - 21:50 Der er 10 kommentarer og
1 løsning

Generer <list> menu udfra db-baseret træmenu.

Hej eksperter

Jeg leder efter en nem og pæn måde at transformere et træbaseret menusystem fra en MySQL tabel til en html-liste form!

Strukturen af tabellen er:

#
# Struktur dump for tabellen `menu`
#

CREATE TABLE menu (
  id int(10) unsigned NOT NULL auto_increment,
  parentId int(10) unsigned default NULL, //evt. forælder id - null for hovedpunkt
  priority smallint(6) NOT NULL default '0', //bruges til rækkefølge af menupunkter
  title varchar(255) NOT NULL default '', //menupunktets titel
  description varchar(255) NOT NULL default '', //beskrivelse af menupunktet
  url varchar(255) NOT NULL default '', //menupunktets url
  PRIMARY KEY  (id),
  KEY pid (parentId)
) TYPE=MyISAM COMMENT='Tree based menu system';

Eksempel på dump fra tabellen:

#
# Data dump for tabellen `menu`
#

INSERT INTO menu VALUES (1, NULL, 0, 'Personal', 'Personal stuff', '?cid=5');
INSERT INTO menu VALUES (2, NULL, 0, 'Study', 'Study related stuff', '?cid=7');
INSERT INTO menu VALUES (3, 1, 0, 'Guestbook', 'Sign and read the guestbook', '?cid=8');

Dvs. her har vi to hovedpunkter samt et underpunkt, hvilket gerne skulle give anledning til følgende liste i html:

<ul>
  <li>Personal</li>
  <ul>
      <li>Guestbook</li>
  </ul>
  <li>Study</li>
</ul>

-eller:

<ul>
  <li>Personal</li>
  <ul>
      <li>Guestbook</li>
  </ul>
</ul>
<ul>
  <li>Study</li>
</ul>

Ideen er at det script/den funktion der konverterer menuen til html-kode skal fungere ligegyldigt, hvor mange nestede menupunkter der findes - den skal bare lave listestrukturen efter ovenstående logik.

Jeg tror problemstillingen kan løses meget nemt og "pænt", hvis man lige har den rigtige ide - og jeg synes mine egne ideer har været temmeligt dårlige indtil videre - der *må* være en pæn løsning til dette problem!

Jeg overvejede lidt om man måske kunne bruge HTML_Menu fra PEAR, men kunne ikke lige få det til at hænge sammen... (http://pear.php.net/package/HTML_Menu)

Håber på nogle gode konstruktive forslag!

Mvh

Tommy Ipsen
Avatar billede detox Nybegynder
02. november 2003 - 23:20 #1
Her er et bud:

<?
require 'connect.inc.php';
$res = mysql_query("SELECT id, parentId, title FROM menu ORDER BY parentId, priority");
while ($row = mysql_fetch_row($res)) {
    if (!$row[1]) $pkt[$row[0]][] = $row[2];
    else array_push($pkt[$row[1]], $row[2]);
}
$out = "";
foreach ($pkt as $menu) {
    $antal = count($menu);
    for ($i=0;$i<$antal;$i++) {
        $out .= "<ul>\n<li>".$menu[$i]."</li>\n";
    }
    for ($i=0;$i<$antal;$i++) {
        $out .= "</ul>\n";
    }
}
echo $out;
?>
Avatar billede rackbox Nybegynder
04. november 2003 - 00:40 #2
Du kan også lave en rekursiv funktion:

function add_list($indent,$id){
  $indent++;
  $query = "select * from menu where id=$id";
  $result = mysql_query($query);
  while ($row=mysql_fetch_array($result)){
      $return.=str_repeat("-",$indent).add_list($indent,$row['id'];
  }
  return $row['id'];
}

Funktionen er beregnet til at vise princippet og vil ikke virke med dine data...
Avatar billede Slettet bruger
04. november 2003 - 00:49 #3
Det er måske bare mig, men den rekursive funktion laver et query for hver punkt eller hvad?

Det er da ret meget spild af ressourcer :)
Avatar billede rackbox Nybegynder
04. november 2003 - 01:05 #4
Det er et princip-eksempel.. det kan laves MEGET smartere med statiske variable, etc.. Gad bare ikke at lave alt for meget kode, hvis svaret alligevel ikke bliver godtaget ;-)
Avatar billede tipsen Nybegynder
04. november 2003 - 13:07 #5
Jeg tror ikke at en rekursiv funktion er svaret her (slet ikke, hvis den involverer queries for hvert kald) - det bør kunne laves dynamisk og dermed hurtigere - så er det også mere sandsynligt, at det vil fungere for større menusystemer og ikke tage for mange systemressourcer.

Jeg vil lige kigge nærmere på detox' udgave og se om den er "bulletproof" :)
Avatar billede detox Nybegynder
04. november 2003 - 13:30 #6
Jeg kan forstå du ønsker flere niveauer af menuer og så dur mit forslag ikke, men måske du kan bruge idéen alligevel.
Avatar billede tipsen Nybegynder
04. november 2003 - 13:36 #7
Skidtet skal fungere uanset antal nestede submenuer - sålænge posterne i db'en er konsistente!
Avatar billede tipsen Nybegynder
04. november 2003 - 19:21 #8
Jeg har nu bikset lidt rundt med Tree klassen i PHP, men kan ikke rigtigt få den til at fungere (De vedlagt docs/eksempler fungerer heller ikke) :-/

-det må da kunne lade sig gøre, at finde en pæn løsning til dette problem.
Avatar billede tipsen Nybegynder
04. november 2003 - 21:29 #9
For de interesserede er der lidt om træstrukturer i en db her:

http://www.sitepoint.com/print/1105
Avatar billede tipsen Nybegynder
12. november 2003 - 12:57 #10
Rettelse - den genererede listestruktur skal ligne denne:

<ul>
  <li>Personal
  <ul>
      <li>Guestbook</li>
  </ul>
  </li>
</ul>
<ul>
  <li>Study</li>
</ul>

Jeg regner med at det må være muligt at benytte PEAR::Tree til at komme fra db-strukturen til en passende arraystruktur - derefter kan der benyttes en modificeret udgave af PEAR::HTML_Menu til at generere selve html-koden (altså listestrukturen)

Jeg har næsten fået modificeret HTML_Menu, så den kan spytte det ønskede output ud, men jeg kan ikke få Tree til at give mig et output der kan bruges af HTML_Menu :-(

Håber stadig at der er nogen der kan hjælpe!
Avatar billede limemedia Nybegynder
12. november 2003 - 13:19 #11
Okay Hr. Tipsen :)
Det er ikke en sølvfads løsning ! Men jeg har noget der tilnærmelsesvist minder om din situation... Koden er herunder. Det er fra et uendeligt trået forum system (skift selv DB kaldet og det kan være din gæstebog - et træ er et træ er et...)

Der genereres et forholdsvist simpelt array (brug print_r($output)) til at se opbygningen. Du vil med variablen indent kunne se hvor dybt du er i træet. Hvis indent er større end linien før, et du et niveau lavere, er den mindre, et niveau højere. Men du vil hurtigt gennemskue det, og dit output vil kunne genereres gennem en simpel løkke struktur gennem arrayet

/ LJ


<?php
    # Code by Lars B. Jensen, lars.jensen@ljweb.com
    # All Rights Reserved.

    function forum_category_list() {
        $query = "
            SELECT id, parent_id, title, descr
            FROM forum_category
            WHERE online='1'
            ORDER BY parent_id ASC, stamp ASC
        ";
        $sql = mysql_query($query) or die(mysql_error());

        if (!mysql_num_rows($sql)) {
            return array();
            exit;
        }

        $header = array();
        $connect = array();

        while($foo = mysql_fetch_assoc($sql)) {
            $header[$foo['id']] = array('title'=>$foo['title'],'descr'=>$foo['descr']);
            $connect[$foo['parent_id']][] = $foo['id'];
        }

        return _category_connect($header, $connect);
    }


    /* PRIVATE FUNCTIONS */

    function _forum_query($query) {
        $sql = mysql_query($query) or die(mysql_error());

        $res = array();
        if (!mysql_num_rows($sql)) {
            return $res;
            exit;
        }

        while ($foo = mysql_fetch_assoc($sql)) {
            $res[] = $foo;       
        }

        mysql_free_result($sql);

        return $res;
    }

    function _category_connect($head, $connect) {
        ksort($connect);
        reset($connect);

        $res = array();
        $indent = 0;

        for($i=0; $i<sizeof($connect[0]); $i++) {
            $res[] = array('id'=>$connect[0][$i], 'title'=>$head[$connect[0][$i]]['title'], 'descr'=>$head[$connect[0][$i]]['descr'], 'indent'=>$indent);
            $res = _category_connect_recurse($res, $head, $connect, $connect[0][$i]);
        }
       
        return $res;
    }

    function _category_connect_recurse($res, $head, $connect, $index, $indent=1) {
        if (isset($connect[$index])) {
            for($i=0;$i<sizeof($connect[$index]);$i++) {
                $res[] = array('id'=>$connect[$index][$i], 'title'=>$head[$connect[$index][$i]]['title'], 'descr'=>$head[$connect[0][$i]]['descr'], 'indent'=>$indent);
                $res = _category_connect_recurse($res, $head, $connect, $connect[$index][$i], $indent+1);
            }
        }
        return $res;
    }
?>
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester