[ ducker @ 24.05.2004. 12:40 ] @
Pozdrav svima!
Imam problem, ne mogu da nadjem pravo (organizaciono) resenje za kategorije. Pokusacu da vam obrazlozim problem sto je moguce detaljnije.
Imam MySQL tabelu:

CREATE TABLE `cats` (
`id` int(10) unsigned NOT NULL auto_increment,
`parent` int(10) unsigned NOT NULL default '0',
`name` varchar(32) NOT NULL default '',
...
PRIMARY KEY (`id`)
) ENGINE=MyISAM;

Ta tabela drzi informacije o kategorijama. Kategorije mogu da imaju ista imena ako se nalaze na razlicitom hijerarhijskom nivou. Zato imam id i parent, a name je samo opis. Znaci, opisi mogu biti isti, ali ne na istom nivou. U adminu proveravam da li postoji red u bazi sa istim parent-om i name-om, ako ima, ne moze da se unese novi. Primer: znaci, putanja do kategorije moze da bude i 'cat24/cat13/cat24/cat45a', a da name='cat24' imaju dva reda u bazi, s tim da ce jednom parent biti 0 (jer je toplevel), a drugom ce parent biti id polja ciji je name 'cat13'.

Jos je vazno da napomenem da ostala polja iz tabele (ona '...') sadrze informacije koje child-ovi nasledjuju od parent-a.


E sad, problem.
Kad hocu da izvucem red iz baze sa tekucom (pod)kategorijom x, a imam putanju npr. cat1/cat2/catx, to radim ovako:

Code:

$x = 'cat1/cat2/catx';
$x1 = explode('/', $x);
$sql_str = "SELECT * FROM cats WHERE name IN ('" . implode ("', '", array_unique ($x1)) . "')";
$sql_return = mysql_query($sql_str);
while ( $out = mysql_fetch_assoc($sql_return) ) $niz[] = $out;


Posle ovoga poredjam $niz po putanji (odnosno po nizu $x1), pa vadim tekuci ( $tekuci = $niz[count($x1)-1] ) koji je ujedno i poslednji, a onda od predzadnjeg trcim redom ka toplevel-u (for ciklusom) i radim update parent-ovim podacima ako tekuci nema naveden taj podatak (to je ono '...' u SQL strukturi).

To radi kako treba (sto kazu, 'drzi vodu'), mada pretpostavljam da i to moze elegantnije da se resi.

Jedino sto mi u ovoj organizaciji nije jasno, to je kako da dobijem isti rezultat na kraju (tj. niz sa podacima o tekucem) ako krecem od:
$x = x; (id kategorije)
a ne sa putanjom ($x = 'c1/c2/...';)

Znaci, pitanje je: kako da nadjem odredjenu (pod)kategoriju (po mogucstvu, sa svim podesenjima koje moze da nasledi od parent-a) ako imam samo njen id? Koliko ja znam, MySQL nema rekurzivne funkcije, ali ne znam kako da ih simuliram u PHPu, a da ne radim na pocetku "SELECT * FROM cats". To mi ipak deluje malo neoptimizovano...

Ima li neko ideju kako ovo resiti, ili bar savet? Nadam se da necu morati zbog ovog problema da radim restruktuiranje baze. A ipak bih zeleo taj deo maksimalno da optimizujem jer se izvrsava u prepend-u svake stranice...


Unapred hvala.
[ noviKorisnik @ 25.05.2004. 14:04 ] @
Hm... našao sam ovo. Izgleda mi da ima veze sotim što želiš...
Code:
function site_fetch_cat_by_id($id) {
    $sql_str = "SELECT * FROM cats";
    $sql_return = mysql_query($sql_str);
    while ( $outcome = mysql_fetch_assoc($sql_return) ) {
        if ( $outcome['id'] == $id ) {
            $cats[] = $outcome;
            $parent = $outcome['parent'];
        } else $db_all[$outcome['id']] = $outcome;
    }
    if ( !isset($cats) ) {
        die('nema...');
    }
    while ( $parent != 0 ) {
        if ( !isset($db_all[$parent]) ) {
            die('nema...');
        }
        $cats[] = $db_all[$parent];
        $parent = $db_all[$parent]['parent'];
    }
    $cats= array_reverse($cats); // evo svih
    $cats_cnt = count($cats);
    $cat = $cats[$cats_cnt-1]; // evo zadnjeg
    // ovde ide to cudo za update-ovanje od parent-a
    foreach ( $cats as $c ) {
        $cats_names[] = $c['name']; // evo path niza
    }
    $path = implode('/', $cats_names); // evo path stringa
    exit;
}

Jeste da ima samo jedan q, ali mi ne deluje baš optimalno... Možda dobiješ neku ideju. Da nije kojim slučajem ograničena dubina potkategorisanja (recimo na 3 do 4 nivoa)?
[ ducker @ 26.05.2004. 13:48 ] @
Hvala ti, noviKorisnice, to je bas ono o cemu sam i ja razmisljao...

Samo, kao sto si i ti lepo rekao, nekako mi to deluje malo neoptimizovano... Ako u tabeli imam 200+ redova, onda je to jako glupo ako mi trebaju samo dva reda...

Kontam da ni ne moze nikako drugacije.

Na tvoje pitanje: iskreno ne bih nikoga ogranicavao na broj podkategorija, da bih povecao funkcionalnost skripte.

U svakom slucaju, hvala ti, za sada cu koristiti tvoje resenje, dok ne naletim na nesto 'optimizovanije'.

Cheers!
[ -zombie- @ 27.05.2004. 06:45 ] @
možeš da optimizuješ tako što bi za svaku (pod)kategoriju pamtio i na kom je nivou.

ako recimo znaš da je kategorija na 4 nivou, možeš jednim upitom (sa JOINovanjem 4 tabele) da izvučeš sve roditelje te kategorije..
[ ducker @ 01.06.2004. 11:02 ] @
Tomice, ako postavim polje level u bazu, zar nije preveliki problem pomeriti kategoriju na drugo mesto?

Do sada sam morao samo da menjam polje parent, a ovako bih morao da menjam level svih child-ova (i grandchild-ova, itd...) kategorije koju menjam.

Zar ne?
[ -zombie- @ 01.06.2004. 14:12 ] @
naravno, nisam ja tvrdio da je ovo idealno rešenje po svim aspektima..

u stvari, ni ne postoje univerzalno idealna rešenja.. jedno je bolje sa jednog aspekta, drugo sa drugog.. ko ne plati na mostu, platiće.. ne, nije to to.. ;)

pazi, na tebi je da proceniš kako će se ta aplikacija koristiti. meni se čini da akcija "prebaci jednu kategoriju u drugu" nije toliko česta, i da je radi samo admin, i to samo ponekad..

sa druge strane, traženje svih roditelja jedne kategorije je verovatno nešto što će trebati svim posetiocima sajta, i to verovatno često..

tako da..