Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php][mysql] Wyświetlanie drzewka kategorii
Forum PHP.pl > Forum > PHP
lectric
Witam,

Otoz mam tabelke sql:

id | parent_id | name

Kategoria ktora posiada parent_id = 0 to kategoria glowna.

Napisalem dwie funkcje:

  1. <?php
  2. function drzewo($id){
  3.  
  4. global $tab,$glebokosc,$drzewko;
  5. $zapytanie="SELECT * FROM category WHERE parent_id='$id' ORDER BY name ASC";
  6. $wynik=mysql_query($zapytanie);
  7.  
  8. while($wiersz=mysql_fetch_assoc($wynik)) {
  9. $drzewko[]=array('id'=>$wiersz[id],'nazwa'=>$wiersz[name],'glebokosc'=>(int)$glebokosc);
  10.  
  11. $zapytanie2="SELECT * FROM category WHERE parent_id=".$wiersz[id]." ORDER BY name ASC";
  12. $wynik2=mysql_query($zapytanie2);
  13. if(mysql_num_rows($wynik2)>0) {
  14. $glebokosc++;
  15. drzewo($wiersz[id]);
  16. $glebokosc--;
  17. }
  18. }
  19. }
  20.  
  21. function rysuj($ilosc,$nazwa,$id) {
  22.  
  23. if($ilosc == 0 ) {
  24. echo "<option value='$id' style='color:#0086df;'>".$nazwa."</option><br>";
  25.  
  26. }
  27. else {
  28. $licznik = 0;
  29. while($licznik <= $ilosc-1) 
  30. {
  31. $kreska= $kreska." &nbsp;&nbsp;&nbsp;|";
  32. $licznik++;
  33. }
  34. echo "<option value='$id'>".$kreska."__".$nazwa."</option>";
  35. }
  36. }
  37. ?>


wywołanie:

  1. <?php
  2. drzewo(0);
  3. foreach ($drzewko as $tab) 
  4. echo rysuj_zaznaczone($tab[glebokosc],$tab[nazwa],$tab[id],$kat_glowna);
  5. ?>



Gdy testowalem to na kilkunastu kategoriach wszystko bylo ok ale gdy docelowo uzylem okolo 10 tys. kategorii pojawil sie problem...
Testujac to na localhost po chwili wszystko zaczelo sie wieszac.
Prosze Was o pomoc.
qqrq
No nic dziwnego, że się zapchało - 10000 to ździebko dużo... smile.gif

Inna sprawa, że popatrz sobie ile to zapytań będzie przy takiej ilości kategorii. Najlepiej wszystkie kategorie pobierz od razu, jednym zapytaniem, a potem na tym co otrzymasz manipuluj po swojemu. Posortuj od razu (w zapytaniu) po parent_id - tak chyba będzie łatwiej to potem ogarnąć...
phpion
Problem leży zapewne w tym, że dla każdej kategorii sprawdzasz czy posiada podkategorie za pomocą zapytania SQL wykonywanego w pętli. Nie dziw się, że przy tak dużej liczbie pętli skrypt pada. Możesz to zrobić bez problemu na 1 zapytaniu!
  1. SELECT * FROM kategorie

Za pomocą tego zapytania budujesz sobie drzewko postaci:
  1. <?php
  2. $cat[0] = array(
  3. 1 => 'Kategoria1',
  4. 2 => 'Kategoria2'
  5. );
  6. $cat[1] = array(
  7. 3 => 'Kategoria11',
  8. 4 => 'Kategoria12'
  9. );
  10. $cat[4] = array(
  11. 5 => 'Kategoria121'
  12. );
  13. ?>

czyli index tablicy $cat to kategoria nadrzędna. Każdy element $cat jest również tablicą zawierającą podkategorie. Wystarczy teraz zwykłą pętlą przelatywać tablicę $cat w poszukiwaniu kategorii i podkategorii. Równocześnie, żeby zaoszczędzić czas, możesz po zbudowaniu odpowedniej gałęzi usuwać z tablicy użyte dane aby przy następnym przebiegu pętli nie sprawdzać tych, które zostały wcześniej użyte.
athabus
Możesz też zrobić coś innego... Zdaje się że gdzieś jest nawet artykuł o tym na wortalu. Id może mieć postać np. liczby 10 cyfrowej gdzie pierwsze 2 cyfry to id kategorii glownej, dwie kolejne to id podkategorii itd.

np.

1000000000 - kategoria glowna
1001000000 - podkakategoria
1002000000 - inna podkategoria
1002010000 - podakategoria poprzedniej podkategorii,
2000000000 - inna kategoria główna itd

W czymś takim sortowanie i wybieranie zagnieżdżonych pozycji jest znacznie łatwiejsze. Z drugiej strony struktura jest trochę mniej skalowalna, ale jeśli masz konkretny przypadek, to zapewne sam określisz wady i zalety takiego rozwiązania.
Ludvik
phpion.com: Pobranie wszystkich elementów z tej tablicy (10 tys. rekordów) skutecznie zawali pamięć... W ten sposób wszystko można zrobić na jednym zapytaniu, tylko trzeba się potem namęczyć, żeby zapisać wszystkie warunki w postaci kodu (niekoniecznie efektywnego).

Można zastosować nested sets, ale wstawianie i przenoszenie elementów wymaga aktualizacji sporej części rekordów (mimo tego, że nie są to skomplikowane operacje, zwykle 2 zapytania starczają). Pobranie wszystkich elementów podrzędnych jest bardzo proste i wymaga tylko jednego zapytania... Ale tak jak mówiłem, utrzymanie nested sets na takiej dużej bazie nie musi być przyjemne (nie testowałem osobiście...). Na Twoim miejscu przestudiowałbym dokładniej temat drzewek (sam się nad tym męczę)...
phpion
Cytat(Ludvik @ 5.09.2007, 14:55:30 ) *
phpion.com: Pobranie wszystkich elementów z tej tablicy (10 tys. rekordów) skutecznie zawali pamięć...

Racja, ale kto normalny robi tyle kategorii biggrin.gif hehe, poza tym przecież dane można cache'ować co rozwiąże problem. Wystarczy to zrobić z głową. W moim przykładzie nie jest problemem pobranie ścieżki od aktualnej kategorii do korzenia, nie ma problemu z pobraniem samych id kategorii potomnych itd itd. Wszystko odbywa się już na tablicach.
lectric
Nie moge używać metody zagnieżdżenia kategorii , musze pozostac przy pierwotnej (rodzic, dziecko)
Ludvik
Przy pobieraniu n poziomów możesz pobrać wszystkie dane za pomocą n zapytań, jeżeli dobrze myślę... Pomyśl coś w tym kierunku (pisane z palca, nie testowane, nie gwarantuję poprawnego działania tongue.gif ).

  1. <?php
  2. function drzewo($id, $glebokosc){
  3. $zapytanie = "SELECT * FROM category WHERE parent_id=$id ORDER BY name ASC";
  4. $wynik = mysql_query($zapytanie);
  5.  
  6. $rodzice = array();
  7.  
  8. while ($wiersz = mysql_fetch_array($wynik)) {
  9. $rodzice[] = $wiersz['id'];
  10. $drzewko[] = array('id' => $wiersz[id], 'nazwa' => $wiersz[name],
  11. 'glebokosc' => 0);
  12. }
  13.  
  14. for ($i = 1; $i < $glebokosc; $i++) {
  15.  $rodzice = implode(', ', $rodzice);
  16. $zapytanie = "SELECT * FROM category WHERE parent_id IN (" . $rodzice
  17. . ") ORDER BY name ASC";
  18. $wynik = mysql_query($zapytanie2);
  19. $rodzice = array();
  20. while ($wiersz = mysql_fetch_array($wynik)) {
  21. $rodzice[] = $wiersz['id'];
  22. $drzewko[] = array('id' => $wiersz[id], 'nazwa' => $wiersz[name],
  23. 'glebokosc' => (int)$glebokosc);
  24. }
  25. }  
  26.  
  27. return $drzewko;  
  28. }
  29. ?>
lectric
Dzieki.
Tylko, ze przy tej metodzie jest utracony wazny element, ktora kategoria dziecko jest pod ktora kategoria rodzicem.
Ludvik
Ale przecież masz pole parent_id w bazie, więc czemu go nie użyć do odwzorowania związków? Dopisanie tego nie będzie raczej problemem...
crashu
kiedys niepotrzebnie rozwiazlem ten problem

  1. <?php
  2. $db['query'] = 'SELECT * FROM '.CATEGORY_TABLE.' WHERE blog = '.$iBlogID.' ORDER BY sub ASC';
  3. $db->query();
  4. $db->num_rows();
  5.  
  6. if( $db['rows'] < 1 ) return;
  7.  
  8. $kubel = array();
  9. $tree = array();
  10. //Tutaj tworze drzewo
  11. while( $row = $db->fetch_array() ) {
  12.  
  13. $id = $row['id'];
  14.  
  15. $kubel[$id]['id'] = $id;
  16. $kubel[$id]['name'] = $row['name'];
  17. $kubel[$id]['subid'] = $row['sub'];
  18.  
  19. if( !is_array($kubel[$id]['subs']) ) $kubel[$id]['subs'] = array();
  20.  
  21. if( $row['sub'] == 0 ) {
  22.  
  23. array_push($tree, &$kubel[$id]);
  24. }
  25. else {
  26.  
  27. if( !is_array($kubel[$row['sub']]['subs']) )
  28. $kubel[$row['sub']]['subs'] = array();
  29.  
  30. array_push($kubel[$row['sub']]['subs'], &$kubel[$id]);
  31. }
  32. }
  33.  
  34. //zaczynam rysowac
  35. if( count($tree) < 1 ) return '<categories/>';
  36.  
  37. $Stos = array();
  38. $string = '';
  39. reset($tree);
  40.  
  41. $row = @current($tree);
  42.  
  43. while( 1 ) {
  44.  
  45. if( $row == null ) {
  46.  
  47. if( count($Stos) > 1 ) {
  48.  
  49. array_pop($Stos);
  50. $last = array_pop($Stos);
  51. $row = @next($last['subs']);
  52. array_push($Stos, $last);
  53.  
  54. $string .= '</category>'.NL;
  55. if( $row == null ) continue;
  56. }
  57. else if( count($Stos) == 1 ) {
  58.  
  59. $row = array_pop($Stos);
  60. if( count($row['subs']) > 0 )
  61. $string .= '</category>'.NL;
  62.  
  63. $row = null;
  64. if( $row == null ) continue;
  65. }
  66. else {
  67.  
  68. $row = @next($tree);
  69. @reset($row);
  70. if( $row == null ) break;
  71. }
  72. }
  73.  
  74. if( count($row['subs']) > 0 ) {
  75.  
  76. $string .= '<category name="'.$row['name'].'" id="'.$row['id'].'" >'.NL;
  77.  
  78. reset($row['subs']);
  79. array_push($Stos, $row);
  80. $row = current($row['subs']);
  81. continue;
  82. }
  83. else {
  84.  
  85. $string .= '<category name="'.$row['name'].'" id="'.$row['id'].'" />'.NL;
  86.  
  87. if( count($Stos) > 0 ) {
  88.  
  89. $last = array_pop($Stos);
  90. $row = @next($last['subs']);
  91. array_push($Stos, $last);
  92. }
  93. else $row = null;
  94. }
  95. }
  96.  
  97. unset($tree);
  98. unset($kubel);
  99. unset($Stos);
  100.  
  101. echo '<categories>'.NL.$string.NL.'</categories>';
  102. ?>
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.