Hi all,

Voor de puzzelaars onder ons een leuke kwestie...

Ik ben bezig met een folder-systeem.
Mijn tabel (kort):

id | parent_id
m2 | NULL
m21 | m2
m22 | m2
m23 | m2
m26 | m22
m29 | m26
m30 | m26

Een folder heeft dus een id, en een parent_id (dat is de id van de map die boven hem ligt.

Stel, ik wil een map verwijderen moet ik ook al zijn childs verwijderen.
Daarvoor wil ik een array hebben met alle childs.

Hiervoor zijn denk ik 2 functies nodig.

1) getchild($var). Deze functie (heb ik al), geeft een array met alle childs van de map $var.

2) allchilds($var). Deze functie (???), zal in de array moeten zoeken en de getchild() uit moeten voeren en zijn array uitbreiden...

Hoe moet ik dit bouwen? Hoe laat ik hem zichzelf herhalen totdat er geen childs meer zijn en hoe zet ik dat in een nette array?

ps. Ik werk in CakePhp, maar tips zijn op welke manier dan ook welkom!

Alvast bedankt!
Daar hoef je helemaal geen puzzelaar voor te zijn, daarvoor moet je gewoon het juiste data model gebruiken. Een hierarchische boomstructuur op zo'n manier in een database proppen lijkt simpel als je eraan begint, maar kleine taken zijn al nagenoeg niet te doen. Voor wat jij nu wil doen bijvoorbeeld, heb je een ongedefinieerd aantal self joins nodig. En dat is natuurlijk niet te doen. In een SQL query ken ik in elk geval geen goede manier om een recursieve functie te bouwen.

Dus, de oplossing, gebruik een nested set model: http://en.wikipedia.org/wiki/Nested_set_model
Wat lastiger om te bouwen, maar dat werkt in elk geval wel. En voor jouw probleem heb je dan een vrij simpele oplossing:

SELECT b.id
FROM mappen a
LEFT JOIN mappen b ON b.lft BETWEEN a.lft AND a.rgt
WHERE a.id = .... (vul hier het id in van de te verwijderen map)
Wanneer je je database iets beter in elkaar gezet had kon je de Iterator pattern gebruiken om langs alle childs te gaan van een bepaalde map en deze wissen.
Folder systeem, dan denk ik meteen aan PHPCR!
Erwin H op 07/10/2013 20:06:39


Dus, de oplossing, gebruik een nested set model: http://en.wikipedia.org/wiki/Nested_set_model
Wat lastiger om te bouwen, maar dat werkt in elk geval wel. En voor jouw probleem heb je dan een vrij simpele oplossing



Erwin, bedankt voor je verhelderende woord. Ziet er wel lastig uit; hoe bouw je dit terwijl alles variabel is?
Hier kan ik mee verder!

Waar ik altijd mee begin is gewoon de root te definieren. Met een root is het toevoegen van een node in de boom op zich niet zo moeilijk.

Als je een tabel hebt met een id (auto increment), lft, rgt en name veld, dan zou de root bijvoorbeeld 1 (lft), 2 (rgt), 'root' (name) zijn. Wil je dan een node toevoegen dan moet dat dus een child van de root worden en na het toevoegen van de node moeten de lft en rgt waardes als volgt zijn:

lft    rgt    name
1      4      root
2      3      node1 


Wil je dan een node toevoegen als kind van node1, dan krijg je dit:

lft    rgt    name
1      6      root
2      5      node1
3      4      node2


Hieruit kan je al het patroon opmerken van hoe je de lft en rgt waardes moet aanpassen bij een insert van een nieuwe node. De nieuwe node krijgt als lft waarde de rgt waarde van zijn nieuwe parent, als rgt waarde wordt lft+1 en alle lft en rgt waardes in de boom die groter of gelijk zijn aan de rgt waarde van de nieuwe parent moeten met twee opgehoogd worden. Als sql queries heb je dus dit nodig:

//zorg dat je de rgt waarde van de nieuwe parent weet, die moet overal op de stippellijnen worden ingevuld
UPDATE tree
SET lft = lft+2
WHERE lft > ....
ORDER BY lft DESC;

UPDATE tree
SET rgt = rgt+2
WHERE rgt >= ....
ORDER BY lft DESC;

INSERT INTO tree(lft, rgt, name)
VALUES(..., ...+1, 'nodeX');

De ordering in de update queries is alleen nodig als je een unieke index gebruikt op de lft en rgt kolommen.
Bij voorkeur verpak ik al deze queries in een stored procedure om het bij elkaar te houden en zodat je zeker weet dat je niet een update vergeet.
Hoi Erwin,

Bedankt voor je mooie uitleg.
Heel duidelijk!
Ik ben er nu mee bezig en je voorbeeld werkt uitstekend!
Bedankt!!!
Als het inserten lukt, dan is de volgende taak om elementen uit de boom te halen. Ook daar zal je de boom moeten herstructureren op een soortgelijke manier.
Dat zeg ik toch?
Erwin H op 08/10/2013 20:10:56

Als het inserten lukt, dan is de volgende taak om elementen uit de boom te halen. Ook daar zal je de boom moeten herstructureren op een soortgelijke manier.

Als je niets doet aan de lft en rgt waardes dan gaat je hele boomstructuur naar de knoppen.
Erwin,

Kan ik mijn tabel ook meerdere 'roots' hebben met dezelfde lft en rgt? (1 en 2?)

Reageren