[Postgres][PHP] Jak zrobi膰 uniwersalne porcjowanie wynik贸w na stronie, aby nie pokazywa艂a si臋 ca艂a zawarto艣膰 bazy danych?
Chcesz wyniki zapytania do bazy danych podzieli膰 na porcje, aby u偶ytkownik m贸g艂 przegl膮da膰 kilka mniejszych stron z wynikami zamiast jednej ogromnej. Chcesz decydowa膰 ile odpowiedzi znajdzie si臋 na ka偶dej ze stron i jak d艂ugi b臋dzie pasek nawigacyjny.
Porcjowanie wynik贸w zapytania to podstawowa czynno艣膰 podczas pracy z bazami danych, gdy wyniki przekraczaj膮 30 rekord贸w. Niekt贸re bazy danych licz膮 nawet kilkaset tysi臋cy wpis贸w i pokazanie ich wszystkich na jednej stronie WWW nie jest mo偶liwe.
Zamiast pokazywa膰 po kilkaset wynik贸w, mo偶na je 艂atwo porcjowa膰. Nie jest wa偶ne co porcjujesz - mog膮 to by膰 wpisy na forum, dedykacje w ksi臋gach go艣ci, informacje o ksi膮偶kach lub zawarto艣膰 katalogu produkt贸w w jakim艣 sklepie.
Opisany poni偶ej skrypt nie tylko 艣wietnie porcjuje dowolne zapytania do baz danych, ale jest niesamowicie elastyczny. Mo偶esz ustawia膰 ilo艣膰 danych przypadaj膮cych na jedn膮 stron臋, przekazywa膰 dodatkowe zmienne podczas przechodzenia pomi臋dzy stronami czy ustala膰 jak szeroki (np. od 1 do 10) b臋dzie pasek s艂u偶膮cy do poruszania si臋 pomi臋dzy stronami z wynikami.
Dodatkowo opr贸cz klikania na poszczeg贸lne strony mo偶esz wykorzysta膰 pola "nast臋pna" i "poprzednia", kt贸re automatycznie przenosz膮 o jedn膮 stron臋 do przodu lub do ty艂u. Zobacz jak napisa膰 uniwersalny skrypt do porcjowania wynik贸w:
<?
function pasek($l_odp,$l_odp_nastronie,$l_odp_napasku,$skrypt,$a) {
$l_odp_podz = intval($l_odp / $l_odp_nastronie);
$l_odp_podz_mod = $l_odp % $l_odp_nastronie;
if ($l_odp_podz_mod>0) $l_odp_podz++;
if ($a<0) $a=0;
if ($a>=$l_odp_podz) $a=$l_odp_podz-1;
$start = $a-1;
if ($a>0) {$pop="<a href=\"".$skrypt."a=$start\"><<<
poprzednia</a> - ";}
else {$pop = "<font color=gray><<< poprzednia </font> - ";}
if ($a<$l_odp_napasku) {$koniec = $l_odp_napasku*2+1;}
else {$koniec = $a+$l_odp_napasku+1;}
if ($a<=$koniec-$l_odp_napasku) {$star=$a-$l_odp_napasku;}
if ($a>=$l_odp_podz-$l_odp_napasku) {$star=$l_odp_podz-$l_odp_napasku*2-1;}
if ($koniec>$l_odp_podz) $koniec = $l_odp_podz;
if ($star<0) $star=0;
for ($i=$star; $i<$koniec; $i++) {
if ($i <> $a) { $pasek .= "<a href=\"".$skrypt."a=$i\">";}
else { $pasek .= "<font color=red><b>"; }
if ($l_odp_podz<>1) {$pomocniczy = $i+1;}
if ($i<>$a) { $pasek .= "$pomocniczy</a> "; }
else {$pasek .= "$pomocniczy</b></font> ";}
}
$dalej = $a+1;
if ($a<$l_odp_podz-1)
{$nas="- <a href=\"".$skrypt."a=$dalej\">nast臋pna >>> </a>";}
else { $nas = "- <font color=gray>nast臋pna >>> </font>";}
if ($pomocniczy>0) {$br= "<br> $pop $pasek $nas"; }
echo "<center> znalezionych: <b>$l_odp</b> na <b>$l_odp_podz</b>
stronach $br</center>";
}
$l_odp_nastronie=10;
$l_odp_napasku=5;
$skrypt="index.php?";
// po艂膮czenie z baz膮
$baza = pg_Connect("dbname=baza1 port=5432 user=uzytkownik");
// ustalenie ilo艣ci wszystkich rekord贸w spe艂niaj膮cych warunek
$wynik = pg_Exec($baza, "SELECT count(*) FROM ludzie;");
$l_odp = pg_result($wynik,0,"count");
// pobranie porcji informacji
$start=$a*$l_odp_nastronie;
$wynik = pg_Exec($baza, "SELECT * FROM ludzie
LIMIT $l_odp_nastronie OFFSET $start");
pg_close($baza);
// pokazanie paska nawigacyjnego
pasek($l_odp,$l_odp_nastronie,$l_odp_napasku,$skrypt,$a);
// wy艣wietlenie wynik贸w z bazy danych
$ile = pg_numrows($wynik);
echo $ile."<p>";
for ($i=0;$i<$ile;$i++) {
$rekord = pg_fetch_row($wynik, $i);
for ($j=0; $j<count($rekord); $j++) {
echo "$rekord[$j] ";
}
echo "<br>";
}
?>
Dzia艂ania funkcji pasek() opisywa膰 nie b臋d臋, poniewa偶 algorytm jest dosy膰 z艂o偶ony i zale偶y od wielu warunk贸w. Generalnie wszystko jest czyst膮 matematyk膮. Funkcja rozbija liczb臋 wszystkich odpowiedzi na poszczeg贸lne sk艂adowe, a wi臋c liczb臋 stron, aktualn膮 pozycj臋 czy ilo艣膰 cyfr w menu. Obliczenia s膮 uzale偶nione od wielu czynnik贸w i warunk贸w pocz膮tkowych.
Wa偶ne aby do funkcji pasek() przekaza膰 pi臋膰 zmiennych:
$l_odp - liczba wszystkich rekord贸w w bazie (mo偶liwych odpowiedzi)
$l_odp_nastronie - liczba rekord贸w na jednej stronie
$l_odp_napasku - liczba cyfr na pasku - wystarczy poda膰 tylko po艂ow臋 planowanej liczby zwi臋kszonej o jeden, np. 5 to w rzeczywisto艣ci 11 cyfr (1,2,3,4,5),6,(7,8,9,10,11). Okre艣la ona ilo艣膰 cyfr po prawej i lewej stronie wzgl臋dem 艣rodka.
$skrypt - nazwa skryptu bez parametr贸w np. index.php? lub z dodatkowymi parametrami index.php?x=123&c=sort&
$a - zmienna okre艣laj膮ca numer strony z wynikami - to w艂a艣nie ona okre艣la, kt贸ra porcja wynik贸w b臋dzie pokazana
Warto poeksperymentowa膰 z r贸偶nymi opcjami aby dostowa膰 skrypt do w艂asnych potrzeb. Opcje s膮 bardzo elastyczne i z powodzeniem mo偶na skrypt zastosowa膰 do dowolnych projekt贸w.
Funkcja pasek() tak na prawd臋 nie porcjuje wynik贸w... Tworzy ona jedynie pasek do nawigacji pomi臋dzy stronami z wynikami i ustala zmienn膮 $a. W艂a艣ciwe porcjowanie zachodzi na etapie zadawania pytania SQL do bazy danych.
Polecenie OFFSET pokazuje wyniki od okre艣lonego numeru rekordu, natomiast LIMIT okre艣la ile tych wynik贸w chcemy pobra膰. Poniewa偶 ilo艣膰 rekord贸w na stronie jest sta艂a, wystarczy zmodyfikowa膰 tylko OFFSET aby uzyska膰 np. pi膮t膮 dziesi膮tk臋 wynik贸w.
Liczb臋 odpowiedzi przypadaj膮cych na stron臋 podajemy pod funkcj膮 pasek(), ustalamy tam r贸wnie偶 liczb臋 cyfr na pasku i skrypt (oraz ewentualne parametry jakie ma przekazywa膰). Brakuje jeszcze ilo艣ci wszystkich rekord贸w. Pierwsze pytanie SQL pobiera brakuj膮c膮 ilo艣膰 rekord贸w (COUNT(*)). Je偶eli liczba rekord贸w w tabeli nie zmienia si臋, mo偶esz t膮 warto艣膰 przypisa膰 na sta艂e i usun膮膰 dwie linijki skryptu.
Gdy masz ju偶 wszystkie zmienne mo偶na zada膰 w艂a艣ciwe pytanie. Nast臋pnie wy艣wietlany jest pasek nawigacyjny i wybrana porcja wynik贸w. Kolejno艣膰 mo偶e by膰 dowolna - najpierw porcja wynik贸w, a na dole pasek nawigacyjny.
Jak widzisz, bez problemu mo偶na w ten spos贸b przegl膮da膰 bazy danych o tysi膮cach czy setkach tysi臋cy rekord贸w. Wszystko odbywa si臋 szybko i bardzo wygodnie dla u偶ytkownika.
Pytanie SQL nie musi zwraca膰 wszystkich rekord贸w - mo偶e zawiera膰 dodatkowe warunki np. sortowanie i wyszukiwanie rekord贸w. W tym celu musisz zmodyfikowa膰 je w dw贸ch miejscach w skrypcie.