Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: PHP/MySQL: Alanavigaatio

Sivun loppuun

OskariB [20.01.2010 23:52:53]

#

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>

benjam1n [21.01.2010 14:26:44]

#

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.

Metabolix [21.01.2010 14:54:51]

#

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ä.

OskariB [21.01.2010 19:58:47]

#

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

Metabolix [22.01.2010 19:30:00]

#

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?

OskariB [22.01.2010 22:40:11]

#

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.

Metabolix [22.01.2010 23:19:55]

#

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.

OskariB [23.01.2010 00:55:52]

#

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

Metabolix [23.01.2010 01:10:48]

#

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);

OskariB [23.01.2010 01:48:57]

#

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.

OskariB [23.01.2010 23:39:32]

#

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.

OskariB [30.01.2010 00:10:10]

#

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ä.

Metabolix [30.01.2010 00:23:29]

#

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.

OskariB [30.01.2010 11:36:33]

#

Kiitoksia, nyt navigaatio toimii haluamallani tavalla.

Itemsin olemassaolo piti vielä tarkistaa, ettei tule virheilmoituksia sivuilla, joilla ei ole alakategorioita.


Sivun alkuun

Vastaus

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

Tietoa sivustosta