Menu opbouw met verschillende niveaus

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Sam Clauw

Sam Clauw

16/12/2010 15:04:16
Quote Anchor link
Hallo iedereen!

Ik ben opnieuw mijn hoofd aan het breken op welke manier ik een menu opbouw met verschillende niveaus. Ik heb reeds een tabel gemaakt waarin ik de verschillende pagina's opnam. Zo ziet het er nu uit:

id--title---------------parent--weight--active--

1---Home----------------0-------1-------1-------
2---De winkel-----------0-------2-------1-------
3---Producten-----------0-------3-------1-------
4---Optische illusies---0-------4-------1-------
5---Contact-------------0-------5-------1-------
6---Links---------------0-------6-------1-------
7---Monturen------------3-------1-------0-------
8---Zonnebrillen--------3-------2-------0-------
9---Lenzen--------------3-------3-------0-------
10--Hoorapparaten-------3-------4-------0-------
11--Glazen--------------3-------5-------0-------

De bedoeling is dus om een menustuctuur op te zetten met <ul>'s en <li>'s. Ik heb allemaal php kronkels in m'n hoofd maar kan jammer genoeg de eindjes niet aan elkaar knopen. Met m'n opzoekwerk schat ik dat ik gebruik kan maken van recursie. Het proces snap ik min of meer, maar ik weet niet hoe ik het toe kan passen in deze situatie. Hier is mijn menu code tot nu toe (werkt enkel voor één niveau, het hoofdniveau):

<ul id="menu">

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
    
    $menu
= new mysqli(MYSQL_SERVER,MYSQL_USER,MYSQL_PASS,MYSQL_DB);
    
    $sql = "SELECT id, title, parent, weight, active FROM pages WHERE active = 1 ORDER BY weight ASC";
    
    if(!$result = $menu->query($sql)){
        trigger_error('Fout in query:' . $menu->error);
    }
else{
        $i = 0;
        while($row = $result->fetch_assoc()){
        
            $i++;                        
            $totalRows = mysqli_num_rows($result);

            // Spaties in de URL vervangen door koppeltekens
            $title = str_replace(' ', '-', $row['title']);
            // URL omzetten naar kleine letters
            $title = strtolower($title);
            
            // Laatste pagina?
            $last = '';
            if($i == $totalRows){
                $last = 'last';
            }

            
            // Pagina actief?
            if (strpos($page, $title)){
                echo '<li class="active ' . $last . '"><a href="/' . $title . '" title="' . $row['title'] . '">' . $row['title'] . '</a></li>' . "\n";
            }
else{
                echo '<li class="' . $last . '"><a href="/' . $title . '" title="' . $row['title'] . '">' . $row['title'] . '</a></li>' . "\n";                            
            }
        }
    }


    $menu->close();

    ?>


</ul>

Bedoeling is dus dat wanneer 'active' op '0' staat, dat het item NIET in het menu getoond wordt. Ik wil de volledige menu structuur echter wel in de database stoppen, zo kan ik m'n sitemap dynamisch creëren. Kan iemand mij een duwtje in de rug geven? Een ruwe en onvolledige code opbouw kan mij zeker al op weg helpen, ik zoek de rest verder wel uit ;)

Bedankt alvast!
 
PHP hulp

PHP hulp

24/12/2024 13:31:49
 
Jens V

Jens V

16/12/2010 15:21:09
Quote Anchor link
Is het zoiets wat je bedoeld?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
function buildMenu($parentid = 0)
{

    $sql = "SELECT id, title FROM pages WHERE parent = " . $parentid . " AND active = 1 ORDER BY weight ASC";
    
    //query uitvoeren.
    
    if(/* resultaat niet leeg */)
    {

        echo '<ul>';
        while(/* elk resultaat ophalen en in $row steken*/)
        {

            echo '<li>';
                echo $row['title']; // of je link of dat met die active = last...
                buildMenu($row['id']); // recursie starten
            echo '</li>';
        }

        echo '</ul>';
    }
}

?>


Jens

edit:
Je kan best in je database die parent 0 veranderen in een NULL-value. Dat klopt beter. Dan moet je dat ook veranderen in mijn functie.
Gewijzigd op 16/12/2010 15:22:20 door Jens V
 
- SanThe -

- SanThe -

16/12/2010 15:25:27
Quote Anchor link
Dit moet je buiten de while() zetten:
$totalRows = mysqli_num_rows($result);

En waar komt $page vandaan?
 
Sam Clauw

Sam Clauw

16/12/2010 15:39:27
Quote Anchor link
@Jens:

ik overloop meteen eens de opbouw die je voorstelde. Het is zeker iets in die aard, 'k heb er een goed voorgevoel bij!

@SanThe:

$page heb ik in mijn config file gedeclareerd.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php

$page
= $_SERVER['REQUEST_URI'];

?>


Het is met andere woorden de url van m'n pagina ;)
Je hebt inderdaad gelijk wat die $totalRows betreft. Ik pas dit al meteen aan!
 
Kris Peeters

Kris Peeters

16/12/2010 16:04:48
Quote Anchor link
Lees dit eens

http://dev.mysql.com/tech-resources/articles/hierarchical-data.html

Toegegeven, het is onmiddellijk een hele hoop. Maar het werkt.
Hiermee kan je data in oneindig (nu ja, toch heel veel) diep nesten, in gelijk welke boomstructuur.
 
Sam Clauw

Sam Clauw

16/12/2010 22:13:49
Quote Anchor link
Yes, het lijkt te werken! Ik heb echter nog één probleempje. De functie staat in de pagina zelf momenteel, maar de variabele $page vanuit de config file wordt niet gevonden. Heel erg vreemd, want buiten de functie blijkt dat wel te werken. Nu moet ik opnieuw die $page declareren, iets wat nogal onlogisch vind ik. M'n code:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php

function buildMenu($parentid)
{

    $menu = new mysqli(MYSQL_SERVER,MYSQL_USER,MYSQL_PASS,MYSQL_DB);
    $sql = "SELECT id, title, parent, weight, active FROM pages WHERE parent = " . $parentid . " AND active = 1 ORDER BY weight ASC";
    $page = $_SERVER['REQUEST_URI'];
    if(!$result = $menu->query($sql)){
        trigger_error('Fout in query:' . $menu->error);
    }
else{
        $i = 0;
        $totalRows = mysqli_num_rows($result);
        if($totalRows != 0)
        {

            echo '<ul id="menu">';
            while($row = $result->fetch_assoc())
            {

                $i++;
                
                // Spaties in de URL vervangen door koppeltekens
                $title = str_replace(' ', '-', $row['title']);
                // URL omzetten naar kleine letters
                $title = strtolower($title);
                
                // Laatste pagina?
                $last = '';
                if($i == $totalRows){
                    $last = 'last';
                }

                
                // Pagina actief?
                if (strpos($page, $title)){
                    echo '';
                    echo '<li class="active ' . $last . '"><a href="/' . $title . '" title="' . $row['title'] . '">' . $row['title'] . '</a>';
                    buildMenu($row['id']);
                    echo '</li>' . "\n";
                }
else{
                    echo '<li class="' . $last . '"><a href="/' . $title . '" title="' . $row['title'] . '">' . $row['title'] . '</a>';
                    buildMenu($row['id']);
                    echo '</li>' . "\n";
                }
            }

            echo '</ul>';
        }
    }

    
    $menu->close();
}


buildMenu(0);

?>


Hoe kan ik ervoor zorgen dat die variabele page wel gevonden wordt?

@Kris: de pagina achter je link ziet er crazy stuff uit! Lectuur voor tussendoor of eerder van cruciaal belang om verder te werken met php?
Gewijzigd op 16/12/2010 22:16:02 door Sam Clauw
 

17/12/2010 00:13:08
Quote Anchor link
Die MySQL pagina is inderdaad wat geblaat van hoger niveau (maar niet van het hoogste niveau). Toch is het best wel interessant om dat door te lezen.
Als je het een beetje doorgelezen hebt, dan zul je zien dat ze de hele structuur op bepaalde manieren in één query kunnen ophalen.
Met de oplossing die je van Jens hebt gekregen zal er (aan de hand van je voorbeeld data) minimaal 11 queries worden gedraaid. Vind je dat ook niet wat zonde? En lijkt het je ook niet logisch dat dat wel beter kan?
Inderdaad kan dat. Zie bijvoorbeeld deze oplossing.
 
Sam Clauw

Sam Clauw

17/12/2010 12:14:18
Quote Anchor link
Die uitleg ziet er inderdaad wel degelijk en makkelijker uit. Ik ga meteen aan de slag op het ook te integreren, bedankt Karl!

Toevoeging op 17/12/2010 14:02:20:

Die manier van werken is inderdaad pakken beter. Nog één bijkomend vraagje: hoe zou ik het best een id aan de eerste <ul> geven? Ik dacht om dit opnieuw met een teller "i" te doen, maar aangezien het een recursieve functie is zal dit nogal moeilijk gaan vrees ik? Hier mijn werkende code tot nu toe:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php

$sitemap
= new mysqli(MYSQL_SERVER,MYSQL_USER,MYSQL_PASS,MYSQL_DB);

// get all menuitems with 1 query
$sql = "SELECT id, title, parent, weight, active FROM pages ORDER BY weight ASC";

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


if(!$result = $sitemap->query($sql)){
    trigger_error('Fout in query:' . $sitemap->error);
}
else{
    while($menuItem = $result->fetch_assoc()){
        $menuData['items'][$menuItem['id']] = $menuItem;
        $menuData['parents'][$menuItem['parent']][] = $menuItem['id'];
    }
}


// menu builder function, parentId 0 is the root
function sitemap($parentId, $menuData){
    $i = 0;
    $sitemap = '';
    if (isset($menuData['parents'][$parentId])){
        $sitemap = '<ul>';
        foreach ($menuData['parents'][$parentId] as $itemId){
            $sitemap .= '<li>' . $menuData['items'][$itemId]['title'];

            // find childitems recursively
            $sitemap .= sitemap($itemId, $menuData);
            $sitemap .= '</li>';
        }

        $sitemap .= '</ul>';
    }

    return $sitemap;
}


// output the menu
echo sitemap(0, $menuData);

?>


PS: dubbelpost inderdaad, maar m'n vorige post was eerder een bedanking voor de moeite die men voor mij al gedaan heeft ;)

Toevoeging op 17/12/2010 14:05:16:

Een schitterende oplossing voor m'n oorspronkelijke probleem, het werkt erg goed! Ik heb echter een bijkomend probleem/onduidelijkheidje. Hoe plaats ik op de eerste <ul> een id? Ik ging eerst werken met een teller "i", maar gezien er gebruik gemaakt wordt van recursie wordt de teller steeds op "0" geplaatst.

Hier mijn werkende code tot nu toe:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php

$sitemap
= new mysqli(MYSQL_SERVER,MYSQL_USER,MYSQL_PASS,MYSQL_DB);

// get all menuitems with 1 query
$sql = "SELECT id, title, parent, weight, active FROM pages ORDER BY weight ASC";

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


if(!$result = $sitemap->query($sql)){
    trigger_error('Fout in query:' . $sitemap->error);
}
else{
    while($menuItem = $result->fetch_assoc()){
        $menuData['items'][$menuItem['id']] = $menuItem;
        $menuData['parents'][$menuItem['parent']][] = $menuItem['id'];
    }
}


// menu builder function, parentId 0 is the root
function sitemap($parentId, $menuData){
    $i = 0;
    $sitemap = '';
    if (isset($menuData['parents'][$parentId])){
        $sitemap = '<ul>';
        foreach ($menuData['parents'][$parentId] as $itemId){
            $sitemap .= '<li>' . $menuData['items'][$itemId]['title'];

            // find childitems recursively
            $sitemap .= sitemap($itemId, $menuData);
            $sitemap .= '</li>';
        }

        $sitemap .= '</ul>';
    }

    return $sitemap;
}


// output the menu
echo sitemap(0, $menuData);

?>


PS: dubbelpost inderdaad, maar m'n vorige post was eerder een bedanking naar de mensen die me tot nu toe geholpen hebben ;)
 
Kris Peeters

Kris Peeters

17/12/2010 14:17:51
Quote Anchor link
Sam Clauw op 17/12/2010 12:14:18:
... Ik dacht om dit opnieuw met een teller "i" te doen, maar aangezien het een recursieve functie is zal dit nogal moeilijk gaan vrees ik ...


Je kan een teller globaal bijhouden

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
...
$i = 0;
function
sitemap($parentId, $menuData){
  global $i;
  ...

  $i++;
}

?>
 
Sam Clauw

Sam Clauw

17/12/2010 15:15:36
Quote Anchor link
Inderdaad, dit werkt ook perfect. De problemen blijven echter komen, en dat terwijl ik dacht dat ik er eindelijk was. Ik sukkel nu namelijk met de links die ik aan m'n <a>'s probeer te geven.

In principe is de url "eenvoudigweg" de paginatitel. Voor de url's in het tweede niveau daarentegen bestaat de url uit de titel van de pagina van het eerste niveau + de titel van de pagina uit het tweede niveau. Bijvoorbeeld:

Home: /home
De winkel: /de-winkel
Producten: /producten
Monturen: /producten/monturen
Zonnebrillen: /producten/zonnebrillen
Lenzen: /producten/lenzen
Hoorapparaten: /producten/hoorapparaten
Glazen: /producten/glazen
Optische illusies: /optische-illusies
Contact: /contact
Links: /links

Ik probeer dit te laten werken via die globale variabelen, maar het is me echter nog niet duidelijk wat of hoe (het werken met die teller "i" begrijp ik daarentegen wél). Geen licht aan het einde van de tunnel voor mij, mag ik jullie opnieuw vragen om mij hierbij te helpen? ;)

De code tot nu toe:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php

// menu builder function, parentId 0 is the root
$i = 0;
$url = '';
function
funcSitemap($parentId, $menuData){
    global $i;
    global $url .= $url;
    $sitemap = '';
    if (isset($menuData['parents'][$parentId])){
        if($i == 0){
            $sitemap = '<ul id="sitemap">' . "\n";
        }
else{
            $sitemap = '<ul>' . "\n";
        }
        
        foreach ($menuData['parents'][$parentId] as $itemId){
        
            // Spaties in de URL vervangen door koppeltekens
            $url = str_replace(' ', '-', $menuData['items'][$itemId]['title']);
            // URL omzetten naar kleine letters
            $url = strtolower($url);
            
            $sitemap .= '<li><a href="' . $url . '" title="' . $menuData['items'][$itemId]['title'] . '">' . $menuData['items'][$itemId]['title'] . '</a>';

            // find childitems recursively
            $i++;
            $sitemap .= funcSitemap($itemId, $menuData);
            $sitemap .= '</li>' . "\n";
        }

        $sitemap .= '</ul>' . "\n";
    }

    return $sitemap;
}


// output the menu
echo funcSitemap(0, $menuData);

?>


En ja, ik ben jullie al heel wat verschuldigd :)
 
Sam Clauw

Sam Clauw

20/12/2010 20:18:26
Quote Anchor link
Kan er mij iemand toch nog eventjes helpen? Ik zit nu al dagen te sukkelen met de opbouw van die URL's in m'n recursieve functie, maar het lukt me echt aan geen kanten. Ik zoek in principe een manier waarbij ik een URL kan gebruiken die uit een vorige functie komt tijdens de recursie. M'n (slechte) testing code zodat jullie misschien een beter zicht hebben waar ik de mist in ga:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
$i
= 0;
$url = '';
function
funcSitemap($parentId, $menuData){
    global $i;
    $sitemap = '';
    global $url;
    if (isset($menuData['parents'][$parentId])){ // Bestaat de parent "0"? Ja!
        
        if($i == 0){
            $sitemap = '<ul id="sitemap">' . "\n";
        }
else{
            $sitemap = '<ul>' . "\n";
        }

        
        global $teller; // neem voorgaande teller uit functie of buiten functie
        
        foreach ($menuData['parents'][$parentId] as $itemId){ // Doe een loop voor de elementen die parent "0 hebben" en sla de waarde van de 0 de rij op in $itemId (waarde is nu "1")
            $test = count($menuData['parents'][$parentId]);
            echo 'AANTAL: ' . $test;
            // Spaties in de URL vervangen door koppeltekens
            $url = str_replace(' ', '-', $menuData['items'][$itemId]['title']);
            // URL omzetten naar kleine letters
            $url = strtolower($url);
            
            $sitemap .= '<li><a href="' . $url . '" title="' . $menuData['items'][$itemId]['title'] . '">' . $menuData['items'][$itemId]['title'] . '</a>';

            // find childitems recursively
            $i++;
            $sitemap .= funcSitemap($itemId, $menuData); // funcSitemap(1, $menuData);
            $sitemap .= '</li>' . "\n";
            
            $teller += 1;
            
            if($teller == $test){
                $url .= $url;
            }
else{
                $url = 'd-';
            }

            //als teller gelijk is aan laatste in foreach, dan de url resetten!!!
        }
        $sitemap .= '</ul>' . "\n";
    }
else{
        $url = 'e-';
    }

    return $sitemap;
}


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


Wie kan mij redding brengen? :)
 
- SanThe -

- SanThe -

20/12/2010 20:31:06
Quote Anchor link
Kun je de inhoud van $menuData geven?
 
Sam Clauw

Sam Clauw

20/12/2010 20:34:58
Quote Anchor link
De array ziet er als volgt uit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<?php

Array
(
    [
items] => Array
        (
            [
1] => Array
                (
                    [
id] => 1
                    [title] => Home
                    [parent] => 0
                    [weight] => 1
                    [active] => 1
                )

            [
7] => Array
                (
                    [
id] => 7
                    [title] => Monturen
                    [parent] => 3
                    [weight] => 1
                    [active] => 0
                )

            [
2] => Array
                (
                    [
id] => 2
                    [title] => De winkel
                    [parent] => 0
                    [weight] => 2
                    [active] => 1
                )

            [
8] => Array
                (
                    [
id] => 8
                    [title] => Zonnebrillen
                    [parent] => 3
                    [weight] => 2
                    [active] => 0
                )

            [
3] => Array
                (
                    [
id] => 3
                    [title] => Producten
                    [parent] => 0
                    [weight] => 3
                    [active] => 1
                )

            [
9] => Array
                (
                    [
id] => 9
                    [title] => Lenzen
                    [parent] => 3
                    [weight] => 3
                    [active] => 0
                )

            [
4] => Array
                (
                    [
id] => 4
                    [title] => Optische illusies
                    [parent] => 0
                    [weight] => 4
                    [active] => 1
                )

            [
10] => Array
                (
                    [
id] => 10
                    [title] => Hoorapparaten
                    [parent] => 3
                    [weight] => 4
                    [active] => 0
                )

            [
11] => Array
                (
                    [
id] => 11
                    [title] => Glazen
                    [parent] => 3
                    [weight] => 5
                    [active] => 0
                )

            [
5] => Array
                (
                    [
id] => 5
                    [title] => Contact
                    [parent] => 0
                    [weight] => 5
                    [active] => 1
                )

            [
6] => Array
                (
                    [
id] => 6
                    [title] => Links
                    [parent] => 0
                    [weight] => 6
                    [active] => 1
                )

        )

    [
parents] => Array
        (
            [
0] => Array
                (
                    [
0] => 1
                    [1] => 2
                    [2] => 3
                    [3] => 4
                    [4] => 5
                    [5] => 6
                )

            [
3] => Array
                (
                    [
0] => 7
                    [1] => 8
                    [2] => 9
                    [3] => 10
                    [4] => 11
                )

        )

)


?>


Hopelijk kun je daar iets mee?
Gewijzigd op 20/12/2010 20:35:24 door Sam Clauw
 
- SanThe -

- SanThe -

20/12/2010 22:57:57
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
function url($menuData, $Id)
{

    if($menuData['items'][$Id]['parent'] == 0)
    {

        return strtolower(str_replace(' ', '-', $menuData['items'][$Id]['title']));
    }

    else
    {
        return strtolower(str_replace(' ', '-', url($menuData, $menuData['items'][$Id]['parent']) . '/' . $menuData['items'][$Id]['title']));
    }
}

function
funcSitemap($menuData, $parentId = 0)
{

    if (isset($menuData['parents'][$parentId]))
    {

        if($parentId == 0)
        {

            $sitemap = '<ul id="sitemap">' . "\n";
        }

        else
        {
            $sitemap = '<ul>' . "\n";
        }

        foreach ($menuData['parents'][$parentId] as $itemId)
        {

            $sitemap .= '<li><a href="' . url($menuData, $itemId) . '" title="' . $menuData['items'][$itemId]['title'] . '">' . $menuData['items'][$itemId]['title'] . '</a></li>' . "\n";
            if(isset($menuData['parents'][$itemId]))
            {

                $sitemap .= funcSitemap($menuData, $itemId);
            }
        }

        $sitemap .= '</ul>' . "\n";
        return $sitemap;
    }

    return '';
}


echo funcSitemap($menuData);
?>
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.