Gdy liczba rekordów w bazie danych wzrośnie, interfejs witryny WWW musi zawierać udogodnienia ułatwiające przeglądanie i wyszukiwanie informacji. W artykule przedstawię sześć przykładowych rozwiązań, które ułatwiają poruszanie się wśród dużej liczby rekordów. Od strony implementacyjnej zarysuję szkielet stronicowania oraz alfabetu połączonego z sortowaniem.
Sześć sztuczek
Jeśli witryna WWW prezentuje zawartość bazy danych, a liczba rekordów w bazie jest duża, to należy zastosować różne rozwiązania ułatwiające przeglądanie danych. Popularnymi rozwiązaniami są:
- kontekstowe hiperłącza,
- stronicowanie,
- sortowanie danych według dowolnej kolumny,
- alfabet do wybierania rekordów na zadaną literę,
- przewijanie rekordów (następny, poprzedni),
- kolorowanie wierszy w tabeli.
Kontekstowymi hiperłączami nazywam odnośniki występujące w tabelach zestawień. Ich rola polega na umożliwieniu łatwego przejścia do strony prezentującej szczegółowe dane dotyczące wybranego zagadnienia. Jeśli, na przykład, tabela artykułów zawiera kolumny: tytuł, rocznik, numer, rubryka, podrubryka i występuje w niej – na pozycji 2 – wpis:
2. Polskie e-banki 5/2001 RYNEK.RAPOR
to:
- tytuł artykułu (Polskie e-banki) jest hiperłączem do strony przedstawiającej szczegółowe dane tegoż artykułu (czyli m.in. nazwiska autorów oraz wstęp),
- cyfra 5 jest hiperłączem do spisu treści numeru 5/2001,
- liczba 2001 jest hiperłączem do zestawienia wszystkich numerów z roku 2001,
- napis RYNEK jest odnośnikiem do strony
prezentującej zestawienie wszystkich artykułów z rubryki RYNEK, - napis RAPORT jest odnośnikiem do zestawienia artykułów z podrubryki RAPORT.
Druga ze sztuczek, stronicowanie, jest najważniejsza. Bez stronicowania wyników można otrzymać podstrony prezentujące tysiące rekordów. Przeglądanie takich stron jest niewygodne, nie mówiąc o czasie generowania witryny. Jeśli tylko liczba rekordów zwróconych przez zapytanie jest duża (w praktyce: przekracza kilkadziesiąt rekordów), to nie należy wyświetlać ich w postaci jednej tabeli. Zamiast tego tabelę dzielimy na fragmenty po około 20 rekordów i dołączamy wskaźnik aktualnej strony.
Trzecim udogodnieniem jest sortowanie tabel wg dowolnej kolumny. Komórki nagłówkowe tabel stają się odnośnikami. Aktywacja hiperłącza
powoduje posortowanie danych wg wybranej kolumny. (Ponowne kliknięcie nagłówka posortuje dane w porządku malejącym.) O porządku sortowania informują strzałki dodane do komórek nagłówkowych.
Czwarty trik polega na dodaniu przycisków następny, poprzedni. Hiperłącza takie ułatwiają przechodzenie po kolejnych rekordach danej kategorii. W ten sposób użytkownik może łatwo przejść do następnej osoby, następnego produktu czy działu.
Jako następne udogodnienie zastosuję alfabet do wybrania rekordów rozpoczynających się na wybraną literę.
Kliknięcie wybranej litery alfabetu powoduje przefiltrowanie rekordów. Na stronie wyświetlane są wyłącznie rekordy rozpoczynające się na wybraną literę. Alfabet taki stosujemy niezależnie w różnych kategoriach (np. do wybierania osób, których nazwisko rozpoczyna się na zadaną literę, lub do wybierania artykułów o tytule rozpoczynającym się na wybraną literę).
Ostatnim rozwiązaniem jest kolorowanie wierszy. Dodatkowo odpowiedni skrypt JS odpowiada za kolorowanie wiersza wskazanego kursorem myszki.
Przykładowa witryna WWW
Jako przykład po raz kolejny wykorzystałem bazę danych artykułów opublikowanych w Magazynie INTERNET. Zestawienie z lat 2001-2006 (roczniki 2001 oraz 2006 są niepełne) daje bazę danych zawierającą 3352 rekordy.
Strona główna witryny jest widoczna na rysunku 1. Menu witryny zawiera opcje Autorzy, Artykuły, Roczniki, Numery, Rubryki oraz Podrubryki.
Każda z opcji powoduje wyświetlenie wszystkich rekordów danej kategorii. I tak: po wybraniu opcji Autorzy użytkownik ujrzy pełne zestawienie autorów piszących do MI. Po wybraniu opcji
Artykuły wyświetlane jest zestawienie wszystkich artykułów. Kolejna opcja, Roczniki, wyświetla wszystkie roczniki zawarte w bazie danych.
I tak dalej.
Kontekstowe odnośniki
Wszystkie dane zawarte w tabelach są kontekstowymi odnośnikami. Gdziekolwiek na stronie pojawia się tytuł artykułu, to będzie on odnośnikiem do szczegółowych danych artykułu. Podobnie: imię i nazwisko zawsze stanowią hiperłącze do zestawienia artykułów danego autora. Rok jest hiperłączem do zestawienia wszystkich numerów
z danego rocznika, a numer – spisu treści wybranego numeru. Krótko mówiąc: każda dana zawarta w tabeli jest hiperłączem do pewnej podstrony,
która – zależnie od kontekstu – prezentuje zestawienie bądź szczegółowe dane.
Stronicowanie wyników
Z racji na liczbę rekordów wyświetlenie na stronie wszystkich artykułów nie ma sensu. W bazie danych znajduje się 1367 artykułów. Tabela zawierająca wszystkie artykuły byłaby bardzo długa i niewygodna. Ten sam argument wyklucza generowanie pełnej listy wszystkich autorów, numerów, rubryk oraz podrubryk. (Jedynie tabela roczników jest na tyle krótka, że nie wymaga stronicowania
Zatem pełne zestawienie rekordów poddajemy stronicowaniu. Rys. 2 przedstawia pierwszą stronę nazwisk autorów. Zestawienie zawiera pierwsze 20 nazwisk.
Zwróćmy uwagę na numerację wierszy tabeli. Pierwsza strona nazwisk zawiera numery od 1 do 20, zaś po przejściu do strony piątej wiersze będą miały numery od 81 do 100.
Liczby wyświetlane ponad tabelą, służą do
zmiany strony wyników. Wskaźnik strony, zawiera przyciski: pierwsza strona, poprzednia strona, następna strona, ostatnia strona oraz numery dostępnych stron. Lista autorów zawiera 11 stron (217 nazwisk). Wskaźnik strony, prezentuje numery wszystkich dostępnych stron.
Zwróćmy uwagę, że we wskaźniku przyciski umożliwiające przejście do pierwszej oraz poprzedniej strony nie są dostępne na pierwszej stronie. Podobnie: na ostatniej stronie niedostępne są przyciski przechodzące do następnej oraz ostatniej strony.
W przypadku listy artykułów wskaźnik przyjmuje nieco inną postać. Tym razem rekordów jest
1367, co daje 69 stron. Wskaźnik tej długości nie zmieści się na ekranie. Rozwiązaniem jest prezentacja tylko fragmentu wskaźnika. Widocznymi numerami będą strona bieżąca, sześć numerów poprzednich oraz sześć numerów następnych. Łącznie 13 numerów.
Na pierwszej stronie wskaźnik pokazuje strony od 1 do 13 .
Na stronie 24 dostępne są strony o numerach od 18 do 30 .
Jeśli numer pierwszej strony (czyli 1) nie jest wyświetlany, wówczas wskaźnik zawiera (obok przycisku przechodzącego do poprzedniej strony) trzy kropki. Podobnie w przypadku braku numeru ostatniej strony wyświetlane są trzy kropki z prawej strony wskaźnika. Kropki te informują
o możliwości przewijania stron w jednym, w drugim lub w obydwu kierunkach.
Sortowanie wyników według dowolnej kolumny
Drugim udogodnieniem w interfejsie witryny jest sortowanie danych. Tabele prezentowane na stronie WWW zawierają kolumny nagłówkowe, które są hiperłączami. Pierwsza aktywacja hiperłącza
powoduje posortowanie danych w porządku rosnącym względem danej kolumny. Jeśli ponownie klikniemy to samo hiperłącze (w nagłówku tabeli), to dane zostaną posortowane malejąco według wybranej kolumny.
Rys. 7 przedstawia listę wszystkich artykułów posortowaną malejąco wg liczby stron (ostatnia kolumna w tabeli). Oczywiście sortowanie jest ściśle związane ze stronicowaniem. Jeśli ustalimy porządek sortowania, stronicowanie odnosi się do wybranego porządku.
Jeśli teraz zmienimy porządek sortowania, poprzez kliknięcie kolumny zatytułowanej Numer, to wyświetlona zostanie pierwsza strona zestawienia artykułów, posortowanego wg innego klucza. Jak widać na rys. 9, artykuł oznaczony numerem
1 jest inny od artykułu zawartego w tabeli widocznej na rys. 7. Jako dość oczywisty wniosek należy pamiętać, że te same dane w tabeli mogą otrzymać różny numer w zależności od ustalonego porządku sortowania.
Zwróćmy uwagę, że o porządku sortowania informuje strzałka umieszczona obok etykiety kolumny. Na rys. 10 przedstawiona jest strzałka informująca o tym, że lista artykułów jest posortowana rosnąco (strzałka skierowana do góry) wg tytułu.
Zauważmy także, że kolumny tabel są hiperłączami wyłącznie do pierwszej strony wyników w danym porządku. Innymi słowy, kliknięcie komórki nagłówkowej powoduje wyświetlenie pierwszej strony wyników posortowanych według wybranej kolumny.
Następny, poprzedni
Przyciski Pierwszy, Poprzedni, Indeks, Następny oraz Ostatni, dostępne w lewym górnym rogu, umożliwiają przewijanie rekordów.
Działają one kontekstowo i są dostępne dopiero po wybraniu jednego z rekordów danej kategorii. Na przykład po wybraniu z listy autorów pani Justyny Adamczyk wskaźnik umożliwi przejście do
rekordu poprzedniego (Arnolda Adamczyka) oraz
następnego (Artura Adamowicza).
Natomiast po wybraniu rocznika 2004 wskaźnik umożliwia przejście do rocznika 2003 (poprzedni rekord) oraz 2005 (następny rekord).
Podobnie, po wybraniu numeru 4/2005 wskaźnik umożliwi przejście do numerów 3/2005 (poprzedni) oraz 5/2005 (następny).
Alfabet
Kolejnym sposobem ułatwienia poruszania się po witrynie jest dostarczenie alfabetu do wybierania rekordów na daną literę. Rys. 12 przedstawia alfabet, który umożliwia wybieranie autorów o nazwiskach rozpoczynających się na wybraną literę.
Alfabet ten jest powiązany z mechanizmem sortowania. Po wybraniu konkretnej litery sortowanie jest zawężone do nazwisk rozpoczynających się na zadaną literę.
Z racji na to, że liczba nazwisk na każdą z liter jest niewielka (sięga kilkunastu), zrezygnowałem ze stronicowania. Zatem alfabet stosuję w połączeniu z sortowaniem danych, ale bez stronicowania.
Kolorowanie wierszy
Ostatni z zabiegów, kolorowanie wierszy, ma charakter czysto kosmetyczny i odbywa się zupełnie niezależnie od pozostałych rozwiązań. Jak widać na rys. 13, co piąty wiersz tabeli podlega kolorowaniu. Dodatkowo, skrypt JS zmienia kolor bieżąco wskazywanego wiersza.
Uwagi dotyczące implementacji
Przygotowanie podanych rozwiązań wymaga:
- ustalenia przestrzeni adresów URL,
- ustalenia odpowiednich zapytań SQL,
- zaimplementowania metod odpowiedzialnych za pobieranie danych z bazy,
- organizacji przekazywania danych wziętych z bazy do szablonu na podstawie zmiennych URL,
- przygotowania szablonu odpowiedzialnego za realizację konkretnego fragmentu interfejsu witryny.
Adresy URL
Aplikacja wykorzystuje cztery zmienne URL:
- id – identyfikuje wybrany dział,
- id2 – identyfikuje wybrany rekord,
- s – identyfikuje kolumnę, według której sortujemy dane,
- str – identyfikuje wybraną stronę.
Na przykład pod adresem:
index.php?id=3&s=3&str=7
znajdziemy siódmą stronę (str=7) listy autorów (dział id=3) posortowaną rosnąco wg trzeciej kolumny (s=3). Natomiast pod adresem:
index.php?id=6&s=-2&str=3
dostępna jest trzecia strona (str=3) zestawienia numerów czasopisma (dział id=6). Dane
są posortowane malejąco według drugiej kolum-
ny (s=-2).
Odnośniki kontekstowe wymagają zazwyczaj podania numeru identyfikacyjnego rekordu (np. wyświetlenie szczegółowych danych artykułu wymaga identyfikatora artykułu, zaś zestawienie artykułów z rubryki powstaje w oparciu o identyfikator rubryki). Numer identyfikacyjny jest zawsze podawany w zmiennej id2.
Stronicowanie i sortowanie
Stronicowanie i sortowanie implementujemy równocześnie. Oto zapytanie, które wyznacza listę autorów posortowaną rosnąco wg nazwisk i zawierającą rekordy od 10 do 25 (w klauzuli LIMIT najpierw podajemy numer pierwszego rekordu,
a później liczbę rekordów):
SELECT
tosoba _ id, imie, nazwisko,
liczbaartykulow, liczbastron
FROM
tosoba
ORDER BY
nazwisko, imie
LIMIT
10, 15
Zadeklaruj w skrypcie stałą DBA _ LICZBA _ REKORDOW _ NA _ STRONIE:
define(\'DBA_LICZBA_REKORDOW_NA_STRONIE\', 20);
Listing 1 ( ) przedstawia (skrócony do jednego porządku sortowania) kod funkcji zwracającej listę autorów. Parametrami funkcji są porządek sortowania oraz numer strony wyników (liczbę rekordów na stronie wyznaczamy w oparciu
o zadeklarowaną stałą).
Wywołanie:
$autorzy = $db->DBA_podaj_wszystkie_osoby(-2, 3);
zwraca trzecią stronę listy autorów posortowaną malejąco wg drugiej kolumny.
Pętla for widoczna na listingu 1 odpowiada za ponumerowanie zwracanych wierszy. Numery wierszy wstawiane są do tablicy asocjacyjnej pod indeksem ’no’.
Gd y gotowa jest metoda DBA _ podaj _ wszystkie _ osoby() uwzględniająca stronicowanie i sortowanie, przechodzimy do implementacji wywołania jej z odpowiednimi parametrami. W skrypcie głównym najpierw ustalamy wartości zmiennych $sortowanie oraz $strona. Odbywa się to na etapie walidacji zmiennych:
$akcja = 3;
$sortowanie = $_GET[\'s\'];
$strona = $_GET[\'str\'];
Ustalony numer strony i porządek sortowania
przekazujemy do metody, a odebrane dane wysyłamy do szablonu:
case 3:
$osoby = $db->DBA_podaj_wszystkie_osoby($sortowanie, $strona);
$s->assign(\'osoby\', $osoby);
Pozostanie jeszcze przygotowanie szablonu. Za drukowanie zestawienia autorów odpowiada szablon autorzy-wszyscy.tpl, którego zarys jest widoczny na listingu 4 ( ). Iteracja section przetwarza tablicę $osoby przekazaną do szablonu ze skryptu index.php.
Do szablonu przekazujemy także zmienną $sortowanie. Na jej podstawie produkujemy komórki nagłówkowe tabel. Jedna z komórek nagłówkowych z listingu 4 przyjmuje postać:
Imię i nazwisko
{if $sortowanie == 1}
↑
{elseif $sortowanie == -1}
↓
{/if}
Strzałki do góry i do dołu są zapisane w kodzie
HTML w postaci encji {stala}↑{/stala} oraz {stala}↓{/stala}.
Wskaźnik strony
Implementacja wskaźnika bieżącej strony rozpoczyna się od zapytania wyznaczającego liczbę stron. W przypadku tabeli tosoba (tabela ta zawiera zestawienie autorów) zapytanie to przyjmie postać:
SELECT
CEILING(COUNT(tosoba _ id) / 30)
FROM
tosoba
Po wykorzystaniu stałej {stala}DBA _ LICZBA _ REKORDOW _ NA _ STRONIE{/stala} oraz metod klasy DB zapytanie to wydajemy w metodzie {stala}DBA _ tosoba _ count _ pages(){/stala} widocznej na listingu 3 ( ).
W skrypcie index.php wywołujemy metodę z listingu 3, po czym zwróconą liczbę stron (wraz
z numerem bieżącej strony oraz stron poprzedniej, następnej, pierwszej i ostatniej) przekazujemy do szablonu:
$strony_liczba = $db->DBA_tosoba_count_pages() + 1;
$s->assign(\'strony _ liczba\', $strony_liczba);
$s->assign(\'strony_biezaca\', $strona);
if ($strona - 1 > 0) {
$s->assign(\'strony_prev\', $strona - 1);
} else {
$s->assign(\'strony_prev\', false);
}
if ($strona + 1 < $strony_liczba) {
$s->assign(\'strony_next\', $strona + 1);
} else {
$s->assign(\'strony_next\', false);
}
... (zmienne $strony_first, $strony_last)
Szablon wskaźnika bieżącej strony autorów jest zapisany w pliku stronicowanie-autorow.tpl.
Przycisk powrotu do poprzedniej strony ma postać:
{if $strony_prev}
{else}
{/if}
Przyciski przewijające do pierwszej, następnej
i ostatniej strony powstają – w niemal identyczny sposób – na podstawie zmiennych{stala} $strony _
first, $strony _ next, $strony _ last{/stala}. Natomiast numery stron (widoczne na wskaźniku) produkuje pętla section:
{section name=strony loop=$strony_liczba start=1}
{if $smarty.section.strony.index == $strony_biezaca}
{$smarty.section.strony.index}
{else}
{$smarty.section.strony.index}
{/if}
{/section}
Zwróćmy uwagę, że powyższa iteracja nie przetwarza tablicy. Jest ona odpowiednikiem następującej pętli for:
for ($i = 1; $i <= $strony_liczba; $i++) {
...
}
Alfabet i sortowanie
Implementacja alfabetu umożliwia sortowanie danych (zawężonych do wybranej litery alfabetu) wg dowolnej kolumny. Zapytanie SQL odpowiedzialne za ustalenie listy autorów, których nazwiska rozpoczynając się na literę A (kod 65)
i są posortowane malejąco wg liczby artykułów jest następujące:
SELECT
tosoba_id, imie, nazwisko,
liczbaartykulow, liczbastron
FROM
tosoba
WHERE
ORD(LEFT(nazwisko, 1)) = 65
ORDER BY
liczbaartykulow DESC, nazwisko, imie
Funkcja {stala}DBA _ podaj _ osoby _ na _ litere(){/stala} przedstawiona na listingu 2 ( ) odpowiada za wydanie powyższego zapytania. Parametrami funkcji są porządek sortowania oraz kod litery alfabetu.
W skrypcie {stala}index.php{/stala} sprawdzamy poprawność zmiennych URL i ustalamy wartość zmiennej $sortowanie:
$akcja = 15;
$sortowanie = $_GET[\'s\'];
Następnie na podstawie zmiennej {stala}$sortowanie{/stala} oraz kodu litery ($ _ GET[\'id2\']) ustalamy listę pasujących nazwisk w odpowiednim porządku. Listę tę (zawartą w zmiennej $osoby) przekazujemy do szablonu:
case 15:
$osoby = $db->DBA_podaj_osoby_
$s->assign(\'osoby\', $osoby);
$s->assign(\'kodlitery\', $_GET[\'id2\']);
Tablicę {stala}$osoby{/stala} przetwarzamy iteracyjnie poprzez szablon:
{$smarty.section.i.iteration}. | {$osoby[i].imie} {$osoby[i].nazwisko} | {$osoby[i].liczbaartykulow} | {$osoby[i].liczbastron} |
Komórki nagłówkowe tabeli produkujemy na podstawie zmiennych $sortowanie oraz $kodlitery:
Imię i nazwisko
{if $sortowanie == 1}
↑
{elseif $sortowanie == -1}
↓
{/if}
Podsumowanie
Na zakończenie chciałbym zwrócić uwagę dwa zagadnienia: rozmiar pliku dba.class.php oraz pobieranie wszystkich rekordów z bazy danych.
Klasa odpowiedzialna za wydawanie zapytań SQL ma kilkadziesiąt metod. Plik dba.class.php liczy kilka tysięcy linii. Poruszanie po takim pliku jest niewygodne. Ponieważ jednak w języku PHP cała klasa musi być zapisana w jednym pliku, zatem nie możemy pliku dba.class.php po prostu rozbić na kilka mniejszych. Rozwiązaniem tego problemu jest dziedziczenie. Klasę DBA możemy podzielić na kilka mniejszych klas dziedziczących po sobie. W omawianym przykładzie podział ten jest dwustopniowy.
Klasa bazowa nazywa się DBA
i zawiera zasadniczy zestaw metod (plik dba.class. php). Dziedzicząca po niej klasa DBANextPrev zawiera metody dotyczące przewijania rekordów (następny/poprzedni) oraz alfabetu (plik dbanextprev.class.php).
Jeśli chodzi o pobieranie rekordów z bazy danych, to pamiętajmy, że metody pobierające wszystkie rekordy (np. wszystkich autorów czy wszystkie artykuły) są potrzebne. Wprawdzie na stronie WWW nie będziemy wyświetlali monstrualnych tabel, ale podczas generowania przyjaznych adresów URL musimy mieć dostęp do pełnych list rekordów. Pamiętajmy więc, że w przypadku stosowania przyjaznych URL-i zapisanych w pliku
.htaccess i generowanych na podstawie bazy danych klasa DBA musi zawierać metody zwracające pełne listy rekordów.