Avatar billede Mik2000 Professor
02. februar 2014 - 16:16 Der er 7 kommentarer og
1 løsning

Menu fra db til ul li

Hej

Jeg har en menu der er opbygget som følger i en mysql db:
id (int)
subid (int)
Navn (varchar)

subid er 0 hvis det er et toppunkt, og ellers har det det id det hører under

Data kunne f.eks. være
1, 0, Toppunkt 1
2, 0, Toppunkt 2
3, 0, Toppunkt 3
4, 2, Underpunkt 2,1
5, 2, Underpunkt 2,2
6, 5, Underunderpunkt 2,2,1
7, 5, Underunderpunkt 2,2,2
8, 3, Underpunkt 3,1

Det skulle gerne ende med en liste i stil med

<ul>
<li>Toppunkt 1</li>
<li>Toppunkt 2
  <ul>
  <li>Underpunkt 2,1</li>
  <li>Underpunkt 2,2
      <ul>
      <li>Underpunkt 2,2,1</li>
      <li>Underpunkt 2,2,2</li>
      </ul>
  </li>
  </ul>
</li>
<li>Toppunkt 3
  <ul>
  <li>Underpunkt 3,1</li>
  </ul>
</li>
</ul>

Jeg har fundet en recursiv funktioner der kalder sig selv. Men den kører en sql forespørgsel pr. punkt, og de advarer om memory problemer.

Kan man evt. tage den ud i et array først, eller hvordan gør man det smartest?

Spørg endelig løs hvis der er noget jeg ikke har forklaret godt nok :). Håber I kan hjælpe :)
Avatar billede arne_v Ekspert
03. februar 2014 - 03:38 #1
Til inspiration:

<?php
/*
CREATE TABLE menu (id INTEGER NOT NULL, parentid INT NULL, label VARCHAR(50), PRIMARY KEY(id));
INSERT INTO menu VALUES (1, 0, 'Toppunkt 1');
INSERT INTO menu VALUES (2, 0, 'Toppunkt 2');
INSERT INTO menu VALUES (3, 0, 'Toppunkt 3');
INSERT INTO menu VALUES (4, 2, 'Underpunkt 2,1');
INSERT INTO menu VALUES (5, 2, 'Underpunkt 2,2');
INSERT INTO menu VALUES (6, 5, 'Underunderpunkt 2,2,1');
INSERT INTO menu VALUES (7, 5, 'Underunderpunkt 2,2,2');
INSERT INTO menu VALUES (8, 3, 'Underpunkt 3,1');
*/

class RawMenuItem {
    public $parentid;
    public $label;
    public function __construct($parentid, $label) {
        $this->parentid = $parentid;
        $this->label = $label;
    }
};

class TreeMenuItem {
    public $label;
    public $subs;
    public function __construct($label) {
        $this->label = $label;
        $subs = array();
    }
}

function load() {
    $rawmenu = array();
    $con = new mysqli('localhost', 'root', '', 'Test');
    $stmt = $con->prepare('SELECT id,parentid,label FROM menu');
    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result($id, $parentid, $label);
    while($stmt->fetch()) {
        $rawmenu[$id] = new RawMenuItem($parentid, $label);
    }
    $stmt->close();
    $con->close();
    return $rawmenu;
};

function raw2tree_level($value, &$a, $rawmenu) {
    foreach($rawmenu as $id => $item) {
        if($item->parentid === $value) {
            $a[$id] = new TreeMenuItem($item->label);
            raw2tree_level($id, $a[$id]->subs, $rawmenu);
        }
    }
}

function raw2tree($rawmenu) {
    $treemenu = array();
    raw2tree_level(0, $treemenu, $rawmenu);
    return $treemenu;
}

define('INDENT_LEVEL','  ');

function display_list($indent, $treemenu) {
    echo $indent . "<ul>\r\n";
    foreach($treemenu as $id => $item) {
        echo $indent . INDENT_LEVEL . '<li>' . $item->label . "</li>\r\n";
        if(count($item->subs) > 0) display_list($indent . INDENT_LEVEL, $item->subs);
    }   
    echo $indent . "</ul>\r\n";   
}

$rawmenu = load();
$treemenu = raw2tree($rawmenu);
display_list('', $treemenu);

?>
Avatar billede Mik2000 Professor
04. februar 2014 - 22:42 #2
Hej Arne

Endnu engang tak for dit store arbejde med at hjælpe :).

En enkelt ting - den menu jeg bruger kræver den ligger således
<ul>
<li>navn
  <ul>
  <li>navn 2</li>
  </ul>
</li>
</ul>

Dvs hvor den nye ul ligger inde i den li hvor den hører til i.
Er det meget avanceret at rette. Har ikke lavet så meget objektorienteret programmering, så er ikke helt sikker på hvordan jeg skal rette det.

--------

Så lige et dumt spørgsmål
Som jeg forstår det, så laver du et array med alt indholdet fra databasen hvor id er nøglen. Inde i det array har du så parentid og label - men ligger de i et array i arrayet eller hvordan er de gemt som to forskellige værdier (håber ikke det er et alt for dumt spørgsmål, men er ikke helt sikker på hvad funktionen RawMenuItem gør)
Avatar billede arne_v Ekspert
04. februar 2014 - 22:53 #3

function display_list($indent, $treemenu) {
    echo $indent . "<ul>\r\n";
    foreach($treemenu as $id => $item) {
        echo $indent . INDENT_LEVEL . '<li>' . $item->label . "</li>\r\n";
        if(count($item->subs) > 0) display_list($indent . INDENT_LEVEL, $item->subs);
    } 
    echo $indent . "</ul>\r\n"; 
}


til:


function display_list($indent, $treemenu) {
    echo $indent . "<ul>\r\n";
    foreach($treemenu as $id => $item) {
        echo $indent . INDENT_LEVEL . '<li>' . $item->label . "\r\n";
        if(count($item->subs) > 0) display_list($indent . INDENT_LEVEL, $item->subs);
        echo $indent . INDENT_LEVEL . '</li>' . "\r\n";
    } 
    echo $indent . "</ul>\r\n"; 
}


burde fixe det.
Avatar billede arne_v Ekspert
04. februar 2014 - 22:54 #4
Jeg bruger ikke array af array men array af class - en class kan indeholder flere fields.
Avatar billede Mik2000 Professor
08. februar 2014 - 15:12 #5
Hej Arne

Det ser rigtig fint ud, og virker som det skal.
Det kunne være jeg skulle få kigget på det, for det ser da smart ud.

Tak for hjælpen - der er selvfølgelig point :)
Avatar billede arne_v Ekspert
08. februar 2014 - 15:47 #6
svar
Avatar billede Mik2000 Professor
08. februar 2014 - 18:30 #7
Jeg stiller lige et ekstra spørgsmål, som måske er dumt da jeg ikke har meget erfaring med oop

Hvis nu jeg vil have flere felter med fra databasen, som jeg kan bruge - hvorledes gør jeg så det.

Jeg har prøvet følgende for at få et felt med der hedder linktype, men må misforstå noget

Der sker det at den vist skriver linktypen som label (og jeg kan ikke få adgang til begge) :(

class RawMenuItem {
    public $parentid;
    public $label;
    public $linktype;
    public function __construct($parentid, $label, $linktype) {
        $this->parentid = $parentid;
        $this->label = $label;
        $this->linktype = $linktype;
    }
};

class TreeMenuItem {
    public $label;
    public $subs;
    public function __construct($label) {
        $this->label = $label;
        $subs = array();
    }
}

function load() {
    $rawmenu = array();
    $con = new mysqli('localhost', 'root', '', 'Test');
    $stmt = $con->prepare('SELECT id,parentid,label, linktype FROM menu');
    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result($id, $parentid, $label, $linktype);
    while($stmt->fetch()) {
        $rawmenu[$id] = new RawMenuItem($parentid, $label, $linktype);
    }
    $stmt->close();
    $con->close();
    return $rawmenu;
};

function raw2tree_level($value, &$a, $rawmenu) {
    foreach($rawmenu as $id => $item) {
        if($item->parentid === $value) {
            $a[$id] = new TreeMenuItem($item->label);
            raw2tree_level($id, $a[$id]->subs, $rawmenu);
        }
    }
}

function raw2tree($rawmenu) {
    $treemenu = array();
    raw2tree_level(0, $treemenu, $rawmenu);
    return $treemenu;
}

define('INDENT_LEVEL','  ');

function display_list($indent, $treemenu) {
    echo $indent . "<ul>\r\n";
    foreach($treemenu as $id => $item) {
        echo $indent . INDENT_LEVEL . '<li>' . $item->label . ' - ' .  $item->linktype .  "\r\n";
        if(count($item->subs) > 0) display_list($indent . INDENT_LEVEL, $item->subs);
        echo $indent . INDENT_LEVEL . '</li>' . "\r\n";
    } 
    echo $indent . "</ul>\r\n"; 
}

$rawmenu = load();
$treemenu = raw2tree($rawmenu);
display_list('', $treemenu);
Avatar billede arne_v Ekspert
08. februar 2014 - 21:21 #8
Du skal have linktype i TreeMenuItem og kopiere deb over i raw2tree.
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