[PHP] Database driven treemenu mogelijk?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Gusev
  • Registratie: December 2006
  • Laatst online: 01:06
Momenteel ben ik bezig met het uitbreiden van een CMS/MIS systeem voor mijn werkgever.

Hierin zou ik graag een treemenu/folderstructuur-menu willen maken.

De parentitems komen in mijn geval uit "tabel1" uit een database die op een MSSQL server staat. De childs en de subchilds zou ik er graag bijwillen zoeken d.m.v. de vreemde sleutels in andere tabellen.

Ik heb overal gezocht en ook een aantal topics doorgenomen, maar kom er niet uit.

Wat ik dus eigenlijk wil is het volgende:

Parent 1 (Tabel 1, ID)
|------------Child 1 (Tabel 2, vreemdesleutel naar tabel 1)
|--------------SubChild 1 (Tabel 3, vreemdesleutel naar tabel 2)
|------------Child 2

Enzovoort.

Momenteel gebruik ik een javascript + CSS file gecombineerd met een UL/LI opbouw in PHP. Vanzelfsprekend is dit om te huilen mede doordat het niet objectgeorienteerd geprogrammeerd is.

Kan iemand mij plz helpen...ik kom er niet meer! tnx!

Voorbeeldcode kan eventueel worden gepost, maar die wil ik jullie eigenlijk onthouden :+

edit: Om het nog iets te verduidelijken, Het probleem ligt hem dus niet in het opvragen of ophalen van de goede sleutels, maar puur op het opbouwen van de treemenu....->javascript richting?? en geen UL LI's meer hopelijk O-)

[ Voor 9% gewijzigd door Gusev op 08-07-2008 11:00 ]


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
UL LI's nesten is gewoon de mooie manier? Voor de opbouw zie (oa, dit is ecfht wel te vinden): http://crisp.tweakblogs.n...using-only-one-query.html

{signature}


Acties:
  • 0 Henk 'm!

Verwijderd

Kun je niet gewoon alle items kwijt in één tabel? En dan gewoon een recursieve functie.

zoals die link van crisp zijn blog

[ Voor 21% gewijzigd door Verwijderd op 08-07-2008 11:23 ]


Acties:
  • 0 Henk 'm!

  • Gusev
  • Registratie: December 2006
  • Laatst online: 01:06
Ik heb even naar het voorbeeld gekeken, maar vind het best lastig om eerlijk te zijn.

In hoeverre het in 1 tabel kan...ik denk dat het antwoord daar simpelweg nee op is. Aangezien de database niet door mij wordt onderhouden/gevuld of wat dan ook, ik moet er alleen gegevens uit lezen.

Ik zal proberen om het duidelijker te maken:

Tabel 1: Trainer
Tabel 2: Trainingen

De parent moet dan alle trainers zijn en de childs alle trainingen bij de bijbehorende trainer. Nogmaals, het opvragen daar zit het probleem niet, echt alleen in het weergeven in een treemenu vorm...

p.s. Ik ben geen uber PHP programmeur zoals jullie waarschijnlijk hebben gemerkt maargoed :P

Acties:
  • 0 Henk 'm!

Verwijderd

Gusev schreef op dinsdag 08 juli 2008 @ 11:30:
Ik heb even naar het voorbeeld gekeken, maar vind het best lastig om eerlijk te zijn.

In hoeverre het in 1 tabel kan...ik denk dat het antwoord daar simpelweg nee op is. Aangezien de database niet door mij wordt onderhouden/gevuld of wat dan ook, ik moet er alleen gegevens uit lezen.

Ik zal proberen om het duidelijker te maken:

Tabel 1: Trainer
Tabel 2: Trainingen

De parent moet dan alle trainers zijn en de childs alle trainingen bij de bijbehorende trainer. Nogmaals, het opvragen daar zit het probleem niet, echt alleen in het weergeven in een treemenu vorm...

p.s. Ik ben geen uber PHP programmeur zoals jullie waarschijnlijk hebben gemerkt maargoed :P
Dan zet je het in een array en loop je daaroverheen met een recursieve functie a la die van crisp.

Bijvoorbeeld:

$items[0] = "Trainer";
$items[0][0] = "Training #1";
$items[0][0][0] = "Locatie #1";

Enzovoorts.

Acties:
  • 0 Henk 'm!

  • Gusev
  • Registratie: December 2006
  • Laatst online: 01:06
Verwijderd schreef op dinsdag 08 juli 2008 @ 12:05:
[...]

Dan zet je het in een array en loop je daaroverheen met een recursieve functie a la die van crisp.

Bijvoorbeeld:

$items[0] = "Trainer";
$items[0][0] = "Training #1";
$items[0][0][0] = "Locatie #1";

Enzovoorts.
Daar ga ik even mee aan de slag tnx!!!

Alleen het voorbeeld van crisp werkt niet helemaal bij mij, ik zie echt niet meer wat ik verkeerd doe :(

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php

$db = "menu"; 
$server = "localhost"; 
$gebruiker = "root"; 
$wachtwoord = "*****"; 

$con = mysql_connect($server,$gebruiker,$wachtwoord);
if (!$con)
  {
  die('Could not connect: ' . mysql_error());
  }

mysql_select_db($db, $con);  
  
// get all menuitems with 1 query
$res = mysql_query("
    SELECT
        id, parentId, name
    FROM
        menu
    ORDER BY
        parentId, name
");


// prepare special array with parent-child relations
$menuData = array(
    'items' => array(),
    'parents' => array()
);

$menuItem = mysql_fetch_assoc($res);

while ($menuItem)
{
    $menuData['items'][$menuItem['id']] = $menuItem;
    $menuData['parents'][$menuItem['parentId']][] = $menuItem['id'];
}

// menu builder function, parentId 0 is the root
function buildMenu($parentId, $menuData)
{
    $html = '';

    if (isset($menuData['parents'][$parentId]))
    {
        $html = '<ul>';
        foreach ($menuData['parents'][$parentId] as $itemId)
        {
            $html .= '<li>' . $menuData['items'][$itemId]['name'];

            // find childitems recursively
            $html .= buildMenu($itemId, $menuData);

            $html .= '</li>';
        }
        $html .= '</ul>';
    }

    return $html;
}

// output the menu
echo buildMenu(0, $menuData);
?>


Warning: mysql_fetch_assoc(): supplied argument is not a valid MySQL result resource in ...\index.php on line 33

Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Gebruik tijdens het debuggen altijd:

PHP:
1
$result = mysql_query("...") or die(mysql_error());


Verder is het niet verkeerd om te controleren of mysql_numrows($result)!=0.

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • Saven
  • Registratie: December 2006
  • Nu online

Saven

Administrator

doe eens:
PHP:
1
2
3
4
5
6
7
8
$res = mysql_query("
    SELECT
        id, parentId, name
    FROM
        menu
    ORDER BY
        parentId, name
")or die(mysql_error());

Acties:
  • 0 Henk 'm!

  • GlowMouse
  • Registratie: November 2002
  • Niet online
Bozozo schreef op dinsdag 08 juli 2008 @ 12:30:
Gebruik tijdens het debuggen altijd:

PHP:
1
$result = mysql_query("...") or die(mysql_error());


Verder is het niet verkeerd om te controleren of mysql_numrows($result)!=0.
Of nog beter: schrijf je eigen db-klasse zodat je met een enkele constante aangeeft of je in debugmodus zit of niet. Anders vergeet je die or die een keer weg te halen voor een live-omgeving, laat je een sql injection bug liggen, en maak je het sommigen alleen maar makkelijker.

Leuke loop trouwens op regel 35. Die zal niet snel stoppen ;)

Acties:
  • 0 Henk 'm!

  • Gusev
  • Registratie: December 2006
  • Laatst online: 01:06
heb het een en ander aangepast zoals hierboven is geadviseerd :P maarre denk dat het gewoon iets teveel van het goede voor mij is...krijg nu de foutmelding:

Unknown column 'name' in 'field list'

Acties:
  • 0 Henk 'm!

  • ripexx
  • Registratie: Juli 2002
  • Laatst online: 17:49

ripexx

bibs

Sorry, maar even verder zoeken kan geen kwaad, toch? Je zegt zelf dat je geen "uber" php programmeur bent, maar dit is echt basics. De foutmelding geeft aan dat de variabele die de functie mysql_fetch_assoc() mee krijgt niet voldoet. Ga dan terug in de code en probeer uit te vinden waarom dat waarschijnlijk niet gaat werken.

In het algemeen, als jij de situatie trainer->training in een tree wil weergeven dan is dat toch niet zo lastig? Alleen gaat het dan niet om een recursief verhaal met parent-child constructies.

Stap 1: Haal de data op uit de database (dit kun je testen in verschillende tools), als deze query klopt krijg je een recordset (soort tabel) terug.
Stap 2: vertaal de recordset naar een gebruikers interface.

In pseudo code:
Recordset
Trainer Training
Jan PHP
Jan MySQL
Piet C#
Piet MS SQL 2005

Dit moet worden:
HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ul>
  <li>Jan
    <ul>
       <li>PHP</li>
       <li>MySQL</li>
     </ul>
  </li>
  <li>Piet
     </ul>
       <li>C#</li>
       <li>MS SQL 2005</li>
     </ul>
  </li>
</ul>


De kunst is nu om zo door de tabel heen te lopen (loop?) en dan het gewenste resultaat samen te stellen. Kijk ook eens naar wat basic tutorials op het internet.
Gusev schreef op dinsdag 08 juli 2008 @ 12:39:
heb het een en ander aangepast zoals hierboven is geadviseerd :P maarre denk dat het gewoon iets teveel van het goede voor mij is...krijg nu de foutmelding:

Unknown column 'name' in 'field list'
Als je niet wil lerendan kunnen we net zo goed stoppen. Verdiep je eens wat meer in de materie. Maar verwacht niet dat wij hier even jou probleem gaan oplossen.

[ Voor 15% gewijzigd door ripexx op 08-07-2008 12:43 ]

buit is binnen sukkel


Acties:
  • 0 Henk 'm!

  • Gusev
  • Registratie: December 2006
  • Laatst online: 01:06
Ik heb er serieus veel tijd ingestoken en 'stap 1' heb ik dan ook wel voor elkaar. En ik kom gewoon niet verder met 'stap 2'...maargoed ik ga maar weer even wat basic tutorials doornemen

Acties:
  • 0 Henk 'm!

  • ripexx
  • Registratie: Juli 2002
  • Laatst online: 17:49

ripexx

bibs

Gusev schreef op dinsdag 08 juli 2008 @ 12:46:
Ik heb er serieus veel tijd ingestoken en 'stap 1' heb ik dan ook wel voor elkaar. En ik kom gewoon niet verder met 'stap 2'...maargoed ik ga maar weer even wat basic tutorials doornemen
Dat je er veel tijd in moet stoppen is iets wat bij het leren hoort. Een oplossing is stap voor stap te beschrijven wat je moet doen om van de ene structuur naar de andere te komen. Om je even op weg te helpen:

Start
1. Voor elke recordset begin met "<UL>"
2. Voor elke eerste unieke trainer doe ...
enz enz

Of maak een flow chart oid.

buit is binnen sukkel


Acties:
  • 0 Henk 'm!

  • Gusev
  • Registratie: December 2006
  • Laatst online: 01:06
hmm..ik begin denk ik te begrijpen wat je bedoeld...

Even heel basic (weer :P):

code:
1
2
3
4
5
6
7
8
9
<?php

echo "<ul>";
     echo "<li>";
          //de loop komt dan hier met o.a. mijn SQL statement
     echo "</li>";
echo "</ul>";

?>


Ben ik zo op de goede weg, want dan ga ik er mee aan de slag?

edit: Dit is dan alleen de trainers niveau, binnen die li komt dan ook weer een ul met li zoals in jouw voorbeeld...

[ Voor 16% gewijzigd door Gusev op 08-07-2008 12:58 ]


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Dude, die vraag is echt te eenvoudig als je weet wat een ul resp. een li is. Desnoods schrijf je gewoon ff direct html, zodat je 1 ding tegelijk aan het leren bent. :z

{signature}


Acties:
  • 0 Henk 'm!

  • OxiMoron
  • Registratie: November 2001
  • Laatst online: 08-07 14:27
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function buildTree($rows) {         
    $menu = array();
    $references = array();
    foreach($rows as $row) {
        $thisref = &$references[ $row['id'] ];
        //We need this, or we'll overwrite the reference.
        foreach($row as $key => $value) 
            $thisref[$key] = $row[$key];                

        if ($row['parent_id'] === null) {
            $menu[ $row['id'] ] = &$thisref;
        } else {
            $references[ $row['parent_id'] ]['children'][ $row['id'] ] = &$thisref;
        }
    }       
    return $menu;
}


$rows zijn gewoon alle rows uit de tabel waarbij parent_id NULL is of verwijst naar een ander element in dezelfde tabel.

Als return komt een lijst van hoofdelementen met bij elk element de children key gevult met z'n subelementen. (Tot oneindig diep)

Dit is de snelste manier om van een platte table structuur een tree te maken, je hoeft maar 1 keer door je data heen om de tree op te bouwen en je kunt gewoon een simpele SELECT * query doen op de tabel.

Lang leve references :)


Voor weergave (even uit de losse pols):
code:
1
2
3
4
5
6
7
8
9
10
11
function printItem($item) {
    echo '<li>'.$item['title'];
    if (isset($item['children'])) {
        echo '<ul>';
        foreach($item['children'] as $child) {
            printItem($child);
        }
        echo '</ul>';
    }
    echo '</li>';
}

Albert Einstein: A question that sometime drives me hazy: Am I or are the others crazy?


Acties:
  • 0 Henk 'm!

  • Joolee
  • Registratie: Juni 2005
  • Niet online
Maar dan ga je recursief werken, iets dat niet nodig is bij het probleem van de TS omdat zijn tree maar 2 lagen diep is.
Ik zou het zelf gewoon zo oplossen: (geen idee of dat de juiste manier is)
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<ul>
<?PHP
while ($row = fetch()) {
    if(empty($currentinstructor) || $currentinstructor != $row['instructor']) {
        if(!empty($currentinstructor)) {
            // Sluit lijst oude instructor af
            // </ul>
            // </li>
        }
        
        $currentinstructor = $row['instructor'];
        
        // Start nieuwe lijst voor instructor
        // <li> $currentinstructor
        // <ul>
    }
    
    // <li> $row['training'] </li>
}
?>
</ul>

Acties:
  • 0 Henk 'm!

  • TeeDee
  • Registratie: Februari 2001
  • Laatst online: 20-09 23:58

TeeDee

CQB 241

Joolee schreef op dinsdag 08 juli 2008 @ 16:26:
[...]

Maar dan ga je recursief werken, iets dat niet nodig is bij het probleem van de TS omdat zijn tree maar 2 lagen diep is.
Totdat er een 3e laag nodig is. Ik ben me bewust van het fenomeen YAGNI, maar komop: iets triviaals als een recursieve method om een simpel treemenu te bouwen; daar zou ik niet eens op besparen.

Heart..pumps blood.Has nothing to do with emotion! Bored


Acties:
  • 0 Henk 'm!

  • Error65
  • Registratie: Oktober 2001
  • Laatst online: 12-01-2023

Error65

Error Inside

Ik weet niet of je er iets aan hebt, maar misschien brengt dit menu je op een idee.

Het menu wordt aan de hand van javascript methoden geschreven. Het maakt niet uit in welke volgorde de elementen worden geplaatst, zolang de verwijzingen maar goed staan. Zodoende kan je met een simpele query al je items uit de database halen en (zonder te sorteren) direct wegschrijven.

Aangezien ik dit menu zo'n 6 jaar geleden heb gemaakt, kan het zijn dat het niet zo netjes in elkaar zit :9 Het is daarom niet aan te raden om dit menu te gebruiken ;)

http://www.uitdehoogte.nl/bert


Acties:
  • 0 Henk 'm!

Verwijderd

Ik vind dat Jolee de 'juiste' oplossing heeft. (Die van Crisp is nog beter natuurlijk ;))

SELECT a.id, b.id
FROM forums
JOIN b
ON a.id = b.foreignId

zou de sql-query kunnen zijn die bij zijn php-code hoort. Alleen niet zulke crappy benamingen :P

Acties:
  • 0 Henk 'm!

  • Gusev
  • Registratie: December 2006
  • Laatst online: 01:06
Wat mij betreft kan er een slotje op...het is gelukt :)

Ik heb het met het voorbeeld van deze website werkend gekregen:

CSSCreator

Misschien niet de beste manier, maargoed...Iedereen bedankt! Enne morgen ga ik de manier van Joolee en Error65 uitproberen...Nu maar is naar huis 8)7

Acties:
  • 0 Henk 'm!

  • H004
  • Registratie: Maart 2006
  • Laatst online: 28-05 19:55
Ik hoop dat je niet de Javascript uit die versie gebruikt want:
Browser Support

Works with: IE 5, IE 5.5, IE 6, NN 7.1, Mozilla 1.3 Opera 7.01, Opera 7.22, Phoenix 0.5, Firebird 0.7 on Windows, Camino 0.7 on Mac
Fails in: NN4, Opera 6.05 on Windows. Safari 1.0, IE5.2 on Mac
T werkt dus niet in FF3, IE6, IE7...
Pagina: 1