Een menu opslaan in de database

Soms kan het nodig zijn dat je een menu moet maken welke opgeslagen dient te worden in de database. Vaak wordt er dan voor elk niveau een aparte database query gedaan wordt. Wanneer de website groter wordt kan dit uiteindelijk te zwaar worden voor de database. Dit kan ook in één query gedaan worden, wat een stuk minder vergt van de database. Dit wordt bereikt door het gebruik van een array, in combinatie met een functie die voor elk niveau herhaald wordt. Uiteindelijk is het doel om een soort gelijk menu te maken:

  • jQuery Tutorials
    • jQuery Tutorial 1
    • jQuery Tutorial 2
    • jQuery Tutorial 3
  • PHP Tutorials
    • PHP Tutorial 1
    • PHP Tutorial 2
    • PHP Tutorial 3
    • PHP Tutorial 4

Tabel aanmaken

De eerste stap is ervoor zorgen dat het menu kan worden opgeslagen in de database. Daarvoor maak ik de volgende tabel aan:

  1. CREATE TABLE IF NOT EXISTS `menu` (
  2.   `menuId` int(11) NOT NULL auto_increment,
  3.   `parentId` int(11) NOT NULL,
  4.   `menuName` varchar(255) NOT NULL,
  5.   `menuDescription` text NOT NULL,
  6.   `sort_order` int(5) NOT NULL,
  7.   PRIMARY KEY  (`menuId`)
  8. )

Dit is een vrij standaard tabel, enkel zit hier een extra veld aan toegevoegd: parentId. Hier komt straks het ID in de staan van het onderdeel wat een level hoger ligt. Bij PHP Tutorial 1 komt hier het ID in te staan van PHP Tutorials. Het formulier voor het invoeren van nieuwe menu items zal er dan ongeveer zo uitzien:

Naam:

Beschrijving:

Bovenliggend item:

  1. Naam:<br /><input type="text" name="menuName" /><br />
  2. Beschrijving:<br /><input type="text" name="menuDescription" /><br />
  3. Bovenliggend item:<br />
  4. <select name="parentId">
  5. <option value="1">jQuery Tutorials</option>
  6. <option value="2">- jQuery Tutorial 1</option>
  7. <option value="3">- jQuery Tutorial 2</option>
  8. <option value="4">- jQuery Tutorial 3</option>
  9. <option value="5">PHP Tutorials</option>
  10. <option value="6">- PHP Tutorial 1</option>
  11. <option value="7">- PHP Tutorial 2</option>
  12. <option value="8">- PHP Tutorial 3</option>
  13. <option value="9">- PHP Tutorial 4</option>
  14. </select><br />
  15. <input type="submit" value="Menu item toevoegen" />

De query om dit in de database te plaatsen ziet er dan zo uit:

  1. $sql = sprintf("insert into menu (parentId, menuName, menuDescription) values ('%s', '%s', '%s')",
  2.         mysql_real_escape_string($_POST['parentId']),
  3.         mysql_real_escape_string($_POST['menuName']),
  4.         mysql_real_escape_string($_POST['menuDescription'])
  5. );
  6. $query = mysql_query($sql) or die (mysql_error());

Tabel uitlezen

Nu er data in de tabel staat kan deze uitgelezen worden. De eerste stap is om deze data in een array te zetten:

  1. $result = mysql_query("SELECT menuId, parentId, menuName FROM menu ORDER BY sort_order, menuName") or die (mysql_error());
  2. $menuData = array(
  3.         'items' => array(),
  4.         'parents' => array()
  5. );
  6.  
  7. while ($menuItem = mysql_fetch_assoc($result)) {
  8.         $menuData['items'][$menuItem['menuId']] = $menuItem;
  9.         $menuData['parents'][$menuItem['parentId']][] = $menuItem['menuId'];
  10. }

Er worden 2 key's aan de array toegevoegd: 1 met daarin alle hoofdcategorieën en daaronder alle sub-categorieën, en 1 voor de database gegevens van het item. Nu deze informatie in een array staat kan deze uitgelezen worden. Dat doen we met een functie die voor elk niveau zichzelf aanroept:

  1. function buildMenu($parentId, $menuData) {
  2.         $html = '';
  3.         if (isset($menuData['parents'][$parentId])) {
  4.                 $html = '<ul>';
  5.                
  6.                 foreach ($menuData['parents'][$parentId] as $itemId) {
  7.                         $html .= '<li><a href="link_naar_pagina.php?menuId=' . $itemId . '">' . stripslashes($menuData['items'][$itemId]['menuName']) . '</a>';
  8.                         $html .= buildMenu($itemId, $menuData);
  9.                         $html .= '</li>';
  10.                 }
  11.                
  12.                 $html .= '</ul>';
  13.         }
  14.         return $html;
  15. }

Nu alle code compleet is, is het enkel nog een kwestie van het aanroepen van de functie om het menu aan te maken:

  1. echo buildMenu(0, $menuData);

De code ziet er dan uiteindelijk zo uit:

  1. function buildMenu($parentId, $menuData) {
  2.         $html = '';
  3.         if (isset($menuData['parents'][$parentId])) {
  4.                 $html = '<ul>';
  5.                
  6.                 foreach ($menuData['parents'][$parentId] as $itemId) {
  7.                         $html .= '<li><a href="link_naar_pagina.php?menuId=' . $itemId . '">' . stripslashes($menuData['items'][$itemId]['menuName']) . '</a>';
  8.                         $html .= buildMenu($itemId, $menuData);
  9.                         $html .= '</li>';
  10.                 }
  11.                
  12.                 $html .= '</ul>';
  13.         }
  14.         return $html;
  15. }
  16.  
  17. $result = mysql_query("SELECT menuId, parentId, menuName FROM menu ORDER BY sort_order, menuName") or die (mysql_error());
  18. $menuData = array(
  19.         'items' => array(),
  20.         'parents' => array()
  21. );
  22.  
  23. while ($menuItem = mysql_fetch_assoc($result)) {
  24.         $menuData['items'][$menuItem['menuId']] = $menuItem;
  25.         $menuData['parents'][$menuItem['parentId']][] = $menuItem['menuId'];
  26. }
  27.  
  28. echo buildMenu(0, $menuData);

Voorbeeld

Een werkend voorbeeld hiervan kun je hier vinden:

Bron:
Formatting a multi-level menu using only one query

BijlageGrootte
menu-in-database.zip1.35 KB