[PHP] volledige navigatiestructuur opbouwen uit parentID's

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Hoi,

ik zit met een probleempje, ik ik vind maar geen oplossing. Ik wil namelijk een navigatie opbouwen, bestaande uit parentID's. Hierbij gebruik makend van een MySQL database, waar elke navigatieitem een ID en een parentID heeft

vb

14
--20
--22
----------33
----------34
-----------------44
-----------------45
-----------------46
----------35
--23
--24
15
16

Je ziet dat items 20,22,23,24 parentID 14 hebben, items 33,34,35 hebben parentID 22 enz...
Nu, als ik item selecteerd heb, bijvoorbeeld 46, dan moet de onderliggende boomstructuur opgebouwd worden.

Hiervoor heb ik het "spoor" tot item 46 in een array gegenereerd:
$nav_trail = array(14,22,34,44);
ook worden nog 3 arrays gegenereerd met de inhoud van de volledige navigatiestructuren:
$nav["0"] = array(14,15,16);
$nav["1"] = array(20,22,23,24);
$nav["2"] = array(33,34,35);
$nav["3"] = array(44,45,46);

Hoe kan ik dit nu opbouwen zodat ie tot gekozen ID opbouwt, en hij ook alle subnavigatieitems laat zien, zoals in het voorbeeld boven...

thx!

Acties:
  • 0 Henk 'm!

  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

Wellicht moet je dit artikel eens lezen ... dat was voor mij echt een enorme eye-opener:

http://www.sitepoint.com/article/hierarchical-data-database

Met die methode kun je in één keer een hele "familie" uit de database halen, hetzij vanuit een "parent" naar beneden toe, hetzij vanuit een "child" naar boven toe.

Acties:
  • 0 Henk 'm!

Verwijderd

Mag je wel behoorlijk rekening gaan houden met update, inserts en deletes. Die hebben nogal een behoorlijke impact op het model wat ze voorstellen. Waarom sla je je structuur niet op in XML, kan je middels DOMDocument en DOMXpath alles ook snel uitlezen!

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Verwijderd schreef op woensdag 27 juli 2005 @ 13:21:
Mag je wel behoorlijk rekening gaan houden met update, inserts en deletes. Die hebben nogal een behoorlijke impact op het model wat ze voorstellen. Waarom sla je je structuur niet op in XML, kan je middels DOMDocument en DOMXpath alles ook snel uitlezen!
Kan je me een voorbeeld geven van zo een XML structuur met DOMDocument en DOMXpath?
thx

Acties:
  • 0 Henk 'm!

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 20:38

alienfruit

the alien you never expected

Ik heb nog geen echte noemenswaardige betere performances gezien tussen de twee methods in dat artikel met MySqle en PHP.

Acties:
  • 0 Henk 'm!

Verwijderd

Klein voorbeeldje... Kan fouten bevatten want het is uit het blote hoofd...

code:
1
2
3
4
5
<data>
   <node title="link1" />
   <node title="link2" />
   <node title="link3" />
</data>

PHP:
1
2
3
4
5
6
7
8
9
10
$domdoc = new DOMDocument();
$domdoc -> load('file.xml');

$domxpath = new DOMXPath($domdoc);
$nodes = $domxpath -> query(/data/node);

foreach ($nodes as $node)
{
   echo $node -> getAttribute('title') . '<br />';
}


O ja, DOMDocument en Xpath werkt volgens mij pas volledig vanaf PHP5. In die versie zijn iig alle specs van w3c verwerkt die gelden voor het domdocument.

Acties:
  • 0 Henk 'm!

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 18-09 16:28

Bosmonster

*zucht*

alienfruit schreef op woensdag 27 juli 2005 @ 13:31:
Ik heb nog geen echte noemenswaardige betere performances gezien tussen de twee methods in dat artikel met MySqle en PHP.
Bij hele grote boomstructuren werkt MPTT (om het maar even af te korten) natuurlijk stukken efficienter. Ja je moet iets meer doen bij het invoegen, verwijderen en wijzigen (paar updates), maar over het algemeen is 99% van wat je doet het weergeven.

Maar zoals hij ook al zegt, bij kleine bomen, of in situaties waar je toch altijd de hele boom op wilt halen, werkt het parent/child model prima. In de meeste gevallen dus.

XML is leuk, maar als je heel je systeem in een database hebt staan met relaties is het wat onhandig om door een boomstructuurtje daar ineens XML voor te pakken :)


[edit]
Wel nog opmerking over het voorbeeld van gvanh. Hij voert de queries recursief uit, wat ik zelf nooit zou doen. Als je boom niet zo groot is (wat ie waarschijnlijk niet is als je parent/child gebruikt) is het een stuk efficienter gewoon eerst de gehele boom op te halen en er vervolgens in je software doorheen te lopen. Kost je beetje geheugen, maar dit is verwaarloosbaar vergeleken met tientallen queries.

[ Voor 37% gewijzigd door Bosmonster op 27-07-2005 13:44 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Bosmonster schreef op woensdag 27 juli 2005 @ 13:39:
XML is leuk, maar als je heel je systeem in een database hebt staan met relaties is het wat onhandig om door een boomstructuurtje daar ineens XML voor te pakken :)
Dat ben ik met je eens, maar ik las nergens dat hij al een bestaand systeem gebruikte, van daar mn suggestie. Ik ben het zelf nu voor een website aan het toepassen en vind het een stuk prettiger in gebruik dan dit via een db te doen. Zeker met de volledige implementatie van het DOMDocument in PHP5 werkt dat top!

Acties:
  • 0 Henk 'm!

  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

Hmm... ik heb altijd begrepen dat je recursie in je code zoveel mogelijk moet voorkomen. Het is dan erg fijn om met één enkele query al je data uit de boom te kunnen halen en deze - bijvoorbeeld - direct naar je template engine te kunnen sturen zonder verdere bewerkingen.

Het toevoegen/verplaatsen/verwijderen van "nodes" in je boom is niet heel erg ingewikkeld. Bovendien hoef je hier maar één keer een tweetal functies voor te schrijven (add_tree_node() en remove_tree_node()), en je kunt ze overal opnieuw gebruiken.

Zoals ik al zei ... ik ben zelf erg blij met het systeem, het scheelt me een hoop kopzorgen.

Acties:
  • 0 Henk 'm!

Verwijderd

gvanh schreef op woensdag 27 juli 2005 @ 13:51:
Hmm... ik heb altijd begrepen dat je recursie in je code zoveel mogelijk moet voorkomen.
Zonder er zelf een waarde oordeel aan te hangen: waarom?

Acties:
  • 0 Henk 'm!

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 18-09 16:28

Bosmonster

*zucht*

Verwijderd schreef op woensdag 27 juli 2005 @ 14:11:
[...]

Zonder er zelf een waarde oordeel aan te hangen: waarom?
Doorzichtigheid. Als het niet nodig is, niet doen.

Scheelt iedere collega een uur studie per recursie.

Acties:
  • 0 Henk 'm!

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 20:38

alienfruit

the alien you never expected

Hmmm, tot 35.000 nodes gaat het hier in iedergeval snel genoeg 0.2311 seconden volgens microtime() :P

Acties:
  • 0 Henk 'm!

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 18-09 16:28

Bosmonster

*zucht*

alienfruit schreef op woensdag 27 juli 2005 @ 14:14:
Hmmm, tot 35.000 nodes gaat het hier in iedergeval snel genoeg 0.2311 seconden volgens microtime() :P
Welk voorbeeld? :P

Acties:
  • 0 Henk 'm!

Verwijderd

Bosmonster schreef op woensdag 27 juli 2005 @ 14:13:
Doorzichtigheid. Als het niet nodig is, niet doen.
Scheelt iedere collega een uur studie per recursie.
Recursie kan het vaak veel beter leesbaar maken. Maar ik ben dus benieuwd naar de criteria van de uitspraak: beter niet gebruiken.

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 20:06

RayNbow

Kirika <3

Verwijderd schreef op woensdag 27 juli 2005 @ 14:20:
[...]

Recursie kan het vaak veel beter leesbaar maken. Maar ik ben dus benieuwd naar de criteria van de uitspraak: beter niet gebruiken.
Recursie moet je alleen vermijden als het niet echt efficient is. Dit hangt dus af per geval. Een geval waar het niet zo slim is om bijv. recursie te gebruiken is om een bepaald Fibonacci getal te berekenen.

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 20:38

alienfruit

the alien you never expected

Welk voorbeeld? :P
Gewoon een unit testcase, je pleurt random nodes met parent e.d. in een tabel en uitlezen maar en dan de start- en eindtijd bijhouden en van elkaar aftrekken :)

Acties:
  • 0 Henk 'm!

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 18-09 16:28

Bosmonster

*zucht*

Verwijderd schreef op woensdag 27 juli 2005 @ 14:20:
[...]

Recursie kan het vaak veel beter leesbaar maken. Maar ik ben dus benieuwd naar de criteria van de uitspraak: beter niet gebruiken.
Voor jou iets verder uitgelegd dan:

- doorzichtigheid van code
- efficiency (niet altijd even efficient)
- gevoelig voor fouten (door ondoorzichtigheid)

Acties:
  • 0 Henk 'm!

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 18-09 16:28

Bosmonster

*zucht*

alienfruit schreef op woensdag 27 juli 2005 @ 14:26:
[...]


Gewoon een unit testcase, je pleurt random nodes met parent e.d. in een tabel en uitlezen maar en dan de start- en eindtijd bijhouden en van elkaar aftrekken :)
Yeah maar een parent/child model dus, niet dat MPTT :)

En in 1x inlezen, niet recursief (waar de kritiek dus op is). (of doe je het wel recursief? Dan vind ik het een goeie prestatie :+)

[ Voor 8% gewijzigd door Bosmonster op 27-07-2005 14:29 ]


Acties:
  • 0 Henk 'm!

Verwijderd

RayNbow schreef op woensdag 27 juli 2005 @ 14:24:
Recursie moet je alleen vermijden als het niet echt efficient is. Dit hangt dus af per geval. Een geval waar het niet zo slim is om bijv. recursie te gebruiken is om een bepaald Fibonacci getal te berekenen.
Open deuren zijn leuk :) Je moet natuurlijk niet recursie als doel hebben. Juist Fibonacci leent zich er uitstekend voor (in eerste instantie) om middels recursie te worden geimplementeerd. Immers Fib ( x ) = x * Fib ( x -1 ) .

Een leidend criteria vind ik overigens de mogelijke diepte, ga je voor je gevoel te diep dan is recursie niet de oplossing.
Bosmonster schreef op woensdag 27 juli 2005 @ 14:27:
Voor jou iets verder uitgelegd dan:
- doorzichtigheid van code
Ik zie recursie niet inherent aan onleesbare/ondoorzichtige code, ik denk ook niet dat je die uitspraak daarom kunt doen.

Overigens voor het probleem van de TS, recursie wordt hier alleen tezamen met een DB call genoemd, maar je kunt toch ook de hele tabel binnen halen en vervolgens er recursief doorheen lopen...

[ Voor 28% gewijzigd door Verwijderd op 27-07-2005 14:35 ]


Acties:
  • 0 Henk 'm!

  • Morphine
  • Registratie: Februari 2002
  • Laatst online: 09-09 19:45
Goh mocht het gelukt zijn, de php code (van de update acties end. en weergave) zou wellicht leuk zijn :*) (_/-\o_ )

Acties:
  • 0 Henk 'm!

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 20:38

alienfruit

the alien you never expected

Tuurlijk niet recursief :+ Ik heb het niet zo op die andere methode voor het opslaan van boomstructuren, op één of andere manier vind ik dat een minder nette manier, onduidelijker etc. :) Maar recursieve zo van elke function call records ophalen, ik haal alles op en vervolgens: SortedArrayList::set( $resultset ) :+

[ Voor 26% gewijzigd door alienfruit op 27-07-2005 14:37 ]


Acties:
  • 0 Henk 'm!

  • jochemd
  • Registratie: November 2000
  • Laatst online: 24-08 12:31
Verwijderd schreef op woensdag 27 juli 2005 @ 13:21:
Mag je wel behoorlijk rekening gaan houden met update, inserts en deletes. Die hebben nogal een behoorlijke impact op het model wat ze voorstellen.
Daar valt wel omheen te werken. Hoewel ik me kan voorstellen dat je dit niet in een MySQL database wil implementeren bij gebrek aan ondersteuning voor stored procedures, functions etc.

Acties:
  • 0 Henk 'm!

  • PhoeniX-
  • Registratie: Juni 2000
  • Laatst online: 01-09 10:26
Een tijdje geleden moest ik een menu maken met verschillende niveaus. Het leek mij leuk om dit in XML te zetten en uiteindelijk werkt het prima:

XML:
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
<menuxml>
    <menu name="main">
        <item position="1">
            <linkname>
                <en>Home</en>
                <nl>Home</nl>
            </linkname>
            <link>index.php?menu_id=1</link>
        </item>
        <item position="2" iscontainer="true">
            <linkname>
                <en>Adverts</en>
                <nl>Advertenties</nl>
            </linkname>
            <item position="1">
                <linkname>
                    <en>Horses for sale</en>
                    <nl>Paarden te koop</nl>
                </linkname>
                <link>index.php?menu_id=5&amp;mode=forsale</link>
            </item>
            <item position="2">
                <linkname>
                    <en>Horses sought</en>
                    <nl>Paarden gezocht</nl>
                </linkname>
                <link>index.php?menu_id=5&amp;mode=wanted</link>
            </item>
        </item>
    </menu>
</menuxml>

Met het iscontainer attribuut geef ik aan of het item subitems heeft - een dergelijk menu-item moest in dit geval iets anders gerenderd worden.

Een recursieve (ik meng me niet in de discussie ;)) functie leest heel de boom uit en bouwt het menu op. Voor de XML functionaliteit heb ik de PEAR module XML_Tree gebruikt - deze werkt ook prima onder PHP 4.x.

[ Voor 19% gewijzigd door PhoeniX- op 27-07-2005 14:54 ]


Acties:
  • 0 Henk 'm!

  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

Om nog even door te zagen over dat recursie verhaal. Van wat ik ervan begrepen heb, is het probleem bij recursie, dat het veel geheugen-ruimte vreet. Bij iedere keer dat dezelfde functie wordt aangeroepen, moet immers voor alle variabelen in de functie opnieuw geheugenruimte vrij worden gemaakt. Wanneer flink oploopt, kan dat de boel redelijk hard vertragen.

Als voorbeeld (het is niet specifiek recursief, maar toch) ... een jaar of wat geleden heb ik een systeem gemaakt, waarbij scholen, leerlingen, docenten e.d. betrokken waren. Een heel mooi (en overzichtelijk) systeem gebouwd, waarbij steeds alle sub-objecten aan een object werd gekoppeld. Als ik dus een school uit de database viste, dan haalde de school automatisch zelf de daaraan gekoppelde adresgegevens uit de database (aparte query). Ook was het handig om per school altijd de contactpersoon bij de hand te hebben, dus op een gegeven moment ook maar zo geregeld dat bij het ophalen van een school automatisch de contactpersoon werd opgehaald. Bij het ophalen van de contactpersoon werden dan automatisch de adresgegevens van de contactpersoon opgehaald...

Je voelt hem al aankomen ... bij het opvragen van een overzicht van scholen met daaraan gekoppelde contactpersonen was bij een toegenomen aantal scholen een gigantische hoeveelheid queries vereist. Nu heb ik wat meer toegespitste queries moeten schrijven, die in een keer alle benodigde data uit de db halen, maar het scheelt enórm in tijd.

Of hoort dit in een topic over hoe je een webapplicatie NIET moet inrichten :+

Acties:
  • 0 Henk 'm!

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 18-09 16:28

Bosmonster

*zucht*

Morphine schreef op woensdag 27 juli 2005 @ 14:33:
Goh mocht het gelukt zijn, de php code (van de update acties end. en weergave) zou wellicht leuk zijn :*) (_/-\o_ )
Check de link uit de eerste reactie nog eens ;)

Alle voorbeelden met nette PHP code bij elkaar.

Acties:
  • 0 Henk 'm!

  • PhoeniX-
  • Registratie: Juni 2000
  • Laatst online: 01-09 10:26
gvanh schreef op woensdag 27 juli 2005 @ 14:54:
Je voelt hem al aankomen ... bij het opvragen van een overzicht van scholen met daaraan gekoppelde contactpersonen was bij een toegenomen aantal scholen een gigantische hoeveelheid queries vereist. Nu heb ik wat meer toegespitste queries moeten schrijven, die in een keer alle benodigde data uit de db halen, maar het scheelt enórm in tijd.
Voor zover ik het heb gezien gaat optimalisatie altijd ten koste van normalisatie (in het geval van een database) of van code structuur (bv. recursieve functies).

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 20:06

RayNbow

Kirika <3

Verwijderd schreef op woensdag 27 juli 2005 @ 14:31:
[...]

Open deuren zijn leuk :) Je moet natuurlijk niet recursie als doel hebben. Juist Fibonacci leent zich er uitstekend voor (in eerste instantie) om middels recursie te worden geimplementeerd. Immers Fib ( x ) = x * Fib ( x -1 ) .
Dat is de definitie van faculteit ;) (En de meeste compilers kunnen die recursie omschrijven naar een for loop).

Definitie van de Fibonacci reeks:
Fib(n) = Fib(n-1) + Fib(n-2)
Fib(0) = 0
Fib(1) = 1

Bij deze recursie worden veel berekeningen opnieuw gedaan. Tabelletje:
-Fibonacci-
  N  Fibonacci(n)  Aantal aanroepen
-----------------------------------
  1             1                 1
  2             1                 3
  4             3                 9
  8            21                67
 16           987              3193
 32       2178309           7049155

Toelichting:
Om Fib(4) te berekenen moet je Fib(3) en Fib(2) berekenen.
Om Fib(3) te berekenen moet je Fib(2) en Fib(1) berekenen.
Om Fib(2) te berekenen moet je Fib(1) en Fib(0) berekenen.
Fib(1) = 1.
Fib(0) = 0.
Fib(2) = 0 + 1 = 1.
Fib(1) = 1 (Dit is vanuit de Fib(3) aanroep).
Fib(3) = 1 + 1 = 2.
Om Fib(2) te berekenen moet je Fib(1) en Fib(0) berekenen. (Dit is vanuit de Fib(4) aanroep).
Fib(1) = 1.
Fib(0) = 0.
Fib(2) = 0 + 1 = 1.
Fib(4) = 2 + 1 = 3.

Dit is dus een voorbeeld waarbij recursie niet efficient is.

[ Voor 4% gewijzigd door RayNbow op 27-07-2005 15:57 ]

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

Verwijderd

gvanh schreef op woensdag 27 juli 2005 @ 12:56:
Wellicht moet je dit artikel eens lezen ... dat was voor mij echt een enorme eye-opener:

http://www.sitepoint.com/article/hierarchical-data-database

Met die methode kun je in één keer een hele "familie" uit de database halen, hetzij vanuit een "parent" naar beneden toe, hetzij vanuit een "child" naar boven toe.
Ik heb dit artikel een hele tijd terug eens gelezen, maar we hebben hier toch gekozen voor de parentid aanpak (adjacency list). Deze table opzet is veel helderder om te lezen en makkelijker handmatig bij te werken dan de aanpak die in dit artikel wordt voorgesteld. Ook de voorgestelde methodes om een node toe te voegen (op pagina 3) zijn veel gecompliceerder en minder efficient dan bij de parentid aanpak.

Het echte voordeel zit em schijnbaar erin dat je een hele (sub)boom in 1 query kan oproepen:
SQL:
1
SELECT * FROM tree WHERE lft BETWEEN 2 AND 11;

Het is misschien persoonlijke voorkeur, maar uit deze SQL query blijkt totaal niet wat er nou eigenlijk precies wordt opgevraagd. Doe mij dan naar een aantal van deze recursieve queries: >:)

SQL:
1
SELECT * FROM tree WHERE parentid=x;

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 20:06

RayNbow

Kirika <3

Verwijderd schreef op woensdag 27 juli 2005 @ 17:24:
[...]
Het echte voordeel zit em schijnbaar erin dat je een hele (sub)boom in 1 query kan oproepen:
SQL:
1
SELECT * FROM tree WHERE lft BETWEEN 2 AND 11;

Het is misschien persoonlijke voorkeur, maar uit deze SQL query blijkt totaal niet wat er nou eigenlijk precies wordt opgevraagd. Doe mij dan naar een aantal van deze recursieve queries: >:)

SQL:
1
SELECT * FROM tree WHERE parentid=x;
Maar die SQL query hoef je in principe maar 1 keer te schrijven en in een functie oid te stoppen. In de rest van je code zie je dan alleen aanroepen naar je geschreven functie en zie je niets meer terug van je SQL query.

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

gvanh schreef op woensdag 27 juli 2005 @ 13:51:
Het toevoegen/verplaatsen/verwijderen van "nodes" in je boom is niet heel erg ingewikkeld. Bovendien hoef je hier maar één keer een tweetal functies voor te schrijven (add_tree_node() en remove_tree_node()), en je kunt ze overal opnieuw gebruiken.
En als je een node wilt verplaatsen? :P

Ik heb mijn menu zowel met parents als met die left en right boundaries methode in de database staan. Bij wijzigingen (toevoegen, verwijderen, verplaatsen), doe ik dat door de parents of de index (index 1 staat voor index 2 als ze dezelfde parent hebben), te wijzigen.

Daarna gooi ik een functie eroverheen die vanuit de parent structuur opnieuw de linker en rechter getallen uitrekent.

Dat is minder efficient dan het zou kunnen bij simpele verplaatsingen, maar als de boomstructuren niet ultragroot zijn, dan is dat geen probleem. En je hoeft maar een functietje te maken in plaats van meerdere.

Acties:
  • 0 Henk 'm!

  • Johnny
  • Registratie: December 2001
  • Laatst online: 14:39

Johnny

ondergewaardeerde internetguru

Ik doe het gewoon zo, met een enkele query, en een tabel die enkel een id en parent_id heeft, het komt er op neer dat je eerst alle data in een array steekt en daarna doormiddel van recursie doorloopt.

Het is lijkt misschien een beetje nodeloos ingewikkeld, maar dat is omdat de originele versie ook meerdere parents per child ondersteunde (werkte met 2 tabellen).

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
$list_subject_id = array();
$list = array();
$list_id = array();
$list_parent_id = array();

function getChildList($id) {

    global $list_parent_id, $list_id;

    $child_list = array();

    for($i = 0; $i < count($list_parent_id); $i++) {

        if($list_parent_id[$i] == $id) {
            array_push($child_list, $list_id[$i]);
        }
    }

    return $child_list;
}


function getSubjectList($start_level) {

    global $list, $list_id, $list_parent_id;
    
    $list = array();
    $list_id = array();
    $list_parent_id = array();

    $query = "SELECT id, parent_id, name, descr FROM subject ORDER BY parent_id, name";
    $result = mysql_query($query);
    while(list($subject_id, $subject_parent_id, $subject_name, $subject_descr) = mysql_fetch_row($result)) {
        
        array_push($list_id, $subject_id);
        array_push($list_parent_id, $subject_parent_id);

        $list[$subject_id]['name'] = $subject_name;
        $list[$subject_id]['descr'] = $subject_descr;
    }

    return getSubjectListChildren(0, $start_level);

}

function getSubjectListChildren($parent_id, $level) {

    global $list, $list_subject_id;

    if($level <= 6) {
        $level++;
    }

    $output = '';

    $child_list = getChildList($parent_id);

    for($i = 0; $i < count($child_list); $i++) {

        if(in_array($child_list[$i], $list_subject_id)) {
            continue;
        }

        $item = $list[$child_list[$i]];

        $output = $output.'<li><h'.$level.' title="'.$item['descr'].'"><a href="admin_subject.php?id='.$child_list[$i].'">'.$item['name'].'</a></h'.$level.'>';

        array_push($list_subject_id, $child_list[$i]);

        $output_children = getSubjectListChildren($child_list[$i], $level);

        if(strlen($output_children) > 0) {
            $output = $output.'<ul>'.$output_children.'</ul>';
        }

        $output = $output.'</li>';
    }

    return $output;
}


?>

[ Voor 8% gewijzigd door Johnny op 27-07-2005 17:54 ]

Aan de inhoud van de bovenstaande tekst kunnen geen rechten worden ontleend, tenzij dit expliciet in dit bericht is verwoord.


Acties:
  • 0 Henk 'm!

  • Genoil
  • Registratie: Maart 2000
  • Laatst online: 12-11-2023
Goh toevallig zo'n topic precies op de dag dat ik overgestapt ben van adjencent tree (AT) op MPTT.

Ik ben het in ieder geval heel oneens met de mensen die de voorkeur geven aan het AT model omdat het er zoveel logischer en helderder uitziet. Vanuit een menselijk perspectief is dat misschien wel zo, maar vanuit een database gezien (tabulair, set-based) is MPTT veel logischer. AT heeft steeds 1 set met een parent uit een andere set, terwijl MPTT simpelweg 1 set heeft.

Stel, je hebt een x aantal kartonnen dozen van verschillende maten (denk maar aan je hardwaredozencollectie ;)) en die wil je zo efficient mogelijk opbergen, dan hang je ze niet allemaal aan elkaar met touwtjes, maar je stopt de kleinere (of meer daarvan bij elkaar) in de grotere. Als je dan dozen nodig hebt van een bepaald formaat en kleiner, pak je degene met de maximale afmetingen en ben je dus in 1 keer klaar.

Het probleem is natuurlijk als er een doos bij moet. Dan moet je het hele zootje weer opnieuw rangschikken. Maarja, hoevaak koop je nu nieuwe hardware ;)?

Bij de keuze tussen MPTT en AT moet je vooral kijken wat de verhouding is tussen SELECTs en INSERTs/UPDATEs/DELETEs. In de meeste gevallen zijn dat zoveel meer SELECTs dat MPTT efficienter is. En ja, dan kan je bij AT wel de hele zooi in 1 query ophalen en vervolgens alles in het geheugen gaan sorteren, maar dat is net zoeits als al je hardwaredozen willekeurig op zolder flikkeren en je elke keer als je er een nodig hebt rotzoeken ;). Als het snel moet is caching natuurlijk ook een handige tool.

Waar ik nog niet helemaal uit ben, is welk model het beste werkt met een polymorphe boomstructuur. Dat wil zeggen, m'n tree zit in een losse tabel en daaraan heb ik per node een referentie vanuit een record uit een willekeurige andere tabel hangen. Dan kan ik met MPTT nog wel in 1 query die hele tree eruit jassen, maar dan zou ik alle mogelijke tabellen erbij moeten joinen om tegelijk het object dat aan de node hangt erbij te krijgen, of per node alsnog met een aparte query het juiste object erbij zoeken. Met AT in principe hetzelfde...

Hebben jullie daar ideeen over?

Acties:
  • 0 Henk 'm!

Verwijderd

RayNbow schreef op woensdag 27 juli 2005 @ 15:56:
Dat is de definitie van faculteit ;) (En de meeste compilers kunnen die recursie omschrijven naar een for loop).
Tsja wat kan ik zeggen: OEPS :)
Je haalt ze wel eens door elkaar, anyways ik zat dus met faculteit in mijn hoofd...
Pagina: 1