Po pierwsze w Twojej tabeli pole `poziom` jest raczej zbędne, na pewno nie jest potrzebne do wygenerowania struktury drzewa, wynika ona z samego powiązania `id` i `id_kategorii_wyzszej`. Kwestia prostoty: zamiast `id_kategorii_wyzszej` użyj pola o nazwie `pid` (od `parent id`), które będzie indeksowane, np:
CREATE TABLE kategorie(
id INT UNSIGNED NOT NULL,
pid INT UNSIGNED NOT NULL,
nazwa VARCHAR(255),
PRIMARY KEY(id),
INDEX(pid)
);
--
-- przykładowe dane
--
INSERT INTO kategorie VALUES(1, 0, 'Kategoria 1');
INSERT INTO kategorie VALUES(2, 0, 'Kategoria 2');
INSERT INTO kategorie VALUES(3, 0, 'Kategoria 3');
INSERT INTO kategorie VALUES(4, 0, 'Kategoria 4');
INSERT INTO kategorie VALUES(5, 0, 'Kategoria 5');
INSERT INTO kategorie VALUES(6, 2, 'Kategoria 2.1');
INSERT INTO kategorie VALUES(7, 2, 'Kategoria 2.2');
INSERT INTO kategorie VALUES(8, 2, 'Kategoria 2.3');
INSERT INTO kategorie VALUES(9, 7, 'Kategoria 2.2.1');
INSERT INTO kategorie VALUES(10, 7, 'Kategoria 2.2.2');
INSERT INTO kategorie VALUES(11, 7, 'Kategoria 2.2.3');
INSERT INTO kategorie VALUES(12, 4, 'Kategoria 4.1');
Po drugie zawsze należy dążyć do ograniczenia ilości zapytań wysyłanych do bazy danych: w miarę wzrostu ich ilości komunikacja z serwerem baz danych staje się wąskim gardłem aplikacji. Strukturę drzewiastą można wygenerować za pomocą samego PHP (gwarantuję Ci, że będzie to działało kilka razy szybciej, wielokrotnie się o tym przekonałem) i tylko
JEDNEGO zapytania do bazy danych.
Aby to zrobić musimy zbudować w PHP tablicę, wykonując małą sztuczkę z polem `pid`: każdy kolejny rekord pobrany z bazy danych, wczytujemy do 'tablica[pid]', dzięki czemu zgromadzimy w jednym miejscu wszystkie elementy o danych pid i będziemy mogli je łatwo pobrać z tablicy. Taką możliwość daje nam niezwykła elastyczność tablic w PHP.
<?php
/*
* Wersja proceduralna (bardzo nielegancka)
* UWAGA: nie ma żadnego ograniczenia na ilość kategorii (głębokość drzewa)
*/
// Pobieramy dane z bazy danych:
$db = new mysqli('localhost','user','password','testy');
$ans = $db->query('SELECT * FROM kategorie');
/*
* Budujemy model danych, w tym wypadku tablicę o strukturze:
* $tablica[parent_id] = { lista potomków }
*/
while($row = $ans->fetch_row())
{
if(!$model[$row[1]])
{
$model[$row[1
]] = array(); }
}
// Mając dane możemy wygenerować widok:
<html>
<body>
';
// Elementy o pid==0 (przechowyne w $model[0]) są kategoriami najwyższego rzędu
function categoryTreeView(& $model, $pid=0) {
foreach($model[$pid] as $category)
{
echo '<div style="margin-left:25px">'.$category[2
];
// Sprawdzamy czy dana kategoria ma potomków, jeżeli tak - wywołujemy funkcję rekurencyjnie:
if(count($model[$category[0
]])) {
categoryTreeView($model, $category[0]);
}
} // ~foreach
}
categoryTreeView($model);
Jeżeli piszesz na klasach (obiektowo) to bardziej zaciekawi Cię ta wersja:
<?php
/*
* Prosta wersja obiektowa
*/
class CategoryModel {
private $model;
public function __construct(mysqli & $db) {
$ans = $db->query('SELECT * FROM kategorie');
while($row = $ans->fetch_row())
{
if(!$this->model[$row[1]])
{
$this->model[$row[1
]] = array(); }
}
public function hasChildren($parentId) {
return count($this->model[$parentId])>0; }
public function getChildren($parentId = 0) {
return $this->model[$parentId];
}
}
class CategoryTreeView {
private $model;
private $html='';
public function __construct(CategoryModel & $model) {
$this->model = $model;
$this->html();
}
private function html($pid=0) {
if($children = $this->model->getChildren($pid))
{
foreach($children as $child)
{
$this->html.= '<div style="margin-left:25px">'.$child[2];
if($this->model->hasChildren($child[0]))
{
$this->html($child[0]);
}
$this->html.= '</div>';
} ~foreach
} ~if
}
public function __toString() {
return $this->html;
}
}
echo new CategoryTreeView
( new CategoryModel(
new mysqli('localhost','user','password','testy')
)
);
W obu wypadkach wynik będzieidentyczny:
Kategoria 1
Kategoria 2
-->Kategoria 2.1
-->Kategoria 2.2
---->Kategoria 2.2.1
---->Kategoria 2.2.2
---->Kategoria 2.2.3
-->Kategoria 2.3
Kategoria 3
Kategoria 4
-->Kategoria 4.1
Kategoria 5