Php; alle childs zoeken

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Simon Simons

Simon Simons

07/10/2013 19:30:56
Quote Anchor link
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!
 
PHP hulp

PHP hulp

05/11/2024 20:49:13
 
Erwin H

Erwin H

07/10/2013 20:06:39
Quote Anchor link
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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
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)
 
Reshad F

Reshad F

07/10/2013 22:00:02
Quote Anchor link
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.
 
Wouter J

Wouter J

07/10/2013 22:34:31
Quote Anchor link
Folder systeem, dan denk ik meteen aan PHPCR!
 
Simon Simons

Simon Simons

07/10/2013 23:29:14
Quote Anchor link
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!
 
Erwin H

Erwin H

08/10/2013 08:43:48
Quote Anchor link
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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
lft    rgt    name
1      4      root
2      3      node1


Wil je dan een node toevoegen als kind van node1, dan krijg je dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
//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.
 
Simon Simons

Simon Simons

08/10/2013 19:39:04
Quote Anchor link
Hoi Erwin,

Bedankt voor je mooie uitleg.
Heel duidelijk!
Ik ben er nu mee bezig en je voorbeeld werkt uitstekend!
Bedankt!!!
Gewijzigd op 08/10/2013 19:40:16 door Simon Simons
 
Erwin H

Erwin H

08/10/2013 20:10:56
Quote Anchor link
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.
 
Simon Simons

Simon Simons

08/10/2013 21:15:38
Quote Anchor link
Vertel, ik snap je niet :P

Hoe verwijder je nu submappen? Reken je dan ook terug met lft en rgt of laat je dat voor wat het dan is?

Toevoeging op 08/10/2013 21:50:38:

Genoeg te leren...

http://falsinsoft.blogspot.nl/2013/01/tree-in-sql-database-nested-set-model.html
 
Erwin H

Erwin H

08/10/2013 23:00:32
Quote Anchor link
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.
 
Simon Simons

Simon Simons

15/10/2013 12:19:55
Quote Anchor link
Erwin,

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

Erwin H

15/10/2013 13:06:39
Quote Anchor link
Nee, want als je dan van een child van de een alle roots wil hebben, krijg je ook de andere root (en subroots). Wat je wel kan doen is een 'dummy' root maken, die weer de root is van je beide roots. Zo kan je twee bomen bouwen binnen dezelfde tabel, waarbij dus beide bomen een sub zijn van de dummy root.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.