[PHP] OO menu opbouwen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Voor een van mijn sites heb ik het menu geheel in de database staan, zodat dit via een cms gewijzigd kan worden.
In eerste instantie had ik het volgende database schema:
IdThemaRubriekSubRubriek

waarbij Id de primary key is.

Dit levert problemen op, wanneer je bijvoorbeeld de volgende DB input (1) hebt:
1Thema1
2Thema1Rubriek1
3Thema1Rubriek2
4Thema1Rubriek1Subrubriek1
enz..


Wanneer ik dan menuNode 1 wil wijzigen, en ik wil de titel naar 'Thema_1' wijzigen,
dan wordt deze titel niet automatisch geüpdate bij de overige relevante menuNodes.

Omdat ik hier toch vanaf wilde heb ik het DB schema aangepast naar
IdParentIdTitel

waarbij Id de primary key is, en ParentId een link naar de parent node (mag NULL zijn)

De inhoud van de database (2) zou er dan nu bijv zo uitzien:
1NULLThema1
21Rubriek1
31Rubriek2
42Subrubriek1
enz..


Nu wil ik de data hieruit tonen in een tabel die de vorm heeft als de DB input hiervoor(1) (dus id, thema, rubriek, subrubriek).

Hier komt het eerste probleem al om de hoek kijken: met mySql kan je niet recursief deze data uit de tabel trekken.
Hier komt dus mijn OO idee om de hoek kijken.

Je neemt een Menu object, daar voeg je elke keer een MenuNode object aan toe.
Het Menu object zoekt de goede parent die bij de betreffende MenuNode hoort op, en voegt aan deze parent een nieuw child toe.
Nadat dan alle MenuNodes in het geheugen goed aan elkaar gekoppeld zijn kan je lineair het menu laten tekenen.
Je vraagt aan Menu->geefMenu(), die maakt een String aan, vraagt aan zijn kinderen middels een for-loopje children[$i]->geefMenu() en dat gaat dan recursief door totdat het hele menu weer als String bij het Menu object terug komt.


De volgende code is onderdeel van de twee classes, het probleem zit hem volgens mij in de referentie naar het Parent Object dat ik terug krijg uit de functie zoekParent().
Het lijkt erop dat ik een kopie van het MenuNode object binnen krijg (met telkens weer als ik een child wil toevoegen, dat het weer het eerste kind is, ook al heb ik daarvoor ook al een child toegevoegd aan dit zelfde(?!?) object). Eigenlijk moet ik hier dus een referentie naar de parent MenuNode terug krijgen i.p.v. een kopie ervan.

Menu.php:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
    db_connect();
    
    $query = "SELECT Id, ParentId, Titel FROM menuItems ORDER BY ParentId, Titel";
    $result = mysql_query($query);
    
    $menu = new Menu;

    while ($row = mysql_fetch_array($result)) {
        // variabelen ophalen uit DB
        $menuNode = new MenuNode($Id, $Parent, $Titel);
        $menu->addNode($menuNode);
    }
    echo $menu->geefMenu();
?>


Menu.class:
PHP:
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
<?php
    var $alle_nodes = array();
    var $totaalAantalNodes = 0;
    var $children = array();
    var $aantalChildren = 0;
    
    function addNode(&$node) {
        $this->alle_nodes[$this->totaalAantalNodes] = $node;
        $this->totaalAantalNodes ++;
        
        $parentId = $node->geefParentId();
        $parent = $this->findParent($parentId);
                
        if ($parent != false) {
            $parent->addChild($node);
            echo $parent->aantalChildren.'<br>';
        }
        else {
            $this->addChild($node);
        }
    }

    function findParent($id) {
        for ($i = 0; $i < $this->totaalAantalNodes; $i ++) {
            if ($this->alle_nodes[$i]->geefId() == $id) {
                return $this->alle_nodes[$i];
            }
        }
        return false;       
    }
    
    function addChild(&$node) {
        $this->children[$this->aantalChildren] = $node;
        $this->aantalChildren ++;   
    }
?>


MenuNode.class:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
<?php
    var $children = array();
    var $aantalChildren;
    var $titel;
    var $id;
    var $parentId;
    
    function addChild(&$node) {
        $this->children[$this->aantalChildren] = $node;
        $this->aantalChildren ++;   
    }
?>


In de methode addNode() in Menu.class echo ik het aantal kinderen van de parent
na het toevoegen aan de parent.
Als ik een tweede node aan de zelfde parent toevoeg, blijft het aantal kinderen
van de parent 1 (of het is opnieuw 1)

Wat zou ik kunnen doen om dit goed te krijgen?

Acties:
  • 0 Henk 'm!

  • Alex
  • Registratie: Juli 2001
  • Laatst online: 20-08 21:38
Je zou hem als het ware global kunnen maken door hem via 'return' trug te geven. Is alelen geklooi dan wat je code niet echt ten goede komt.

Deze post is bestemd voor hen die een tegenwoordige tijd kunnen onderscheiden van een toekomstige halfvoorwaardelijke bepaalde subinverte plagiale aanvoegend intentioneel verleden tijd.
- Giphart


Acties:
  • 0 Henk 'm!

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 12:54

Bosmonster

*zucht*

Wat een ingewikkeld gedoe voor zoiets simpels :/

Je hebt alles in een simpel formaat in je database. Je kunt dit net zo simpel omzetten naar een multi-dimensional array structuur (of als je langzaam wilt doen je Object-structuur).

Zorg verder dat als een item geen parent heeft deze bijvoorbeeld 0 is (ipv NULL). Das een stuk makkelijk coden en scheelt je een berg checks. In je object zet je dit ook weer om naar false wat het er allemaal niet doorzichtiger op maakt.

Ook zitten er wat vreemde dingen in imho zoals:

$menuNode = new MenuNode($Id, $Parent, $Titel);
$menu->addNode($menuNode);

Waarom het aanmaken van de MenuNodes niet gewoon in de addNode() method regelen? Scheelt je wederom een hoop gedoe met pass-by-reference.

Verder vragen dit soort dingen om inconsistentie/redundantie:

$this->alle_nodes[$this->totaalAantalNodes] = $node;
$this->totaalAantalNodes ++;

handiger is bijvoorbeeld:

$this->alle_nodes[] = $node;
$this->totaalAantalNodes = sizeof($this->alle_nodes);

Maar ook wel belangrijk, je weet nu nooit zeker of je misschien al childNodes aan het toevoegen bent van parents die nog niet bestaan :? Die gaan dan dus mogelijk verloren.

Nog wat:

Je slaat nu een grote array op met daarin weer alle objecten.. en als je de parent daarvan wilt weten ga je daar doorheen loopen elke keer... sla ze dan op in een array met de Id als index...

Of kortweg: je bent van iets simpels iets heel ingewikkelds aan het maken :P

[ Voor 3% gewijzigd door Bosmonster op 12-07-2003 23:53 ]


Acties:
  • 0 Henk 'm!

  • CyberSnooP
  • Registratie: Augustus 2000
  • Laatst online: 16-08 06:44

CyberSnooP

^^^^ schrijft --->

Verwijderd schreef op 12 juli 2003 @ 20:39:
Hier komt het eerste probleem al om de hoek kijken: met mySql kan je niet recursief deze data uit de tabel trekken.
Hier komt dus mijn OO idee om de hoek kijken.
Ik zie de connectie tussen dit probleem en OO niet echt. Er zijn echter andere data-modellen die dit wel makkelijker mogelijk maken, zonder verdere vereiste functionaltieit van het DBMS. Lees daarover dit artikel op Webgoeroe.net eens door.
In de methode addNode() in Menu.class echo ik het aantal kinderen van de parent na het toevoegen aan de parent.
Als ik een tweede node aan de zelfde parent toevoeg, blijft het aantal kinderen
van de parent 1 (of het is opnieuw 1)

Wat zou ik kunnen doen om dit goed te krijgen?
Volgens mij heb je een references probleem, het object $parent is niet hetzelfde object als dat in de alle_nodes array, maar een clone (lang leve PHP en OO :)). Probeer dit eens:

Menu.class:
PHP:
12
$parent =& $this->findParent($parentId);
PHP:
23
function &findParent($id) {

|_____vakje______|


Acties:
  • 0 Henk 'm!

  • Bananeman
  • Registratie: Juli 2000
  • Niet online
CyberSnooP schreef op 13 July 2003 @ 11:07:

[...]
Volgens mij heb je een references probleem, het object $parent is niet hetzelfde object als dat in de alle_nodes array, maar een clone (lang leve PHP en OO :)). Probeer dit eens:

Menu.class:
PHP:
12
$parent =& $this->findParent($parentId);
PHP:
23
function &findParent($id) {
Dit is idd het probleem... en dan moet b.v. ook de volgende regel veranderen:

PHP:
1
$menuNode = new MenuNode($Id, $Parent, $Titel);

moet worden:
PHP:
1
$menuNode =& new MenuNode($Id, $Parent, $Titel);

Motor-forum.nl


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Bedankt allemaal voor de reacties.
Bosmonster schreef op 12 July 2003 @ 23:51:

Je hebt alles in een simpel formaat in je database. Je kunt dit net zo simpel omzetten naar een multi-dimensional array structuur (of als je langzaam wilt doen je Object-structuur).
Hier ben ik na jouw tip ook even mee aan het stoeien geweest, maar hier liep ik ook nog tegen enkele problemen aan waardoor ik dit even aan de kant heb gezet om later nog eens over na te denken.
(het lampje flikkert nog een beetje; heb het licht nog niet helmaal gezien :))
Je slaat nu een grote array op met daarin weer alle objecten.. en als je de parent daarvan wilt weten ga je daar doorheen loopen elke keer... sla ze dan op in een array met de Id als index...
Perfect! Dit werkt natuurlijk veel sneller om de parent te vinden!
Ik had er helemaal niet bij stilgestaan dat je de objecten ook in de array kon toevoegen op de index van hun primary key..
Bananeman2002 schreef op 13 July 2003 @ 18:46:

Dit is idd het probleem... en dan moet b.v. ook de volgende regel veranderen:

PHP:
1
$menuNode = new MenuNode($Id, $Parent, $Titel);

moet worden:
PHP:
1
$menuNode =& new MenuNode($Id, $Parent, $Titel);
Volgens mij maakt dit niet echt uit, want wanneer ik de MenuNode aan het Menu toevoeg maakt het eigenlijk niet zo veel uit of ik er een diepe kopie van krijg, de references die ik erna gebruik zijn wat dat betreft veel belangrijker
CyberSnooP schreef op 13 July 2003 @ 11:07:

Volgens mij heb je een references probleem, het object $parent is niet hetzelfde object als dat in de alle_nodes array, maar een clone (lang leve PHP en OO :)). Probeer dit eens:

Menu.class:
PHP:
12
$parent =& $this->findParent($parentId);
PHP:
23
function &findParent($id) {
Dit werkt inderdaad een stuk beter!
Ik heb nu alleen nog een probleem in mijn geefMenu() methode, dat de references in de children array niet helemaal goed staan, maar daar stoei ik nog wel even mee verder.

Maar...
dit brengt mij meteen bij de volgende onduidelijkheid:
Hoe strict moet je zijn bij het gebruik van het &-teken?

Ik ben bijvoorbeeld in voorbeeld code al eens tegengekomen:
PHP:
1
2
3
    function doeIets(&$objectje) {
        $this->objectje =& $objectje;
    }

Maar ook:
PHP:
1
2
3
    function doeIets(&$objectje) {
        $this->objectje = $objectje;
    }

Maakt het nou nog uit of je de eerste of de tweede methode gebruikt?
Of heb je bij de tweede manier nog steeds dat php een kopie maakt van je object?!?
En is de tweede manier dus pertinent fout?!?
Pagina: 1