PDA

Bekijk Volledige Versie : PHP recursive



ST247
16/04/08, 20:45
Hallo,
Ik ben nog volop php aan het leren en ik was op zoek naar een
flexibele oplossing om parents en children uit een tabel te ordenen.
Om het wat duidelijker te maken is hier de structuur van een tabel :
CREATE TABLE `klas` (
`klasID` tinyint(4) NOT NULL auto_increment,
`parentklas` tinyint(4) NOT NULL default '0',
`klas` varchar(10) collate latin1_general_ci NOT NULL,
PRIMARY KEY (`klasID`)
)
Waarbij de parent van een klas dus in parentklas wordt opgegeven. De
'hoofdklassen' hebben als parent 0.
Dit zou ik vb. ook kunnen gaan gebruiken om navigatie en subnavigatie
op te slaan. Ik ga er van uit dat we op voorhand niet weten hoeveel
niveaus diep we gaan.
Ik wou dus een stuk flexibele code schrijven om dit alles in volgorde
(telkens parent met zijn children) te plaatsen, elke groep children
in een geneste lijst.
Hiervoor heb ik momenteel de volgende oplossing :
/// start code
function walkthrough($arr) {
echo "<ul>";
foreach ($arr as $key => $val) {
echo "<li>" . $val;
$arr = "klas" . $key;
echo "</li>";
global ${$arr};
if (is_array($$arr)) {
walkthrough(${$arr});
}
}
echo "</ul>";
}
$qryKlas = "SELECT * FROM klas ORDER BY parentklas, klas";
$rsKlas = mysql_query($qryKlas, $con) or die (mysql_error());
$aantal = mysql_num_rows($rsKlas);
while ($rij = mysql_fetch_assoc($rsKlas)) {
$naam = "klas" . $rij["parentklas"];
${$naam}[$rij["klasID"]] = $rij["klas"];
}
$arr = "klas0"; //beginarray

walkthrough(${$arr});

Waar ik dus een associatieve array aanmaak per parentklas.
Ik vroeg me af of er geen oplossing is die het aanmaken van zo'n
array overbodig maakt en waar het dus mogelijk is gewoon telkens je
recordset te gaan doorlopen.
Ik dacht ook dat het globaal maken van een variabele niet echt aan te
raden is, maar ik zag hier anders niet direct een oplossing.
Alle suggesties zijn dus welkom.
Bedankt alvast ;)

Branko Collin
16/04/08, 23:35
On Wed, 16 Apr 2008 20:41:45 +0200, "ST247" <ST247@invalid.com> wrote:

>Waar ik dus een associatieve array aanmaak per parentklas.
>Ik vroeg me af of er geen oplossing is die het aanmaken van zo'n
>array overbodig maakt en waar het dus mogelijk is gewoon telkens je
>recordset te gaan doorlopen.

Hebben we het over miljoenen records of over enkele tientallen? Ik
vermoed dat in het laatste geval de associatieve array sneller zal
zijn. (Recursief je database doorlopen betekent een heleboel
SQL-queries.)

In het laatste geval zou je erover kunnen denken om een aparte tabel
aan te leggen waarin je de te gebruiken volgorde van de records
vastlegt.

Ik zie het probleem eerlijk gezegd niet. Als je een heel zware
applicatie hebt, zul je toch allerlei bijzondere dingen moeten doen om
het werkend moeten krijgen. Ik vermoed dat je een lichte applicatie
hebt, en dan zou ik zoveel mogelijk in PHP en zo weinig mogelijk in
SQL doen.


--
branko collin
"I'm a little man, and I am also evil, also into cats,
.... also into cats" - Fall Out Boy, This Ain't a Scene,
It's an Arms Race

ST247
16/04/08, 23:45
> >Waar ik dus een associatieve array aanmaak per parentklas.
> >Ik vroeg me af of er geen oplossing is die het aanmaken van zo'n
> >array overbodig maakt en waar het dus mogelijk is gewoon telkens
je
> >recordset te gaan doorlopen.
>
> Hebben we het over miljoenen records of over enkele tientallen? Ik
> vermoed dat in het laatste geval de associatieve array sneller zal
> zijn. (Recursief je database doorlopen betekent een heleboel
> SQL-queries.)
Maximum enkele tientallen


> In het laatste geval zou je erover kunnen denken om een aparte
tabel
> aan te leggen waarin je de te gebruiken volgorde van de records
> vastlegt.
Daar ben ik zo niet voor te vinden in dit geval.
> Ik zie het probleem eerlijk gezegd niet. Als je een heel zware
> applicatie hebt, zul je toch allerlei bijzondere dingen moeten doen
om
> het werkend moeten krijgen. Ik vermoed dat je een lichte applicatie
> hebt, en dan zou ik zoveel mogelijk in PHP en zo weinig mogelijk in
> SQL doen.
Ik wil het inderdaad ook oplossen in PHP zelf, 1 query die alles uit
de tabel haalt en dan PHP die alles in volgorde gaat plaatsen.
Ik dacht dat mijn oplossing niet de netste en meest optimale
oplossing was. Ik vroeg me dus af of er geen manier was waar je die
array's niet moet aanmaken en waar je hetzelfde resultaat kan
verkrijgen door gewoon enkele malen je recordset te doorlopen.
--
Composed with Newz Crawler 1.9 http://www.newzcrawler.com/

Rik Wasmus
17/04/08, 03:45
On Wed, 16 Apr 2008 20:41:45 +0200, ST247 <ST247@invalid.com> wrote:

> Hallo,
> Ik ben nog volop php aan het leren en ik was op zoek naar een
> flexibele oplossing om parents en children uit een tabel te ordenen.
> Om het wat duidelijker te maken is hier de structuur van een tabel :
> CREATE TABLE `klas` (
> `klasID` tinyint(4) NOT NULL auto_increment,
> `parentklas` tinyint(4) NOT NULL default '0',

De standaard voor 'root' records is meestal dat de 'parent' daar juist op
NULL wordt gezet, omdat die zeker nooit kan bestaan als primary key (0
theoretisch wel, als er mensen met de database hebben lopen klooien...).

> `klas` varchar(10) collate latin1_general_ci NOT NULL,
> PRIMARY KEY (`klasID`)
> )
> Waarbij de parent van een klas dus in parentklas wordt opgegeven. De
> 'hoofdklassen' hebben als parent 0.
> Dit zou ik vb. ook kunnen gaan gebruiken om navigatie en subnavigatie
> op te slaan. Ik ga er van uit dat we op voorhand niet weten hoeveel
> niveaus diep we gaan.
> Ik wou dus een stuk flexibele code schrijven om dit alles in volgorde
> (telkens parent met zijn children) te plaatsen, elke groep children
> in een geneste lijst.
> Hiervoor heb ik momenteel de volgende oplossing :
> /// start code
> function walkthrough($arr) {
> echo "<ul>";
> foreach ($arr as $key => $val) {
> echo "<li>" . $val;
> $arr = "klas" . $key;
> echo "</li>";
> global ${$arr};
> if (is_array($$arr)) {
> walkthrough(${$arr});
> }
> }
> echo "</ul>";
> }
> $qryKlas = "SELECT * FROM klas ORDER BY parentklas, klas";
> $rsKlas = mysql_query($qryKlas, $con) or die (mysql_error());
> $aantal = mysql_num_rows($rsKlas);
> while ($rij = mysql_fetch_assoc($rsKlas)) {
> $naam = "klas" . $rij["parentklas"];
> ${$naam}[$rij["klasID"]] = $rij["klas"];
> }
> $arr = "klas0"; //beginarray
> walkthrough(${$arr});
>
> Waar ik dus een associatieve array aanmaak per parentklas.
> Ik vroeg me af of er geen oplossing is die het aanmaken van zo'n
> array overbodig maakt en waar het dus mogelijk is gewoon telkens je
> recordset te gaan doorlopen.
> Ik dacht ook dat het globaal maken van een variabele niet echt aan te
> raden is, maar ik zag hier anders niet direct een oplossing.
> Alle suggesties zijn dus welkom.
> Bedankt alvast ;)

Voor een echte SQL oplossing, zie:
<http://dev.mysql.com/tech-resources/articles/hierarchical-data.html>

Oplossing zonder global (niet getest, maar je ziet het idee):

$qryKlas = "SELECT * FROM klas ORDER BY parentklas, klas";
$rsKlas = mysql_query($qryKlas, $con) or die (mysql_error());
$helper = array(0 => array());
$results = array();
while($rij = mysql_fetch_assoc($rsKlas)){
//even nodig:
if($rij['klasID'] == $rij['parentKlas']) trigger_error('Corrupte tree
denk ik...',E_USER_FATAL);
//zet eigen entry in de array
$helper[$rij['parentKlas']][$rij['klasID']] = $rij;
//maak entry voor descendants
$helper[$rij['parentKlas']][$rij['klasID']]['kindjes'] = array();
//maak referentie in de $helper array
$helper[$rij['id']] =&
$helper[$rij['parentKlas']][$rij['klasID']]['kindjes']
}
function walkthrough($var){
if(!is_array($var)) return $var;
$return = '<ul>';
foreach($var as $key => $value){
$return .= .'<li>'.$key.':'.walktrough($value).'</li>';
}
foreach($var as $val) $return .= walkthrough($val);
$return .= '</ul>';
return $return;
}
//enkel $helper[0] is van belang als je de hele tree wil hebben
echo walkthrough($helper[0]);
--
Rik Wasmus

ST247
17/04/08, 11:15
Rik Wasmus <luiheidsgoeroe@hotmail.com> wrote in message
<op.t9qep9yf5bnjuv@metallium.lan>

> On Wed, 16 Apr 2008 20:41:45 +0200, ST247 <ST247@invalid.com>
wrote:
>
> > CREATE TABLE `klas` (
> > `klasID` tinyint(4) NOT NULL auto_increment,
> > `parentklas` tinyint(4) NOT NULL default '0',
>
> De standaard voor 'root' records is meestal dat de 'parent' daar
juist op
> NULL wordt gezet, omdat die zeker nooit kan bestaan als primary key
(0
> theoretisch wel, als er mensen met de database hebben lopen klooien.
...).
Dat wist ik niet, ik zal er zeker rekening mee houden.
> Oplossing zonder global (niet getest, maar je ziet het idee):
>
> $qryKlas = "SELECT * FROM klas ORDER BY parentklas, klas";
> $rsKlas = mysql_query($qryKlas, $con) or die (mysql_error());
> $helper = array(0 => array());
> $results = array();
> while($rij = mysql_fetch_assoc($rsKlas)){
> //even nodig:
> if($rij['klasID'] == $rij['parentKlas']) trigger_error('Corrupte
tree
> denk ik...',E_USER_FATAL);
> //zet eigen entry in de array
> $helper[$rij['parentKlas']][$rij['klasID']] = $rij;
> //maak entry voor descendants
> $helper[$rij['parentKlas']][$rij['klasID']]['kindjes'] = array();
> //maak referentie in de $helper array
> $helper[$rij['id']] =&
> $helper[$rij['parentKlas']][$rij['klasID']]['kindjes']
> }
> function walkthrough($var){
> if(!is_array($var)) return $var;
> $return = '<ul>';
> foreach($var as $key => $value){
> $return .= .'<li>'.$key.':'.walktrough($value).'</li>';
> }
> foreach($var as $val) $return .= walkthrough($val);
> $return .= '</ul>';
> return $return;
> }
> //enkel $helper[0] is van belang als je de hele tree wil hebben
> echo walkthrough($helper[0]);
Ik krijg nu alle klassen te zien met parentklas 0. 1 klas heeft
kindjes, maar die krijg ik daar niet te zien (bij kindjes wordt dit
ook niet opgesomd). De laatste klas geeft nog eens alle klassen met
parentklas 0. De kindjes krijg ik dus nergens te zien. Enig idee
waar dit misloopt ?
Een print_r van de $helper[1] (de enige klas met children) geeft me :
Array ( [5] => Array ( [klasID] => 5 [parentklas] => 1 [klas] =>
5MULa [graad] => 3 [jaar] => 1 [kindjes] => Array ( ) ) [6] => Array
( [klasID] => 6 [parentklas] => 1 [klas] => 5MULb [graad] => 3 [jaar]
=> 1 [kindjes] => Array ( ) ) [7] => Array ( [klasID] => 7
[parentklas] => 1 [klas] => 5MULc [graad] => 3 [jaar] => 1 [kindjes]
=> Array ( ) ) )
Waar klasID 5 eigenlijk ook nog 2 kindjes heeft (klasID 9 en 10) en
klasID 9 ook nog eens een kind heeft.
Wat ik eigenlijk als uitvoer zou willen krijgen is iets als :
hoofdklas info (klas)
kindjesklas info (klas)
kindjesklas info (klas)
hoofdklas info (klas)
.....
Als je dit nu aanpast zodat de hoofdklassen als parentklas NULL
hebben, wat moet er dan zoal veranderen in de code ?
Bedankt alvast.
--
Composed with Newz Crawler 1.8 http://www.newzcrawler.com/