Ik heb een main menu bestaande uit 8 records. Van deze 8 records hebben er 3 ook sub items (submenu) Er is mij vaak verteld om volgens een structuur te werken waar zowel de main items als de sub items in dezelfde database tabel staan gebruikmakend van parent_id. Iets zoals dit:

CREATE TABLE `menus` (
  `id` int(11) NOT NULL,
  `menu_name` varchar(32) NOT NULL,
  `parent_id` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `menus` (`id`, `menu_name`, `parent_id`) VALUES
(1, 'Home', 0),
(2, 'About us', 0),
(3, 'Services', 0),
(4, 'Contact', 0),
(5, 'Online Service', 3),
(6, 'Home Service', 3);

Op zich klinkt het heel logisch maar ik heb geen idee hoe ik hier mee om moet gaan in mijn Model (query), View (Template) en Controller. Ik werk namelijk via het MVC principe. Kan iemand mij een stap op weg helpen.

Bij voorbaat dank
Met twee slimmigheidjes los je dat in PHP op.
1) stop de menu items die bij elkaar horen in een array (doe print_r($menu) om te zien wat ik bedoel)
2) maak een recursive functie die zichzelf herhaaldelijke keren aanroept en zo het menu maakt

<?php

/*
* example data
*/
$data = array(
array(
'id' => 1,
'name' => 'homepage',
'parent' => 0
),
array(
'id' => 2,
'name' => 'About',
'parent' => 0
),
array(
'id' => 3,
'name' => 'Services',
'parent' => 0
),
array(
'id' => 4,
'name' => 'Contact',
'parent' => 0
),
array(
'id' => 5,
'name' => 'Online Service',
'parent' => 3
),
array(
'id' => 6,
'name' => 'Home Service',
'parent' => 3
),
array(
'id' => 7,
'name' => 'test',
'parent' => 6
),
);


$menu = array();

/*
* use array keys to sort the menu items
*/
foreach($data as $item)
{
$menu[$item['parent']][] = $item;
}

// print_r($menu);

echo buildMenu($menu);

/*
* Recursive function that creates submenus in other submenus
*/
function buildMenu($menu, $key = 0)
{
$html = '<ul>' . "\n";

foreach($menu[$key] as $item)
{
$html .= '<li>' . $item['name'];

if(isset($menu[$item['id']])) {
$html .= buildMenu($menu, $item['id']);
}

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

return $html;
}

?>
Hoi Frank. :)

Hartelijk bedankt voor de reactie. Dat ziet er logisch uit. Maar hoe query ik de database?
vervang regel 1 t/m 54 voor:
<?php
$menu = array();
$query = 'SELECT * FROM menu';
$result = mysqli_query($conn, $query);
while($item = mysqli_fetch_assoc($result)) {
$menu[$item['parent']][] = $item;
}

Hi Frank. Wederom bedankt!

Het probleem is dat, zoals ik al aangaf via MVC methode werk. Dus ik heb dit in mijn Model

public function get_menu() 
{
	$sql = "SELECT *
		      FROM menu";
				  
	$stmt = $this->pdo->query($sql);		
	return $stmt->fetchAll();
}


Dit pik ik op in de Controller:

$menu_items = $this->page->get_menu();


en verstuur dit naar de Vieuw:

$this->render('header', compact('menu_items'));


Met andere woorden, waar jij de opmaak in je functie(s) hebt doe ik dat normaal gesproken in de View:

<?php foreach($menu_items as $menu_item): ?>
   ......
<?php endforeach; ?>


En op dit punt weet ik niet hoe ik jou methode hierin zou moeten verwerken.
Donald,

De MVC methode is enkel bedoeld om verantwoordelijkheden onder te verdelen waardoor je programma beter gestructureerd wordt.

Het renderen van de menu items zou ik niet in de view doen (als uitzondering op de rest) vanwege de complexe geneste structuur. In plaats daarvan zou je je eigen class moeten bouwen die meer opties biedt dan mijn voorbeeldje. Minimaal zou je in je data ook een css-class mee moeten kunnen geven en natuurlijk ook de link.
Maar je kunt ook nog denken aan een icon, een "active" menu-item en aan disabled menu items :-)

In je controller zou je dan iets kunnen doen als
<?php

$menu = new MyCustomMenu(); // je eigen class
$menu->initialize($this->page->get_menu());

$this->render('header', array(
'menu' => $menu
));
?>

en in de view zou je dan kunnen doen:

<?php
echo $menu->render();
?>

[size=xsmall]Toevoeging op 23/06/2017 23:22:37:[/size]

Voorzetje voor MyCustomMenu:
<?php

class MyCustomMenu
{
protected $menu;

public function initialize($menu_items)
{
foreach($menu_items as $item)
{
$this->menu[$item['parent']][] = $item;
}

return $this;
}

public function render()
{
return $this->buildMenu($this->menu);
}

/*
* Recursive function that creates submenus in other submenus
*/
protected function buildMenu($menu, $key = 0)
{
$html = '<ul>' . "\n";

foreach($menu[$key] as $item)
{
$html .= '<li>' . $item['name'];

if(isset($menu[$item['id']])) {
$html .= $this->buildMenu($menu, $item['id']);
}

$html .= '</li>' . "\n";
}

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

return $html;
}
}
Hoi Frank, wederom hartelijk bedankt voor de input. Ik ga hiermee aan de slag
Hoi Frank.

Sorry voor een beetje late reactie. Afgelopen week in de lappemand gelegen (snip en snip verkouden). Even terugkomend op deze kwestie. Er zijn een aantal dingen die mij verwarren. Allereerst je hebt het over een complexe geneste structuur, maar zo complex is het eigenlijk toch niet. Er zijn twee levels. 1 met parent_id = NULL en 1 met parent_id = 2 dan wel 3. Ik heb jou methode proberen na te maken in de voor mij bekende werkwijze:

public function get_menu_items($lang)
{
	$sql = "SELECT *
		      FROM menu 
			 WHERE language_abbr = ?";
				 
    $items = $this->pdo->prepare($sql);
    $items->execute(array($lang));
		
    $menu_items = array();
	foreach ($items as $item) {
		if (!isset($menu_items[$item['parent_id']])) {
			$menu_items[$item['parent_id']] = array();	
		}
		$menu_items[$item['parent_id']][] = $item;
				
	}
	return $menu_items;		
}


en dit in de View:

<ul>
<?php $parent_id = NULL; foreach ($menu_items[$parent_id] as $item):?>
<li><a href="#"><?= $item['navigation_name']; ?></a></li>     
<?php endforeach; ?>
</ul>

Dit geeft me in principe al de eerste laag (parent_id = NULL). Er is een andere reden waarom ik het een en ander wel graag in de View doe en wel om de reden dat de site Bootstrap based is dus ik ook nog wel wat classes etc kwijt moet (dropdown etc).

Ben alleen niet zeker hoe ik de tweede laag (sub menus) moet genereren

Reageren