Tutorials
Geneste Items
Geneste items in een database opslaan en er weer uithalen is iets wat vaak best lastig lijkt, maar wat eigenlijk best meevalt. In deze tutorial zal ik uitleggen hoe je dit handig kunt aanpakken.
Pagina 1
Inleiding
Veel beginnende programmeurs vinden het lastig hoe je geneste items goed in een database kunt opslaan en er weer uit kunt halen. Zelf ben ik hier vroeger ook al vaker tegenaan gelopen, en met deze tutorial hoop ik andere beginnende programmeurs een duwtje in de juiste richting te kunnen geven.
Ik zal eerst laten zien wat geneste items eigenlijk zijn en hoe je ze handig kunt gebruiken. Daarna zal ik laten zien hoe je ze het beste kunt opslaan in een database en tot slot zal ik vertellen hoe je ze daar weer het beste uit kunt halen.
Helemaal aan het einde zal ik ook nog wat vertellen over geneste items opslaan in XML. Dit heeft voor- en nadelen, en over hoe je dit precies moet aanpakken zal ik in deze tutorial niet verder ingaan.
[color=red]LET OP!!
Ik kom er net achter dat de in deze tutorial gebruikte code erg lijkt op de [color=red]code die al eerder door Tommy is geplaatst[/color]. Ik heb deze code (helaas) niet van tevoren gezien, maar wil wel even een linkje ernaar plaatsen.[/color]
Benodigde voorkennis:
- PHP en MySQL
- Multidimensionale Arrays
- Recursieve functies
Ik zal eerst laten zien wat geneste items eigenlijk zijn en hoe je ze handig kunt gebruiken. Daarna zal ik laten zien hoe je ze het beste kunt opslaan in een database en tot slot zal ik vertellen hoe je ze daar weer het beste uit kunt halen.
Helemaal aan het einde zal ik ook nog wat vertellen over geneste items opslaan in XML. Dit heeft voor- en nadelen, en over hoe je dit precies moet aanpakken zal ik in deze tutorial niet verder ingaan.
[color=red]LET OP!!
Ik kom er net achter dat de in deze tutorial gebruikte code erg lijkt op de [color=red]code die al eerder door Tommy is geplaatst[/color]. Ik heb deze code (helaas) niet van tevoren gezien, maar wil wel even een linkje ernaar plaatsen.[/color]
Benodigde voorkennis:
- PHP en MySQL
- Multidimensionale Arrays
- Recursieve functies
Pagina 2
Wat zijn geneste items?
Geneste items kan je eigenlijk overal tegenkomen. Alles wat een boomstructuur heeft, bestaat uit geneste items. Zo kan bijvoorbeeld een filesysteem of een inhoudsopgave bestaan uit geneste items.
Een voorbeeld
Een voorbeeld van geneste items is het menu dat bovenaan deze website staat.
Geneste items kunnen zo diep zijn als je zelf wilt, dus je kunt zoveel lijsten in een andere lijst plaatsen als wat je nodig hebt.
Enkele begrippen
Item - Dit begrip heb ik al een aantal keer gebruikt. In het bovenstaande voorbeeld is elke pagina een item.
Ouder - Een ouder van een item is het item dat 'erboven' staat, en dan bedoel ik niet de regel erboven. De ouder van het item B. Teksten is iv. Welke codes kan ik gebruiken?. De vier bovenste items (Informatie, PHP stuff, Forum en Contact hebben geen ouder.
Kind - De betekenis hiervan zal je nu wel kunnen raden. Een kind van een item is elk item dat 'eronder' staat.
Grootouders en kleinkinderen - De grootouder van een item is het item dat er twee levels boven staat. Evenzo is een kleinkind een item dat er twee levels onder staat.
Een voorbeeld
Een voorbeeld van geneste items is het menu dat bovenaan deze website staat.
1. Informatie
a. Nieuws
b. FAQ
- Wat is PHPhulp?
- Auteursrechten
- Hoe voeg ik iets toe?
- Welke codes kan ik gebruiken?
A. Ignore
B. Teksten
c. Over PHPhulp
2. PHP stuff
a. PHP tutorials
b. PHP scripts
c. PHP boeken
3. Forum
4. ContactGeneste items kunnen zo diep zijn als je zelf wilt, dus je kunt zoveel lijsten in een andere lijst plaatsen als wat je nodig hebt.
Enkele begrippen
Item - Dit begrip heb ik al een aantal keer gebruikt. In het bovenstaande voorbeeld is elke pagina een item.
Ouder - Een ouder van een item is het item dat 'erboven' staat, en dan bedoel ik niet de regel erboven. De ouder van het item B. Teksten is iv. Welke codes kan ik gebruiken?. De vier bovenste items (Informatie, PHP stuff, Forum en Contact hebben geen ouder.
Kind - De betekenis hiervan zal je nu wel kunnen raden. Een kind van een item is elk item dat 'eronder' staat.
Grootouders en kleinkinderen - De grootouder van een item is het item dat er twee levels boven staat. Evenzo is een kleinkind een item dat er twee levels onder staat.
Pagina 3
Geneste items opslaan
Zoals je in het vorige hoofdstuk al hebt kunnen zien, is een veel gebruikte toepassing van geneste items een menu opbouw met subpagina's. Als je een CMS hebt, wil je deze pagina’s natuurlijk in een database opslaan, zodat de website dynamisch blijft.
De database tabel maken
De database maken is een kwestie van maar één tabel.
Dit is een sterk vereenvoudigde tabel om de pagina’s in op te slaan. Natuurlijk moeten hier in de praktijk ook nog kolommen aan worden toegevoegd met de inhoud van de pagina, maar voor dit voorbeeld zijn die niet nodig.
De auto_increment waarde wordt op 1 gesteld, zodat we er zeker van zijn dat id 0 (nul) niet bestaat. Die waarde reserveren we namelijk als ouder_id voor de root-items.
Pagina's toevoegen
Het toevoegen van pagina’s is erg gemakkelijk. Eén simpele INSERT-query is genoeg.
Als je geen pagina_id invult, krijgt dit de standaard waarde ‘0’ (nul). Een item met deze standaardwaarde komt dus bovenaan de boomstructuur te staan.
Om subpagina’s van deze pagina te maken, vul je ook het ouder_id in.
Een voorbeeld
Ik zal voor de duidelijkheid de query geven om de paginastructuur van het vorige hoofdstuk op te slaan. Allereerst nog even deze paginastructuur.
Om dit toe te voegen kan de volgende query gebruikt worden.
De database tabel maken
De database maken is een kwestie van maar één tabel.
CREATE TABLE Menu (
pagina_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
ouder_id INT UNSIGNED NOT NULL DEFAULT '0',
titel VARCHAR( 100 ) NOT NULL,
PRIMARY KEY (pagina_id)
) ENGINE=InnoDB AUTO_INCREMENT=1Dit is een sterk vereenvoudigde tabel om de pagina’s in op te slaan. Natuurlijk moeten hier in de praktijk ook nog kolommen aan worden toegevoegd met de inhoud van de pagina, maar voor dit voorbeeld zijn die niet nodig.
De auto_increment waarde wordt op 1 gesteld, zodat we er zeker van zijn dat id 0 (nul) niet bestaat. Die waarde reserveren we namelijk als ouder_id voor de root-items.
Pagina's toevoegen
Het toevoegen van pagina’s is erg gemakkelijk. Eén simpele INSERT-query is genoeg.
INSERT INTO Menu (titel) VALUES ('Pagina 1')Als je geen pagina_id invult, krijgt dit de standaard waarde ‘0’ (nul). Een item met deze standaardwaarde komt dus bovenaan de boomstructuur te staan.
Om subpagina’s van deze pagina te maken, vul je ook het ouder_id in.
INSERT INTO Menu (ouder_id, titel) VALUES (1, 'Subpagina 1')Een voorbeeld
Ik zal voor de duidelijkheid de query geven om de paginastructuur van het vorige hoofdstuk op te slaan. Allereerst nog even deze paginastructuur.
1. Informatie
a. Nieuws
b. FAQ
i. Wat is PHPhulp?
ii. Auteursrechten
iii. Hoe voeg ik iets toe?
iv. Welke codes kan ik gebruiken?
A. Ignore
B. Teksten
c. Over PHPhulp
2. PHP stuff
a. PHP tutorials
b. PHP scripts
c. PHP boeken
3. Forum
4. ContactOm dit toe te voegen kan de volgende query gebruikt worden.
INSERT INTO Menu (pagina_id, ouder_id, titel) VALUES
(1, 0, 'Informatie'),
(2, 1, 'Nieuws'),
(3, 1, 'FAQ'),
(4, 3, 'Wat is PHPhulp?'),
(5, 3, 'Auteursrechten'),
(6, 3, 'Hoe voeg ik iets toe?'),
(7, 3, 'Welke codes kan ik gebruiken?'),
(8, 7, 'Ignore'),
(9, 7, 'Teksten'),
(10, 1, 'Over PHPhulp'),
(11, 0, 'PHP stuff'),
(12, 11, 'PHP tutorials'),
(13, 11, 'PHP scripts'),
(14, 11, 'PHP boeken'),
(15, 0, 'Forum'),
(16, 0, 'Contact')Pagina 4
Geneste items ophalen
Aan gegevens die in je database staan heb je niks als je ze er niet uit kunt halen. Ik zal hier een manier laten zien om dat slim aan te pakken. Er zijn verschillende mogelijkheden, maar deze vind ik zelf het makkelijkst.
Stap 1: De query
De query is eigenlijk net zoals elke andere SELECT-query.
Dit is verder niks bijzonders. Maar hoe kan je hier nou makkelijk een lijst van maken?
Stap 2: De gegevens in een array plaatsen
De tweede stap is om de gegevens in een multidimensionale array te plaatsen.
Dit ziet er al iets ingewikkelder uit. Wat we hier doen is een array maken die er als volgt uit komt te zien:
Zoals je ziet maken we een array met als buitenste key de waarde van ouder_id. De waarde van deze buitenste array is een andere array met daarin alle pagina’s met deze ouder_id.
Stap 3: De items weergeven
Tot slot moeten we deze array nog netjes weergeven aan de gebruiker. Hiervoor maken we gebruik van een recursieve functie.
Als eerste wordt de array met root items naar deze functie verzonden. De geordende lijst wordt gestart en elk item wordt bekeken. Ook wordt er per item bekeken of het kinderen heeft. Als dat het geval is, wordt de array met kinderen naar deze functie verstuurd. Tot slot wordt de geordende lijst weer afgesloten.
Door de array met kinderen weer naar dezelfde functie te sturen, komt er een geordende lijst binnen het lijst-item. Het resultaat staat hieronder.
En dit is precies wat we wilde hebben. Natuurlijk is dit nog geen menu, maar dit is wel de basis. Als je die eenmaal goed beheerst, kan je het uitbreiden en aanpassen aan je eigen behoeften.
Stap 1: De query
De query is eigenlijk net zoals elke andere SELECT-query.
<?php
// Maak eerst zelf verbinding met de database
mysql_connect('localhost', 'gebruiker', ‘wachtwoord’);
mysql_select_db('database');
// Voer de query uit
$query = 'SELECT pagina_id, ouder_id, titel FROM Menu';
$resultaat = mysql_query($query) or die('De query kon niet uitgevoerd worden.');
?>Dit is verder niks bijzonders. Maar hoe kan je hier nou makkelijk een lijst van maken?
Stap 2: De gegevens in een array plaatsen
De tweede stap is om de gegevens in een multidimensionale array te plaatsen.
<?php
// Sla de pagina's op in een array
$paginas = array();
while (list($pagina_id, $ouder_id, $titel) = mysql_fetch_array($resultaat)) {
// Voeg toe aan de array
$paginas[$ouder_id][$pagina_id] = $titel;
}
?>Dit ziet er al iets ingewikkelder uit. Wat we hier doen is een array maken die er als volgt uit komt te zien:
Array
(
[0] => Array
(
[1] => Informatie
[11] => PHP stuff
[15] => Forum
[16] => Contact
)
[1] => Array
(
[2] => Nieuws
[3] => FAQ
[10] => Over PHPhulp
)
[3] => Array
(
[4] => Wat is PHPhulp?
[5] => Auteursrechten
[6] => Hoe voeg ik iets toe?
[7] => Welke codes kan ik gebruiken?
)
[7] => Array
(
[8] => Ignore
[9] => Teksten
)
[11] => Array
(
[12] => PHP tutorials
[13] => PHP scripts
[14] => PHP boeken
)
) Zoals je ziet maken we een array met als buitenste key de waarde van ouder_id. De waarde van deze buitenste array is een andere array met daarin alle pagina’s met deze ouder_id.
Stap 3: De items weergeven
Tot slot moeten we deze array nog netjes weergeven aan de gebruiker. Hiervoor maken we gebruik van een recursieve functie.
<?php
function maak_lijst($ouder) {
// We hebben de paginas array nodig
global $paginas;
// Start een geordende lijst
echo '<ol>';
// Maak een lus voor elke onderliggende array
foreach ($ouder as $pagina_id => $titel) {
// Weergeef de pagina
echo '<li>'.$titel;
// Controleer op subtaken
if (isset($paginas[$pagina_id])) {
// Roep deze functie weer aan
maak_lijst($paginas[$pagina_id]);
}
// Sluit het lijst item
echo '</li>';
}
// Sluit de geordende lijst
echo '</ol>';
}
// Verzend de root-items naar de functie
maak_lijst($paginas[0]);
?>Als eerste wordt de array met root items naar deze functie verzonden. De geordende lijst wordt gestart en elk item wordt bekeken. Ook wordt er per item bekeken of het kinderen heeft. Als dat het geval is, wordt de array met kinderen naar deze functie verstuurd. Tot slot wordt de geordende lijst weer afgesloten.
Door de array met kinderen weer naar dezelfde functie te sturen, komt er een geordende lijst binnen het lijst-item. Het resultaat staat hieronder.
<ol>
<li>Informatie
<ol>
<li>Nieuws</li>
<li>FAQ
<ol>
<li>Wat is PHPhulp?</li>
<li>Auteursrechten</li>
<li>Hoe voeg ik iets toe?</li>
<li>Welke codes kan ik gebruiken?
<ol>
<li>Ignore</li>
<li>Teksten</li>
</ol></li>
</ol></li>
<li>Over PHPhulp</li>
</ol></li>
<li>PHP stuff
<ol>
<li>PHP tutorials</li>
<li>PHP scripts</li>
<li>PHP boeken</li>
</ol></li>
<li>Forum</li>
<li>Contact</li>
</ol>En dit is precies wat we wilde hebben. Natuurlijk is dit nog geen menu, maar dit is wel de basis. Als je die eenmaal goed beheerst, kan je het uitbreiden en aanpassen aan je eigen behoeften.
Pagina 5
Opslaan in XML
Een andere manier om geneste items op te slaan is XML. Dit is eigenlijk precies waar XML voor bedoeld is. Het XML-document zou er dan zo uit kunnen zien:
Het grote voordeel hiervan is dat je in het XML-bestand ook meteen de structuur ziet. In de database zie je die niet. Nadeel is wel weer dat het voor de meeste PHP’ers moeilijker is, omdat een database over het algemeen vaker wordt gebruikt dan een XML-bestand.
Opslaan en uitlezen
Het opslaan en uitlezen van een XML-bestand ga ik hier niet behandelen. Misschien dat ik over een tijdje wel een tutorial schrijf over hoe je dit met XML kunt aanpakken, maar voor nu vind ik dat ik al genoeg geschreven heb.
Als je meer wilt weten over PHP en XML, moet je maar even googelen, er zijn genoeg goede tutorials over te vinden. Ik heb het hier genoemd, zodat jullie zien dat de manier die ik in deze tutorial heb gebruikt niet de enige manier is om zo'n probleem aan te pakken.
<?xml version=”1.0” encoding=”UTF-8”?>
<menu>
<pagina naam=”Informatie”>
<pagina naam=”Nieuws”/>
<pagina naam=”FAQ”>
<pagina naam=”Wat is PHPhulp?”/>
<pagina naam=”Auteursrechten”/>
<pagina naam=”Hoe voeg ik iets toe?”/>
<pagina naam=”Welke codes kan ik gebruiken?”>
<pagina naam=”Ignore”/>
<pagina naam=”Teksten>
</pagina>
</pagina>
<pagina naam=”Over PHPhulp”/>
</pagina>
<pagina naam=”PHP stuff”>
<pagina naam=”PHP tutorials”/>
<pagina naam=”PHP scripts”/>
<pagina naam=”PHP boeken”/>
</pagina>
<pagina naam=”Forum”/>
<pagina naam=”Contact”/>
</menu>Het grote voordeel hiervan is dat je in het XML-bestand ook meteen de structuur ziet. In de database zie je die niet. Nadeel is wel weer dat het voor de meeste PHP’ers moeilijker is, omdat een database over het algemeen vaker wordt gebruikt dan een XML-bestand.
Opslaan en uitlezen
Het opslaan en uitlezen van een XML-bestand ga ik hier niet behandelen. Misschien dat ik over een tijdje wel een tutorial schrijf over hoe je dit met XML kunt aanpakken, maar voor nu vind ik dat ik al genoeg geschreven heb.
Als je meer wilt weten over PHP en XML, moet je maar even googelen, er zijn genoeg goede tutorials over te vinden. Ik heb het hier genoemd, zodat jullie zien dat de manier die ik in deze tutorial heb gebruikt niet de enige manier is om zo'n probleem aan te pakken.
Pagina 6
Slotwoord en referenties
Dit was de tutorial over geneste items. Het is misschien allemaal wat snel gegaan. De beste manier om het helemaal door te hebben, is om dit over te nemen en te proberen. Gewoon een heleboel proberen. En als het niet helemaal lukt, hebben we hier op deze website een prachtig forum!
Ik wil er voor de duidelijkheid nog even op wijzen dat dit dus niet de enige manier is om een boomstructuur in een database op te slaan! Maar ik vind zelf dat hij niet heel moeilijk te begrijpen is en hij is makkelijk uit te breiden.
Disclaimer
Deze methode wordt ook uitgelegd in het boek Snel op weg: PHP 5 voor gevorderden van Larry Ullman. De recursieve functie is bijna letterlijk overgenomen uit dit boek.
Ik wil er voor de duidelijkheid nog even op wijzen dat dit dus niet de enige manier is om een boomstructuur in een database op te slaan! Maar ik vind zelf dat hij niet heel moeilijk te begrijpen is en hij is makkelijk uit te breiden.
Disclaimer
Deze methode wordt ook uitgelegd in het boek Snel op weg: PHP 5 voor gevorderden van Larry Ullman. De recursieve functie is bijna letterlijk overgenomen uit dit boek.
Reacties
0