[mysql] Dane meta

Jedną z najważniejszych rzeczy, którą robi się przy projektowaniu systemu, jest mechanizm gromadzenia i dostarczania dodatkowych danych. Dane te nie są domyślnie dostępne, ale mogą być wyciągnięte z bazy przy pomocy dodatkowego zapytania. Dlaczego tak? Przede wszystkim chodzi o elastyczność. Dzięki przerzuceniu danych do dodatkowej tabeli możemy odchudzić główną tabelę. Możemy także wprowadzić podział ze względu na język lub jakiś inny warunek. Zobaczmy, jak można zaprojektować tabele i mechanizmy.

Tabele

Dane meta mogą siedzieć w jednej tabeli. Takie rozwiązanie stosowane jest np. w WordPressie. W sumie się sprawdza, o ile nie trzeba znaleźć czegoś ważnego. Dlatego też preferuję rozwiązanie z tyloma tabelami meta, ile jest bazowych tabel wymagających dodatkowych danych. Tu pojawia się pierwsza bardzo ważna kwestia: struktura tabel meta musi być taka sama. Dlaczego? Ponieważ w ten sposób ułatwiamy sobie pobieranie i wstawianie danych. Bez tego musielibyśmy pisać funkcje specjalnie do każdej tabeli. Dzięki identycznej strukturze posługujemy się jednym zapytaniem i jedną funkcją wstawiającą dane. Na początek tabela może wyglądać następująco:

id_elementu INT
pole char( 50 )
wartosc text
jezyk TINYINT
modul TINYINT

Większości elementów nie muszę chyba opisywać. Pozostaje tylko kolumna moduł, której zadaniem jest trzymać informację, z którego modułu dane meta pochodzą. Dzięki temu poszczególne moduły panela administracyjnego nie będą ingerować w nieswoje dane. Jeżeli nie przewidujesz izolowania danych, to tę kolumnę możesz pominąć.

Edytor

Przy edycji elementu pobieramy dane z głównej tabeli, a następnie z tabeli meta. W edytorze najlepiej będzie umieścić te dodatkowe pola z nazwą meta_pole. Dzięki temu przy zapisywaniu będziemy mogli z $_POST wyciągnąć wszystko co zawiera meta_ i zapamiętać w $meta. Po poprawnym zapisaniu elementu określamy jego id (mysql_insert_id() albo id przekazane w $_POST) i przy pomocy pętli przechodzimy po tablicy $meta. Wewnątrz pętli sklejamy i wywołujemy zapytania zapisujące dane meta w bazie (ew. tworzymy jedno zapytanie wykonujące wielokrotny insert). Pozostaje tylko kwestia tego co zrobić z poprzednimi danymi. Najprościej będzie wywołać kasowanie danych wskazanego elementu. Cały proces może wyglądać następująco:

zapisz_dane();
$id = okresl_id();
usun_meta( $id );
zapisz_meta( $id, $meta );

Część dla odwiedzających

Tutaj dobrze będzie zrobić tak, żeby nie odwoływać się do bazy danych przy każdym elemencie, do którego potrzebujemy danych. Przykładowo funkcja wez_meta może przyjmować następujące parametry: id elementów, rodzaj danych, potrzebne pola. W samej funkcji sprawdzamy co znajduje się w id elementów. Jeżeli to all, to bierzemy wszystkie dane, w przeciwnym wypadku ograniczamy je przy pomocy where id_elementu in ( ). Na koniec pozostają potrzebne pola. Dzięki nim ograniczymy pamięć potrzebną do przechowania danych meta. Jeśli potrzebna nam jest ocena, to nie ma sensu pobierać także opisów, autorów, danych technicznych itd. Uzyskane dane meta odsyłamy jako tablicę, w której indeksem jest id_elementu, a wartością kolejna tablica:

$meta[$row['id_elementu]][] = $row;

Potrzebna jeszcze będzie funkcja wstawiająca dane do głównego zbioru. Nazwijmy ją wstaw_meta i niech działa na przekazanych danych elementu oraz danych meta:

foreach( $produkt as $indeks => $row ) {
 $row = wstaw_meta( $row, $meta[$row['id']] );
 $produkt[$indeks] = $row;
}

Można także przygotować samo pobieranie danych tak, żeby uwzględniało konieczność podpięcia tabeli meta. Więcej o tym w następnym akapicie.

Uwagi końcowe

Jeśli do tabeli dodamy indeksy w odpowiednich miejscach, to jedno zapytanie więcej nie zrobi większej różnicy w szybkości strony. Osobną kwestią jest liczba głównych elementów oraz ilość danych meta. Jeśli potrzebne są one do mapy xml dla googla (lub podobnego zbieracza danych, jak ceneo, skąpiec itd), to rozsądnym wyjściem będzie rozbicie tego na kilka fragmentów lub zrezygnowanie z funkcji pobierającej dane meta na rzecz sklecenia zapytania dobierającego dane meta przy pomocy left join:

select a,b,c, tm1.wartosc as x, tm2.wartosc as y, tm3.wartosc as z from tabela as t
left join tabela_meta as tm1 on tm1.id_elementu = t.id and tm1.pole = 'x'
left join tabela_meta as tm2 on tm2.id_elementu = t.id and tm2.pole = 'y'
left join tabela_meta as tm3 on tm3.id_elementu = t.id and tm3.pole = 'z'

gdzie a,b,c to dane z tabeli, a x,y,z, to wartości pól z tabeli meta. Listę pól do x, y, z bierzemy z wykazu pól potrzebnych do prawidłowego działania i możemy zrobić to następująco:

$pola = array( 'ocena', 'liczba_ocen' ) ;
$meta = 1 ;
foreach( $pola as $pole ) {
 $select[] = "tm".$meta.".wartosc as ".$pole ;
 $left_join[] = "left join tabela_meta as tm".$meta." on tm".$meta.".id_elementu = t.id and tm".$meta.".pole = '$pole'" ;
 $meta++;
}

W tabeli $select znajdują się pola, które pobieramy w zapytaniu, w $left_join złączenia do kolejnych pól. Metoda sprawdzi się tylko wtedy, gdy będziemy wiedzieli jakie pola są nam potrzebne i gdy nie będzie ich zbyt wiele.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

*