Tervehdys,
kaipaisin neuvoa, kuinka toteuttaa PHP/MySQL -yhdistelmällä alanavigaatio, joka käsittää kaksi tasoa. Lähinnä oikeanlaisen kantakyselyn taikominen tuottaa ongelmia. Yhden tason alanavin sain rakennettua seuraavilla kannan sarakkeilla:
id | url | name | priority | type | category ------------------------------------------------------------- 2 | paasivu-2 | Pääsivu 2 | 2 | article | null 5 | sivu-2 | Sivu 2 | 2 | subarticle | 2
Ja tietysti minulla on jokaisella yksittäisellä sivulla tiedossa, mikä on kyseisen sivun id ja category.
Päänavigaation rakenne:
<ul> <li><a href="#">Pääsivu 1</a></li> <li class="open"><a href="#">Pääsivu 2</a></li> <li><a href="#">Pääsivu 3</a> </ul>
Alanavigaation rakenne:
<ul> <li><a href="#">Sivu 1</a></li> <li><a href="#">Sivu 2</a></li> <li class="open"><a href="#">Sivu 3</a> <ul> <li class="open"><a href="#">Alasivu 1</a></li> <li><a href="#">Alasivu 2</a></li> </ul> </li> <li><a href="#">Sivu 4</a></li> </ul>
Itselläni on kaksi taulua, pääsivuille oma ja alasivuille oma.
Alasivujen taulussa viitataan mihin pääsivuun linkki kuuluu.
Jotenki tällain:
<ul> <li><a href="#">Sivu 1</a></li> <li><a href="#">Sivu 2</a></li> <li class="open"><a href="#">Sivu 3</a> <?php if($sql = mysql_query("SELECT id, paasivu, linkki FROM alasivut WHERE paasivu='sivu3'")) { echo "<ul class=\"alalinkit\">"; while($tiedot = mysql_fetch_array($sql)) { echo "<li><a href=\"#\">$tiedot[linkki]</a></li>"; } echo "</ul>"; } ?> </li> <li><a href="#">Sivu 4</a></li> </ul>
En tiedä onko se oikea tapa menetellä, mutta toimii minulla.
Itse loisin puurakenteen PHP:llä. Nykyinen taulusi sopii aivan hyvin.
<?php function load_navigation() { $tree = array(); // SELECT * FROM navigation ORDER BY miten_haluat; $all = array( 2 => array('id' => 2, 'category' => null), 3 => array('id' => 3, 'category' => null), 5 => array('id' => 5, 'category' => 2), 6 => array('id' => 6, 'category' => 3), 7 => array('id' => 7, 'category' => 3), 8 => array('id' => 8, 'category' => 6), ); // Kikkaillaan viittauksilla, ei kopioida dataa. foreach ($all as $id => &$item) { if (empty($item['category'])) { $tree[$id] = &$item; } else { $all[$item['category']]['items'][$id] = &$item; } } return $tree; } print_r(load_navigation());
Nyt tiedot muodostavat puurakenteen. Tulostamiseen rekursio on hyvä menetelmä.
Valitettavasti benjam1nin koodi ei sovellu tähän käyttötarkoitukseen, enkä saanut Metabolixin koodia toimimaan oikein.
Täällä on hyvä esimerkki siitä, mitä tarkoitan. Murupolku kyseisessä tapauksessa: www.paroc.fi > Rakennuseristeet > Tuotteet > Tuoteryhmät
Mikä koodissani aiheutti ongelmia? Katsoitko, mitä se nykymuodossaan tulostaa? Saitko haettua tiedot tietokannasta ja tulostettua ne samalla tavalla? Vai etkö vain osannut tulostaa niitä print_r:n sijaan haluamassasi HTML-muodossa?
Pienen säätämisen jälkeen sain print_r:llä tulostettu tietokannasta haetun datan seuraavalla tavalla:
Array ( [0] => Array ( [id] => 1 [category] => null [page] => etusivu [title] => Etusivu ) [1] => Array ( [id] => 8 [category] => null [page] => lorem-ipsum [title] => Lorem ipsum ) [2] => Array ( [id] => 5 [category] => 8 [page] => alasivu [title] => Alasivu ) [3] => Array ( [id] => 2 [category] => 5 [page] => alasivun-alasivu [title] => Alasivun alasivu ) ) )
Tällä hetkellä painiskelen halutun HTML-muodon tulostamisen kanssa.
Et ilmeisesti tajunnut koodistani, että taulukko pitäisi indeksoida id:n mukaan. Joudut siis käymään kannasta saamasi rivit läpi ja kokoamaan ne uuteen taulukkoon.
Jaa-a, pitänee Googletella ahkerasti. Tämmöisellä tuli edellinen viritelmä tehtyä:
<?php $result = mysql_query($sql); $tree = array(); $all=array(); while($row = mysql_fetch_array($result, MYSQL_ASSOC)) { array_push($all,$row); } return $all; // Kikkaillaan viittauksilla, ei kopioida dataa. foreach ($all as $id => &$item) { if (empty($item['category'])) { $tree[$id] = &$item; } else { $all[$item['category']]['items'][$id] = &$item; } } return $tree
Ei tässä nyt ole mistään Googlesta kyse vaan ohjelmoinnin perusasioista. Mietipä hetki: mitä hyötyä on jälkimmäisestä silmukasta, kun poistut funktiosta returnilla jo ennen sitä? Ota ensimmäinen return pois ja korvaa array_push sijoitusrivillä, jossa käytät indeksinä rivin id:tä.
Jatkoa:
<?php $_GET['page'] = 8; // Testausta. // Haetaan tiedot. $navi = load_navigation(); $page = 1; if (!empty($_GET['page'])) { $page = $_GET['page']; } // Etsitään puusta oikea haara. Ehkä olisi fiksumpaa hoitaa // tämä jo load-funktiossa yksinkertaisella silmukalla. function path($items, $page) { foreach ($items as $item) { if ($item['id'] == $page) return array($page); if (empty($item['items'])) continue; $path = path($item['items'], $page); if ($path) { array_unshift($path, $item['id']); return $path; } } return null; } $path = path($navi, $page); // Tarkistetaan, että löytyi; muuten laitetaan oletussivu. if (empty($path)) { $path = array($page = 1); } // Tulostetaan rekursiivisesti valikko. function menu($items, $path) { if (empty($items) || empty($path)) return; $open = array_shift($path); echo "<ul>\n"; foreach ($items as $item) { echo "<li>", $item['id']; if ($item['id'] == $open && !empty($item['items'])) { menu($item['items'], $path); } echo "</li>\n"; } echo "</ul>\n"; } menu($navi, $path);
Tässä tapauksessa en yrittänyt Googlata, vaan suuntasin suoraan PHP.nettiin. Pitänee vielä puolustautua, että ensimmäinen returni on jäänyt tuohon väliin vahingossa. Nyt saan print_r:llä tulostettu mitä esimerkissäsi tarkoitit. Syventynen HTML:n tulostamiseen myöhemmin tänään.
Edit. Kiitoksia vaivannäöstä, olit jo kerennyt kokoamaan jatkoa.
Navigaatio "toimii" tällä hetkellä päinvastaisessa järjestyksessä.
<?php $all = array( 1 => array('id' => 1, 'category' => null, 'title' => 'Etusiuv'), 8 => array('id' => 8, 'category' => null, 'title' => 'Lorem ipsum'), 5 => array('id' => 5, 'category' => 8, 'title' => 'Alasivu'), 2 => array('id' => 2, 'category' => 5, 'title' => 'Alasivun alasivu'), );
Ollessani sivulla "Lorem ipsum", navigaatiossa näkyy vain sisarelementit, esimerkissäni "Etusivu". "Alasivun alasivulla" taas näkyy kaikki parentit ja parenttien sisarelementit.
En vain millään saa alanavigaatiota toimimaan täysin oikein, vaikka hyvin lähelle olen päässyt.
Päänavigaatio ——————————————————————————— Etusivu Lorem ipsum ——————————————————————————— Alanavigaatio ———————————————————— Etusivu (Ei pitäisi näkyä) Lorem Ipsum (Ei pitäisi näkyä) Alasivu 1 Alasivu 2 Alasivun Alasivu Alasivu 3 Alasivu 4 ————————————————————
Kun olen sivulla "Alasivun alasivu", näkyy alanavigaatiossa kyseisen sivun parentit ja parenttien sisaret. Muuten näkymä on oikea, mutta en haluaisi alanavigaation päänavigaation elementtejä.
Kun taas olen sivulla Alasivu 2, näkyy alanavigaatiossa jälleen parentit ja parenttien sisaret, ei ollenkaan lapsielementtejä.
Pääsivut saa pois yksinkertaisesti aloittamalla tulostuksen vasta seuraavalta tasolta. Samalla voi tyylikkäästi jättää valikon kokonaan pois, jos mitään tulostettavaa ei ole. Kokeile jotain tällaista:
<?php if (!empty($path)) { $open = array_shift($path); if (!empty($navi[$open]["items"])) { echo "<h2>Alanavi</h2>\n"; menu($navi[$open]["items"], $path); } }
Toinen ongelma taas ratkennee, kun otat menu-funktion ensimmäisestä if-lauseesta empty($path)-tarkistuksen pois. Sattui varmaan ajatusvirhe, kun suoraan laatikkoon kirjoittelin.
Kiitoksia, nyt navigaatio toimii haluamallani tavalla.
Itemsin olemassaolo piti vielä tarkistaa, ettei tule virheilmoituksia sivuilla, joilla ei ole alakategorioita.
Aihe on jo aika vanha, joten et voi enää vastata siihen.