Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php][sql] Bread Crumps
Forum PHP.pl > Forum > PHP
john_doe
Witam,

Tworzę katalog produktów. Menu jest rozwijane w dół, może być n-poziomowe. Tworze je skryptem, kolumny m.in. (id, name, link, image, parent_id).

Chciałbym stworzyć bread crumps ale jak narazie nie przychodzi mi do głowy jak to zrobić?

Tworzę to w CI. Nie jest to zbyt rozbudowany system. Narazie link mam postaci http://www.katalog.pl/device/show/2/5

gdzie kolejno

device - kontroller
show - metoda
2 - id grupy
4 - do paginacji

proszę o wskazówki jak wykonać "gdzie jestem"

Chciałbym to zrobić już teraz zanim wykonam cały katalog a potem przez Okruszki ... będę musiał coś poprawiać wstecz.

może napisać coś takiego co by sprawdzało pokrewieństwo wstecz aż do parent_id = 0

pozdrawiam
uirapuru
hmmm, masz wiele możliwości stworzenia struktury drzewa w bazie danych, najprostsze to korzystanie z dodatkowej kolumny: parent_id
drugi sposob to tzw. nested sets. Ja korzystam z obu naraz. Poza tym masz jeszcze materialized path.

Najprościej - jak działają?

a/ kazdy wpis ma id i parent_id - odwolują sie do siebie nawzajem. aby znaleźć breadcrumb musialbys pobrać element który aktualnie wyswietlasz oraz wszystkie wiersze 'starsze' - niestety przez rekurencję, a więc sposób jest po prostu powolny i kosztowny

b/ nested set to taka konstrukcja, gdzie najwyzszy element jest jak zbiór i zawiera w sobie wszystkie 'poniższe', a one zawierają kolejne dzieci, a te dzieci kolejne dzieci itd. ważne są 'uszy' zbioru. Zbiór pusty ma lewe ucho = 1, prawe ucho = 2. Jeżeli dodamy coś do tego zbioru, to teraz dziecko będzie miało lewe ucho = 2, prawe = 3, natomiast zbiór 'rodzic' będzie mieć zmodyfikowane prawe ucho - powiększone o 2. W rezultacie dostajemy coś takiego:



Mam nadzieję, że widzisz, gdzie są 'uszy' - to liczby na krawędziach. Ten sposob jest ok, ale o ile wyciągnięcie 'ścieżki' jest proste dzięki niemu, to już inne modyfikacje (usunięcie, przeniesienie) bywają kosztowne. Ja najbardziej lubie pracować na połączeniu obu powyższych

c/ materialized path zawiera po prostu kolumnę, w której wpisujesz id albo bezpośredino breadcrumbsy, np. tak:

1, meble, kategoria z meblami, meble
2, drewniane, kategoria z meblami drewnianymi, meble.drewniane
3, kuchenne, kategoria z meblami drewnianymi do kuchni, meble.drewniane.kuchenne
4. stoły, kategoria z meblami drewnianymi do kuchni bedacymi stolami ;D, meble.drewniane.kuchenne.stoly

Jak widać masz breadcrumb w ostatniej kolumnie jak na dłoni - tyle, ze wyobraz sobie co sie stanie, jesli bedziesz chcial przeniesc gdzies indziej element smile.gif


Poza powyzszym musisz pamietac o elementach statycznych - nie wszystko masz w bazie. dlatego najfajniejszym moim zdaniem rozwiązaniem jest tworzyć (statycznie lub dynamicznie plus cacheowanie) pliku np. xml zawierajacego całą 'nawigację' - hierarchiczną strukturę strony w postaci xmlowego drzewa. Wtedy tylko odczytujesz sobie z pliku 'gdzie jestes' i wyciągasz ścieżkę.
john_doe
uirapuru dzięki za post. Na chwilę obecną wykorzystuję punkt a) o którym piszesz.
mając tabele

id | label | link | parent_id

rzeczywiście muszę stworzyć funkcję rekurencyjną "wspinającą" się ku górze kończąć na parent_id = 0

zastanawiam się czy lepiej dać z tej tabeli SELECT * i potem robić operacje przeszukiwania na tablicy aby uniknąć ponownego i ponownego odpalania zapytania.
tylko jeszcze tego nie napisałem...

pozdro
uirapuru
Pierwsze rozwiązanie ma wielką wadę właśnie w tym przypadku - trzeba orać zapytaniami bazę. Dlatego właśnie łącze 1) z 2) - wtedy za pomocą jednego select wyciagam od razu wszystkie elementy 'starsze' (po prostu znajdujące się na lewo od 'ucha' interesującego nas elementu, to tak w wielkim uproszczeniu)
john_doe
wiesz robię to 1szy raz więc muszę się przkonać i udoskonalić

narazie mam tyle i nie chodzi smile.gif

  1. public function create_breadcrumps( $options = array() )
  2. {
  3. $bread = '';
  4. $CI =& get_instance();
  5.  
  6. $query = $CI->db->query("SELECT id, parent, label, link FROM menu WHERE id = " . $options['id'] );
  7.  
  8. $result = $query->row(0);
  9.  
  10. $bread .= $result->label;
  11.  
  12. while($result->parent == 0)
  13. {
  14. $bread .= $this->create_breadcrumps( array('id' => $result->parent) );
  15. }
  16.  
  17. return $bread;
  18.  
  19. }

zwraca mi aktualny label bez przodków
uirapuru
polecam a) x-debug i korzystać z debugowania kodu (podstawowe narzędzie w arsenale programisty) albo chociaż cool.gif dużo var_dump() robić na poszczególnych zmiennych i juz wiesz co i gdzie nie halo smile.gif
phpion
Co do problemów z wywołaniem rekurencyjnym: po pobraniu ścieżki zapisz ją w cache i następnymi żądaniami stamtąd pobieraj. Nie będziesz "orał" bazy danych.
uirapuru
dodatkowym przyspieszeniem moim zdaniem rekurencji owej byłoby napisanie funkcji w sql, którą się wywołuje dla konkretnego elementu a ona zwraca w postaci np. jsona poszczególne elementy - odpada wtedy tez koniecznosc robienia zapytań w php w kółko...
phpion
No tak, ale wówczas i tak odpalasz X zapytań, ale z poziomu bazy danych. Na pewno będzie to szybsze, ale rekurencyjne wywoływanie zapytań i tak będzie występowało. Ja bym postawił mimo wszystko na cache, ewentualnie zabawę z funkcją na bazie danych + cache.
uirapuru
phpion: i mysle, ze to bardzo dobre rozwiazanie w pewnych przypadkach wink.gif
john_doe
nie za bardzo kumam o co Wam chodzi panowie? w tej chwili przypisuję każdy zwrot z bazy i dopisuję go do ścieżki. Tak wygląda kod smile.gif jednak coś jest nie tak bo nadal mam to samo o czym pisałem wcześniej.
CuteOne
  1.  
  2. $bread[$result->id]['label'] = $result->label;
  3.  
  4. while($result->parent == 0)
  5. {
  6. $bread[$result->id][] = $this->create_breadcrumps( array('id' => $result->parent) );
  7. }


Powinno zatrybić wink.gif

ps. do tego dodałbym szukanie po IP LINK - mmo użycia LIKE jest naprawdę wydajne
john_doe
dzięki CuteOne mam taki kod teraz z Twoją sugestią ... ten sam rezultat. Czy wchodzą w menu rozwijam gałąź w dół i klikam w link czyli powinno być

menuGłówne -> subMenu w breadcrumps

i taki link http://127.0.0.1/main/device/3

array
3 =>
array
'label' => string 'subMenu1' (length=10)

  1. public function create_breadcrumps( $options = array() )
  2. {
  3. //$bread = array();
  4. $CI =& get_instance();
  5.  
  6. $query = $CI->db->query("SELECT id, parent, label FROM menu WHERE id = " . $options['id'] );
  7.  
  8. $result = $query->row(0);
  9.  
  10.  
  11. $bread[$result->id]['label'] = $result->label;
  12.  
  13. while($result->parent == 0)
  14. {
  15. $bread[$result->id][] = $this->create_breadcrumps( array('id' => $result->parent) );
  16. }
  17.  
  18. return $bread;
  19.  
  20. }
CuteOne
while($result->parent == 0) nie ma sensu - wykonujesz pętle tylko gdy parent = 0 po czym psrawdzasz czy id = 0 istnieje (id powinno zaczynać się od 1)

  1. if($result->parent > 0)
  2. {
  3. $bread['submenu'][$result->id] = $this->create_breadcrumps( array('id' => $result->parent) );
  4.  
  5. return $bread;
  6. }

ps. po co pętla skoro pobierasz tylko jeden rekord?? tongue.gif
john_doe
racja CuteOne

podaję rozwiązanie, dodatkowo w tym przypadku przydałoby się dołożyć funkcjonalność odwracania zwracanego stringa, w tej postaci breadcrump jest od tyłu.

i przerabiam na materialized path

  1. public function create_breadcrumps( $options = array() )
  2. {
  3.  
  4. $bread = '';
  5. $CI =& get_instance();
  6.  
  7. $query = $CI->db->query("SELECT id, parent, label FROM menu WHERE id = " . $options['id'] );
  8.  
  9. $result = $query->row(0);
  10.  
  11.  
  12. $bread .= $result->label;
  13.  
  14. if($result->parent > 0)
  15. {
  16. $bread .= $this->create_breadcrumps( array('id' => $result->parent) );
  17. }
  18. return $bread;
  19.  
  20. }
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.