Ik ondervind problemen met het maken van een Adjacency list. Voorheen gebruikte ik altijd if statements in de View voor het opmaken van een multi level menu. Maar daar ik via het MVC principe probeer te werken hoort dat natuurlijk niet zo. Dus heb ik gisteren verschillende tutorial gelezen over dit onderwerp. maar ik kom er niet uit Dit is de tafel:

CREATE TABLE IF NOT EXISTS `navigatie` (
  `id` tinyint(4) NOT NULL AUTO_INCREMENT,
  `parent` tinyint(4) NOT NULL DEFAULT '0',
  `url` varchar(64) NOT NULL,
  `label` varchar(64) NOT NULL,
  `sequence` tinyint(4) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


Dit is de inhoud:

INSERT INTO `navigatie` (`id`, `parent`, `url`, `label`, `sequence`) VALUES
(1, 0, '/', 'Home', 1),
(2, 0, 'javascript:void(0)', 'Diensten', 2),
(3, 0, 'avascript:void(0)', 'Tarieven', 3),
(4, 0, '/case_studies', 'Case Strudies', 4),
(5, 0, '/over', 'Over', 5),
(6, 2, '/diensten/online_strategie', 'Online Strategie', 1),
(7, 2, '/diensten/webdesign', 'Web Design', 2),
(8, 2, '/diensten/webdevelopment', 'Web Development', 3),
(9, 2, '/diensten/digital_marketing', 'Digital Marketing', 4);


En in de Model Class heb ik het volgende:

	public function get_menu()
	{
		$sql = $this->pdo->query('SELECT * FROM site_navigation ORDER BY parent, sequence ASC');
		
		$items	= array();
		$rows = $sql->fetchAll(PDO::FETCH_ASSOC);
		foreach ($rows as $r => $row) {
			$parent = (int)$row['parent'];
			if (!isset($items[$parent])) {
				$items[$parent][] = $row;
			}
		}
		foreach ($items[0] as $m => $item) {
			echo '<ul class="navbar-nav ml-auto">';
				echo '<li>'.$item['label'].'</li>';
				$this->get_sub_menu($item['id']);
			echo '</ul>';
		}
		return $items;
	}


En dan loop ik vast. Kan iemand mij verder op weg helpen. Bij voormaat dank
@Thomas. Het klink misschien heel dom maar ik zie de overeenkomst niet. Zou je op basis wat ik in de openings post heb gedeeld een voorbeeld kunnen geven?

Alvast bedankt
De query zal in ieder geval op de tabel "navigatie" moeten plaatsvinden, of hoe je deze ook uiteindelijk noemt, dit is mogelijk niet "site_navigation"?

Verder zou je de bewerkingen kunnen splitsen in:
- het bouwen van de boom
- het printen van de boom

Ik denk dat het onderstaande standalone voorbeeld voor zich spreekt:
<?php
// https://www.phphulp.nl/php/forum/topic/adjacency-model-ik-krijg-het-niet-voor-elkaar/102341
/*
CREATE TABLE IF NOT EXISTS `navigatie` (
  `id` tinyint(4) NOT NULL AUTO_INCREMENT,
  `parent` tinyint(4) NOT NULL DEFAULT '0',
  `url` varchar(64) NOT NULL,
  `label` varchar(64) NOT NULL,
  `sequence` tinyint(4) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

// mind the typo in Tarieven
INSERT INTO `navigatie` (`id`, `parent`, `url`, `label`, `sequence`) VALUES
(1, 0, '/', 'Home', 1),
(2, 0, 'javascript:void(0)', 'Diensten', 2),
(3, 0, 'javascript:void(0)', 'Tarieven', 3),
(4, 0, '/case_studies', 'Case Strudies', 4),
(5, 0, '/over', 'Over', 5),
(6, 2, '/diensten/online_strategie', 'Online Strategie', 1),
(7, 2, '/diensten/webdesign', 'Web Design', 2),
(8, 2, '/diensten/webdevelopment', 'Web Development', 3),
(9, 2, '/diensten/digital_marketing', 'Digital Marketing', 4);
*/
error_reporting(E_ALL);
ini_set('display_startup_errors', true);
ini_set('display_errors', 'stdout');

class Test
{
    protected $db;
    protected $tree;

    public function __construct() {
        $this->db = new mysqli('ip', 'user', 'password', 'db');
        $this->db->set_charset('utf8'); // never forget!
        $this->buildTree(); // init tree
    }

    protected function buildTree() {
        // dummy root element
        $this->tree = array(
            0 => array(
                'label'     => 'root',
                'url'       => '',
                'parent'    => false,
                'children'  => array(),
            ),
        );

        $res = $this->db->query(
            'SELECT id, parent, url, label
            FROM navigatie
            ORDER BY parent, sequence'
        );
        while ($row = $res->fetch_assoc()) {
            // init current element
            $this->tree[$row['id']] = array(
                'label'     => $row['label'],
                'url'       => $row['url'],
                'parent'    => $row['parent'],
                'children'  => array(),
            );
            // hook current element to parent
            $this->tree[$row['parent']]['children'][] = $row['id'];
        }
    } // buildTree

    protected function escape($in) {
        return htmlspecialchars($in, ENT_QUOTES, 'UTF-8');
    } // escape

    public function printTree($id=0) {
        // print current item, except if it is root
        $item = $this->tree[$id]; // shorthand
        if ($id > 0) {
            // always use some form of output escaping!
            ?><li><a href="<?php echo $this->escape($item['url']) ?>"><?php echo $this->escape($item['label']) ?></a><?php
        }
        // does this item have children?
        if (count($item['children']) > 0) {
            ?><ul><?php
                foreach ($item['children'] as $child) {
                    $this->printTree($child);
                }
            ?></ul><?php
        }
        // close current item
        if ($id > 0) {
            ?></li><?php
        }
    } // printTree
} // Test

$test = new Test();
$test->printTree();
?>[end]
@Thomas. Dat ziet er geweldig uit, hartelijk dank hiervoor. Laatste vraagje nog. Zoals ik al aangaf probeer ik via de MVC methode te werken, dus mijn vraag is hoe ik dit (printTree) naar de Controller krijg en dus vervolgens in de View kan gebruiken

[size=xsmall]Toevoeging op 14/08/2018 07:56:46:[/size]



[size=xsmall]Toevoeging op 14/08/2018 08:12:58:[/size]

@Thomas. Dit is mijn Controller:

class Controller
{
    protected $pageId;
	protected $tuinId;
    protected $layout = 'layout';
    protected $page;

    public function __construct()
    {
		$pdo            = Db::getInstance();
		$this->page     = new Model_Page($pdo);
    }

    protected function render($template, $data = array())
    {
        $layoutData = array(
		    'main_items'      => $this->page->get_main_menu(),
		    'sub_items'       => $this->page->get_sub_menu(),
			'content'         => new View($template.'.php', $data)
        );
        $view = new View($this->layout.'.php', array_merge($layoutData, $data));
        echo $view->render();
    }
}


Kan ik dat gedeelte vanaf protected function buildTree() onder de construct__ functie toevoegen? Ik bedoel:

$this->pdo->set_charset('utf8');
$this->buildTree();

toevoegen aan de construct functie en het gedeelte vanaf de buildTree() functie daaronder plaatsen?
Sorry voor mijn onwetendheid maar ik heb werkelijk geen idee.
Ik denk dat je het als volgt moet zien. MVC schrijft je theoretisch voor hoe je dingen organiseert. Het zou waarschijnlijk logisch zijn als je het opbouwen van de (data van de) boom regelt in een Model. Vervolgens zorgt een View voor de weergave hiervan. Maar dan zit je met de Controller.

Een webpagina is opgebouwd uit meerdere onderdelen: een kop, wat menu's, wat sidebars en andere snippets, en dan een brok hoofd content en dan misschien nog wat footers en fluff. Alles is vaak gecentreerd rondom die hoofdcontent en dat (lijkt mij althans) is dan ook waar de Controller rondom gecentreerd zal zijn: welke content wordt op die pagina geserveerd. Mogelijk hebben menu's wel wat interactie met de pagina in de vorm van een gehighlighte link van de huidige pagina, of een uitgeklapt submenu van het onderdeel waar je in zit.

De vraag is echter, hoe past dat in MVC? Hier is volgens mij geen eenduidig antwoord op, althans, ik heb deze nooit echt gevonden. Dit is meer een soort van systeemarchitectuurvraag - hoe regel ik de opbouw van mijn webpagina's, en tegelijkertijd probeer je waarschijnlijk MVC te doorgronden en dit concept toe te passen :).

Mijn (voorzichtige) advies zou zijn: maakt het jezelf niet te moeilijk. Neem voorlopig genoegen een MVC-aanpak voor de hoofdcontent, en organiseer ondertussen alle "randfunctionaliteit" zoals menu's en sidebars zo goed als dat kan en zinnig is in op zijn minst classes en templates.

Daarnaast zijn er misschien ook nog wel andere logische eenheden te onderscheiden (zoals het Maintemplate, het skelet van je webpagina, waarin dit menu en alle andere "randcontent" min of meer verankerd zit)?

Mogelijk kun je dat later nog wel helemaal ombouwen naar een soort van hiërarchische MVC (volgens mij heette dat ook echt zo HMVC) maar blijf je zelf afvragen: ben ik nu niet het paard achter de wagen aan het spannen door mezelf het gereedschap op te leggen waarmee ik de klus zou moeten klaren?

Ik heb ook redelijk wat informatie gezocht over wat MVC nu precies is en hoe dit er in de praktijk uit zou moeten zien. Die zoektocht werd aanzienlijk bemoeilijkt door ... ahem ... hardliners die daar ... uitgesproken meningen over hebben :). Hierbij is het waarschijnlijk belangrijk (zoals ook een van de comments zei, geloof ik) dat MVC een idee (jaja, design pattern) is, met vele uitwerkingsvormen / verschijningen.
Thomas van den Heuvel op 14/08/2018 14:30:16

Ik denk dat je het als volgt moet zien. MVC schrijft je theoretisch voor hoe je dingen organiseert. Het zou waarschijnlijk logisch zijn als je het opbouwen van de (data van de) boom regelt in een Model. Vervolgens zorgt een View voor de weergave hiervan. Maar dan zit je met de Controller.

Een webpagina is opgebouwd uit meerdere onderdelen: een kop, wat menu's, wat sidebars en andere snippets, en dan een brok hoofd content en dan misschien nog wat footers en fluff. Alles is vaak gecentreerd rondom die hoofdcontent en dat (lijkt mij althans) is dan ook waar de Controller rondom gecentreerd zal zijn: welke content wordt op die pagina geserveerd. Mogelijk hebben menu's wel wat interactie met de pagina in de vorm van een gehighlighte link van de huidige pagina, of een uitgeklapt submenu van het onderdeel waar je in zit.

De vraag is echter, hoe past dat in MVC? Hier is volgens mij geen eenduidig antwoord op, althans, ik heb deze nooit echt gevonden. Dit is meer een soort van systeemarchitectuurvraag - hoe regel ik de opbouw van mijn webpagina's, en tegelijkertijd probeer je waarschijnlijk MVC te doorgronden en dit concept toe te passen :).

Mijn (voorzichtige) advies zou zijn: maakt het jezelf niet te moeilijk. Neem voorlopig genoegen een MVC-aanpak voor de hoofdcontent, en organiseer ondertussen alle "randfunctionaliteit" zoals menu's en sidebars zo goed als dat kan en zinnig is in op zijn minst classes en templates.

Daarnaast zijn er misschien ook nog wel andere logische eenheden te onderscheiden (zoals het Maintemplate, het skelet van je webpagina, waarin dit menu en alle andere "randcontent" min of meer verankerd zit)?

Mogelijk kun je dat later nog wel helemaal ombouwen naar een soort van hiërarchische MVC (volgens mij heette dat ook echt zo HMVC) maar blijf je zelf afvragen: ben ik nu niet het paard achter de wagen aan het spannen door mezelf het gereedschap op te leggen waarmee ik de klus zou moeten klaren?

Ik heb ook redelijk wat informatie gezocht over wat MVC nu precies is en hoe dit er in de praktijk uit zou moeten zien. Die zoektocht werd aanzienlijk bemoeilijkt door ... ahem ... hardliners die daar ... uitgesproken meningen over hebben :). Hierbij is het waarschijnlijk belangrijk (zoals ook een van de comments zei, geloof ik) dat MVC een idee (jaja, design pattern) is, met vele uitwerkingsvormen / verschijningen.

@Thomas. Dat is geen antwoord op mijn vraag. Ik heb je de Controller getoond. Dus de vraag blijft. Kan ik jou oplossing in mijn Controller integreren? Dat is het enige dat ik graag zou willen weten. Anders blijf ik mijn oude systeem hanteren
Volgens mij zegt Thomas hier met heel veel woorden: zie maar (er is niet 1 "juiste" manier). Dus zoals je het nu gedaan hebt is een (prima) oplossing.

Zelf neig ik wat meer naar de "hard liners" toe, en zou ik alleen de hiërarchische layoutData meegeven (dus de data uit $this->tree in Thomas z'n voorbeeld), en de werkelijke HTML uitwerking in je (HTML) template doen. In mijn eigen geval iets van:

//in main template
<!-- 
  toon voor alle items in mainMenu de volgende regel 
  (incl subMenu via tekst blok "subMenu")
-->
<ul class="main-menu">
[*mainMenu|<li><a href='\[url\]'>\[label\]</a>\[@subMenu\]</li>]
</ul>

//en tekst blok "subMenu" is dan:
<!--
  indien children, toon alle children
  en indien die weer children, enz
-->
{[%children]{<ul class="sub-menu">
[*children|<li><a href='\[url\]'>\[label\]</a>\[@subMenu\]</li>]
</ul>}}


Voordeel hiervan is dat je "later" de menu data ook heel eenvoudig via bijvoorbeeld een JSON view mee kunt geven aan een API ofzo (mocht je een app gaan maken die wel dezelfde menu structuur gaat gebruiken, maar deze zelf rendert - vanuit die JSON data).
Ik bedoelde meer dat een menu een onderdeel is van een groter geheel, en dat het misschien logischer is om op dat grotere geheel het MVC-patroon toe te passen, en niet op elke snippet.

Dat is geen antwoord op mijn vraag.

Misschien niet, maar ik probeer je attent te maken op wat nuances, en dat je misschien wat aan het doorslaan bent met waar en wanneer je MVC zou moeten toepassen.

Los daarvan, dit klinkt nogal ondankbaar. Ik krijg niet betaald om jouw problemen op te lossen en ik wil je ook niet direct een (rechtstreekse) oplossing geven, want dan sta je morgen weer voor de deur met iets waar je niet voldoende over na hebt gedacht. Ik wil dat je nadenkt over wat je doet zodat je er op een gegeven moment zelf uit kunt komen.

Daarbij, stel dat jij het moeras inrijdt, moet ik je dan aanmoedigen en uitleggen hoe je beste kunt vermijden dat je niet vast komt te staan in de blubber, of zou het toch handiger zijn je te wijzen op een verharde weg? Ik snap dat jij zo snel mogelijk naar je bestemming wilt, maar er moet wel een weg lopen. Soms moet je terug om vooruit te kunnen.

Jij vraagt om advies, en vervolgens zeg je in wezen "dit antwoord / deze aangewezen oplossingsrichting bevalt me niet". Mja. Good luck.
@Thomas. Het is absoluut geen ondankbaarheid. Ik vraag alleen of hetgeen jij als voorbeeld gaf in mijn huidige Controller kan worden geïntegreerd. Ik vraag je niet om een complete website te maken, ik vraag je niet om op basis van wat ik heb getoond het af te maken zodat ik het kan het kan kopiëren en plakken. Ik vraag alleen of het mogelijk is om hetgeen je als voorbeeld gaf in mijn huidige Controller te integreren.

Sorry dat je het verkeerd hebt begrepen

Reageren