Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: Oksavalikot

Sivun loppuun

SysRq868 [09.04.2007 22:35:37]

#

Koetan nyt tehdä itselleni mahdottomuuksien rajoissa piilevää asiaa PHP-harjoituksieni nimissä: monitasoista oksavalikkoa (vrt. resurssienhallinta, eng. "tree menu"). Olen typistänyt sen tiedot sisältävän MySQL-kannan kolmeen kenttään (otsikot korostuksen vuoksi isolla, todellisuudessa pienellä), alla. Kaikki kentät ovat varchareja.

CID   ITEMNAME     PARENT
0     Makkarat
1     Bratwurst    0
2     Metwurst     0
3     Eläimet      0
4     Possu        3
5     Hevonen      3
6     Letut
7     Pinaatti     6
8     Normaalit    6

Yksinkertaisuudessaanhan (aika sana) mikäli rivillä ei ole "parent"-kentässä mitään, se on päätason elementti. Jos siinä taas on jotain, se on sen numeroisen elementin alielementti. Oudosti sanottu, mutta ehkä sen älyää. Tuosta pitäisi saada seuraavanlainen valikko aikaiseksi (siis järjestää ne aakkosjärjestykseen samalla - muutenkin rivit voivat olla ihan sekaisin):

Makkarat
  Bratwurst
  Eläimet
    Hevonen
    Possu
  Metwurst
Letut
  Normaalit
  Pinaatti

Tarkoitus olisi myös, että PHP:n avulla valikoita voi supistella ja laajennella miten vain sielu sietää - tosin vain yksi ylemmän tason elementti kerrallaan - valikkoa ei siis voisi avata täyteen loistoonsa kerrallaan (vrt. NetAnttila.comin harmaa sivuvalikko). Olen osannut tehdä vain ensimmäisen alatason toimintaan alla olevalla koodilla. Eikä se edes järjestä niitä aakkosiin.

<?php
function getTopParameters($ditch = false){
  $path = $_SERVER['REQUEST_URI'];
  $p = explode("?", $path);
  if($ditch == true){
    $p2 = explode("&openid", $p[1]);
    return $p2[0];
  } else {
    return $p[1];
  }
}

  //Pure Jenkki
  $phandle = mysql_query("SELECT * FROM tree WHERE parent = ''", $link);
  $phandle2 = mysql_query("SELECT COUNT(*) FROM tree WHERE parent = ''", $link); //Kiitos, Grez
  $pinfo2 = (mysql_fetch_assoc($phandle2));
  for($i=0;$i<$pinfo2["COUNT(*)"];$i++){
    $pinfo = (mysql_fetch_assoc($phandle));
    echo "<a href=\"?".getTopParameters(true)."&amp;openid=".$pinfo["cid"].
"\">".$pinfo["itemname"]."</a><br>";
    if($_GET["openid"] == $pinfo["cid"]){
      $cha = mysql_query("SELECT * FROM tree WHERE parent = '".$pinfo["cid"]."'", $link);
      $cha2 = mysql_query("SELECT COUNT(*) FROM tree WHERE parent = '".$pinfo["cid"]."'", $link); //Kiitos, Grez
      $cin2 = (mysql_fetch_assoc($cha2));
      for($a=0;$a<$cin2["COUNT(*)"];$a++){
        $cin = (mysql_fetch_assoc($cha));
        echo "&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"?".getTopParameters(true)."&amp;openid=".
$cin["cid"]."\">".$cin["itemname"]."</a><br>";
      }
    }
  }
?>

Mutta jos mitään niistä avatuista alatasoista klikkaa, koko homma sulkeutuu (koska openid ei ole enää sama). Miten voisi hyppelehtiä teoriassa vaikka kuinka pitkään seuratakseen parent-kenttiä pitääkseen koko polun auki? Toisenlaisia toteutustapoja? Mitään vinkkejä?

Grez [09.04.2007 22:41:05]

#

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

Erilaisia tree-traversal algoritmeja on vaikka kuinka

Merri [09.04.2007 22:51:55]

#

Cornix taisi olla joka kyseli irkissä tämän perään tässä taannoin, lopputulos:
http://vesa.piittinen.name/joku.php

Ja koodi:
http://vesa.piittinen.name/joku.php.txt

Tuo taulukon data näyttäisi olevan yks-yhteensopivaa tämän esimerkin kanssa.


Elementit voi järjestää aakkosjärjestykseen tietokantakutsussa ihan yksiulotteisella tasolla.

SysRq868 [10.04.2007 15:01:08]

#

Sain siitä väännettyä MySQL-version: http://sooda.dy.fi/paste/?0DO

Nyt kun vain saisi ne avattavaksi/suljettavaksi asti, niin kaikki olisi hyvin. Omat taidot ei riitä, varsinkaan kun tässä on niin hirveästi itselleni uusia funktioita (reset, current, next, key... jne) eikä ole omaa koodia...

Voisiko joku auttaa? Kiitollisna.

Merri [10.04.2007 20:24:19]

#

Olihan ne minullekin uusia käytettäviä tässä yhteydessä, mutta PHP.netistä kyllä saa aika hyvän kuvan siitä mistä on kunkin funktion osalta kyse. Eli tärkeää tässä olisi nyt se, että tosiaan itse katsot vaihe vaiheelta mitä tuo koodi kussakin vaiheessa tekee, selvittää itsellesi miksi se toimii. Kukaan muu kun ei voi tehdä sitä sinulle. Kun ymmärrät miksi se toimii, niin tiedät jo sitten aika pian että miten saat laajennettua sitä.

(Vinkki: saat sulkeutumisen ja avautumisen päätoiminnon toteutettua yhdellä ainokaisella tarkistuksella ja lisäarvolla.)

SysRq868 [10.04.2007 21:33:28]

#

Monen kirosanan jälkeen ymmärsin suunnilleen, miten koodi toimii. Mutta - usko tai älä - vieläkään ei valjennut, miten tuon avaus/sulkuhomman toteuttaisi...

Merri [10.04.2007 22:47:52]

#

Estät tulosta_lapset -funktiossa lasten tulostuksen jos kyseisen listaelementin lapset on merkitty suljetuksi. Ja sen saat tietää lisäämällä jonnekin kohtaan tiedon siitä, onko isännöivän elementin lapset suljettu vaiko ei (esim. true/false -arvo).

SysRq868 [10.04.2007 23:07:32]

#

Ei, ei, nyt ei vieläkään onnaa. Ehkä pitäisi mieluummin omistautua savenvalannan hienoon taiteeseen. Mutta aion kuitenkin saada tämän nyt valmiiksi.

Ajattelin laittaa $naviin neljänneksi booleanin näyttämään, josko lapset on suljettu vaiko eikö. Kaikki sujui niin kauan kunnes piti keksiä, miten ja missä se määritellään, onko juuri kyseisen isännän lapset suljettuja vaiko eikö ja aagh, menin solmuun.

Älysin, että paras paikka joka rivin true/falsen määrittelemiseen olisi tuo while, koska siinä joka rivi käydään läpi joka tapauksessa. Paras heittoni:

<?php
// ....

while( $rivi = current($navi) ) {  //loopataan koko $navi, $rivi sisältää nykyisen tietueen sisällön
	if($rivi[1] == '') {  // jos PARENT on tyhjä, eli se on päätason elementti
		$isannat[] = key($navi); // lisätään se isäntien listaan
	} else { // jos se onkin lapsi
		$navi[ $rivi[1] ][3][] = key($navi); //lapsi listataan arrayhyn navitietueen loppuun
	}
    if($_GET["openid"] == key($rivi)){
      $navi[ $rivi[1] ][4] = false;
    }
	next($navi);  //seuraavaan valikon kohtaan, loop alusta
}

// ....
?>

mutta sittenhän siitä hassu tuli. Trial-and-error ei nyt ihan toimi - olen tässä säätämässä vielä joulunakin. Eli en nyt siis millään keksi, miten. Miten? Kiitos kaunis.

Cornix [10.04.2007 23:37:38]

#

Tuossa ei nyt ainakaan missään vaiheessa aseteta niitä true-arvoja sille puulle, jonka pitäis olla avoinna.

SysRq868 [11.04.2007 07:37:22]

#

Asetan sen trueksi oletuksena arrayn kehittämisessä. Koko koodi: http://sooda.dy.fi/paste/?id=W5n&vrj=php

Merri [11.04.2007 16:49:29]

#

function tulosta_lapset($id, $lapset) {  //lasten kirjoitus - key $navissa, lapsiarray
    global $navi;  //tuodaan valikko mukaan
    echo '<li><a href="?openid='.$id.'">'.$navi[$id][0].'</a>';  //kirjoitetaan linkki
    if( count($lapset) && $navi[$id][4] ) {  //jos silläkin on lapsia = array on olemassa
        if($navi[ $lapset[$i] ][4]){
            echo '<ul>';  //sisennys
            for($i = 0, $maxi = count($lapset); $i < $maxi; $i++) {  //tulostetaan nekin
                tulosta_lapset($lapset[$i], $navi[ $lapset[$i] ][3]); //...kutsumalla itseään
            }  //loppuruljanssi alkaa
            echo '</ul>';
        }
    }
    echo '</li>';
}

Eli muutettu rivi on

if( count($lapset) && $navi[$id][4] ) {

nyt siis jos arvo on true, niin lapset näkyy, jos false, niin eivät näy.

SysRq868 [11.04.2007 17:09:10]

#

Kiitos. Vaan nyt meni oudoksi. Ei muuten tapahtunut mitään, mutta kun otin tuon if($navi[ $lapset[$i] ][4]){ sieltä pois, niin rupesi näkymään actionia. Tosin ei sellaista, kuin haluaisin.

Valikossa on yksi ylimääräinen pallura kun kaikki on kiinni, ja ylemmän päätason elementin saa auki alemmasta päätason elementistä (Makkarat-valikko aukeaa koko kokonaisuudessaan, kun painaa Letut-linkkiä).

Sitten muutin koodia niin, että alkujaan joka $navin kohdassa lukisi oletuksena false, ja se muutettaisiin while'ssä trueksi jos openid on sama kuin nykyinen rivi. Nyt oikea valikko aukeaa, kun klikkaa tiettyä päätason elementtiä. Mutta valikko vieläkin avautuu kokonaisuudessaan (joka alitaso pitäisi voida avata ja sulkea erikseen), päätason elementti sulkeutuu kun jotakin sen lapsista klikkaa, ja siellä kummittelee aina välillä se outo extrapallura.

Tämä on aivan liian vaikeaa... :(

Merri [11.04.2007 19:08:09]

#

Nyt ryhtiä tuohon ajatusmalliin hyvä mies! Lähtökohta on aina se, että osaat tehdä asian tai ainakin selvittää miten asia tehdään. Jos et tiedä, piirrä vaikka paperille logiikka jonka mukaan asioiden pitäisi toimia. Varmista pariin otteeseen että se tosiaan toimisi kuten on tarkoitus. Sitten ala verrata sitä nykyiseen koodiin.

(Eli joo, en ole nyt sillä tuulella että jaksan tehdä kaiken valmiiksi, ja toisaalta näitä hieman monimutkaisempia asioita on ihan hyvästä opetella ajattelemaan alusta loppuun itse, ei sitä muuten oikeasti opi ohjelmointia. Tässähän ei nyt ole kyse PHP-kielestä oikeastaan ollenkaan, vaan siitä että kykenee ajattelemaan asian mielessään ja muodostamaan sen pohjalta toimivaa koodia.)

Se alkuperäinen skriptini muuten värjäsi avoinna olevaan sivuun asti boldilla. Oletko miettinyt että sen voi adaptoida pienin muutoksin pitämään huolta avaamisista ja sulkeutumisista?


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta