Kadar je v tabeli veliko zapisov, jih običajno ne prikažemo vseh hkrati. Namesto tega jih razdelimo na več strani. Tak postopek imenujemo delni izpis ali paginacija.
Delni izpis izboljša preglednost strani in zmanjša količino podatkov, ki jih mora aplikacija prikazati naenkrat. Uporabnik se med posameznimi deli rezultatov premika s povezavami, kot so prejšnja stran, naslednja stran ali številke strani.
Pomni: Delni izpis temelji na treh podatkih: številu zapisov na stran, začetnem odmiku in skupnem številu vseh zapisov.
Pri paginaciji je pomembno, da so rezultati urejeni z ukazom ORDER BY. Tako uporabnik pri prehodu med stranmi dobi predvidljiv in stabilen vrstni red zapisov.
Vsebina strani
Osnovna pravila
Pri delnem izpisu iz celotnega nabora zapisov prikažemo samo določen del. Zato moramo poznati število zapisov na stran in začetni odmik.
- Za delni izpis uporabimo
LIMITinOFFSET. LIMITdoloča, koliko zapisov prikažemo.OFFSETdoloča, koliko začetnih zapisov preskočimo.- Skupno število vseh zapisov pridobimo z
COUNT(*). - Število strani izračunamo iz skupnega števila zapisov in števila zapisov na stran.
- Začetni odmik mora biti veljavno nenegativno celo število.
- Rezultate uredimo z
ORDER BY. - Pri izpisu vrednosti uporabimo
htmlspecialchars().
Pozor: Vrednost parametra start prihaja iz URL naslova, zato jo moramo vedno preveriti. Če je negativna, neveljavna ali previsoka, jo prilagodimo na smiselno vrednost.
Delni izpis zapisov oziroma paginacija
Paginacija pomeni, da uporabniku prikažemo le določen del zapisov, na primer 5 ali 10 zapisov na posamezni strani. Tako je izpis preglednejši in hitrejši.
Pri paginaciji običajno potrebujemo:
- koliko zapisov želimo prikazati na eni strani,
- od katerega zapisa naprej želimo začeti izpis,
- skupno število vseh zapisov v tabeli.
Osnovna sintaksa za delni izpis je:
SELECT *
FROM imeTabele
ORDER BY idStolpec
LIMIT steviloZapisov OFFSET zacetek;
Za izračun paginacije potrebujemo še skupno število zapisov:
SELECT COUNT(*) AS total
FROM imeTabele;
Na podlagi števila vseh zapisov izračunamo, koliko strani potrebujemo, katera stran je trenutna in ali lahko uporabniku pokažemo povezavo na prejšnjo ali naslednjo stran.
Pomni: Če je na strani prikazanih 5 zapisov, potem ima prva stran OFFSET 0, druga stran OFFSET 5, tretja stran pa OFFSET 10.
Osnovni primer z mysqli
Spodnji zgled prikaže 5 zapisov na stran in uporablja parameter start za določitev začetnega odmika.
<?php
define('DB_SERVER', 'localhost');
define('DB_USER', 'uporabnik');
define('DB_PASS', 'skritoGeslo');
define('DB_NAME', 'knjiznica');
$connection = mysqli_connect(DB_SERVER, DB_USER, DB_PASS, DB_NAME);
if (!$connection) {
die(
'Povezava s podatkovno zbirko ni vzpostavljena: ' .
mysqli_connect_error() .
' (' . mysqli_connect_errno() . ')'
);
}
$limit = 5;
$start = $_GET['start'] ?? 0;
if (filter_var($start, FILTER_VALIDATE_INT) === false || (int)$start < 0) {
$start = 0;
}
$start = (int)$start;
// Skupno število zapisov
$countResult = mysqli_query($connection, "SELECT COUNT(*) AS total FROM knjige");
$countRow = mysqli_fetch_assoc($countResult);
$totalRecords = (int)$countRow['total'];
// Delni izpis zapisov
$stmt = mysqli_prepare(
$connection,
"SELECT ID_knjige, Priimek_avtorja, Ime_avtorja, Naslov, Strani, Cena, Leto
FROM knjige
ORDER BY ID_knjige
LIMIT ? OFFSET ?"
);
mysqli_stmt_bind_param($stmt, 'ii', $limit, $start);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
while ($row = mysqli_fetch_assoc($result)) {
echo htmlspecialchars($row['Naslov']) . '<br>';
}
mysqli_stmt_close($stmt);
mysqli_close($connection);
?>
Pri mysqli uporabimo mysqli_query() za pridobivanje skupnega števila zapisov, za delni izpis pa pripravljen stavek z vrednostma LIMIT in OFFSET.
Osnovni primer s PDO
Tudi z vmesnikom PDO lahko pripravimo delni izpis in navigacijo med stranmi.
<?php
$streznik = 'localhost';
$baza = 'knjiznica';
$uporabnik = 'uporabnik';
$geslo = 'skritoGeslo';
try {
$pdo = new PDO("mysql:host=$streznik;dbname=$baza;charset=utf8mb4", $uporabnik, $geslo);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$limit = 5;
$start = $_GET['start'] ?? 0;
if (filter_var($start, FILTER_VALIDATE_INT) === false || (int)$start < 0) {
$start = 0;
}
$start = (int)$start;
$stmtCount = $pdo->query('SELECT COUNT(*) AS total FROM knjige');
$countRow = $stmtCount->fetch(PDO::FETCH_ASSOC);
$totalRecords = isset($countRow['total']) ? (int)$countRow['total'] : 0;
$stmt = $pdo->prepare(
"SELECT ID_knjige, Priimek_avtorja, Ime_avtorja, Naslov, Strani, Cena, Leto
FROM knjige
ORDER BY ID_knjige
LIMIT :limit OFFSET :start"
);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->bindValue(':start', $start, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
echo htmlspecialchars($row['Naslov']) . '<br>';
}
}
catch (PDOException $e) {
echo 'Napaka pri delnem izpisu: ' . $e->getMessage();
}
?>
Pri PDO vrednosti :limit in :start vežemo kot cela števila z PDO::PARAM_INT. Tako jasno določimo, da gre za številski vrednosti.
Izračun strani pri paginaciji
Pri paginaciji moramo poleg poizvedbe izračunati še nekaj dodatnih vrednosti, da lahko uporabniku pravilno prikažemo navigacijo.
- skupno število zapisov pridobimo z ukazom
COUNT(*), - število strani izračunamo iz skupnega števila zapisov in velikosti strani,
- trenutno stran izračunamo iz začetnega odmika,
- pripravimo povezave za prejšnjo in naslednjo stran,
- če uporabnik vnese previsok začetni odmik, ga prilagodimo na zadnji smiselni blok zapisov.
$limit = 5;
$totalRecords = 23;
$totalPages = (int)ceil($totalRecords / $limit);
Če imamo 23 zapisov in na eni strani prikažemo 5 zapisov, potrebujemo 5 strani.
$currentPage = (int)floor($start / $limit) + 1;
Če je $start enak 10 in je $limit enak 5, je trenutna stran tretja stran.
Pozor: Pri deljenju skupnega števila zapisov z velikostjo strani uporabimo ceil(), ker tudi nepopolna zadnja stran šteje kot samostojna stran.
Navigacija med stranmi
Pri delnem izpisu uporabniku običajno prikažemo povezave za premikanje med stranmi. Pri tem moramo izračunati ustrezne vrednosti parametra start.
$previousStart = max(0, $start - $limit);
$nextStart = $start + $limit;
Povezava na naslednjo stran je smiselna samo, če naslednji začetni odmik ne preseže skupnega števila zapisov.
if ($nextStart < $totalRecords) {
echo '<a href="14_delni-izpis.php?start=' . $nextStart . '">Naslednja</a>';
}
Povezave na številke strani lahko pripravimo z zanko:
for ($page = 1; $page <= $totalPages; $page++) {
$pageStart = ($page - 1) * $limit;
echo '<a href="14_delni-izpis.php?start=' . $pageStart . '">' . $page . '</a> ';
}
Pomni: Pri navigaciji je dobro označiti trenutno stran. Tako uporabnik lažje razume, kateri del rezultatov trenutno gleda.
Primerjava pristopov mysqli in PDO
Oba pristopa omogočata delni izpis s preverjenimi vrednostmi za LIMIT in OFFSET. Razlikujeta se predvsem v načinu priprave poizvedbe in branju rezultatov.
| Korak | mysqli |
PDO |
|---|---|---|
| Preverjanje odmika | filter_var() |
filter_var() |
| Štetje zapisov | mysqli_query() |
$pdo->query() |
| Priprava delnega izpisa | mysqli_prepare() |
$pdo->prepare() |
| Parametra | ?, ? |
:limit, :start |
| Branje rezultatov | mysqli_fetch_assoc() |
$stmt->fetchAll() |
Aplikacija Knjige
📘Aplikacija Knjige
V priloženi aplikaciji Knjige je delni izpis izveden v datoteki 14_delni-izpis.php. Na posamezni strani se prikaže po 5 zapisov, začetni odmik pa se prebere iz parametra start. Če je vrednost neveljavna ali negativna, se nastavi na 0.
Aplikacija najprej z ukazom SELECT COUNT(*) AS total FROM knjige prešteje vse zapise, nato pa z ukazom LIMIT :limit OFFSET :start pridobi le trenutni del rezultatov. Če je začetni odmik previsok, ga prilagodi na zadnji možni blok zapisov.
Nato izračuna še trenutno stran, skupno število strani ter vrednosti za povezavi nazaj in naprej. Na strani se izpišejo tudi aktivne številke strani in preglednica zapisov. Če zapisov ni, se pokaže posebno obvestilo.
14_delni-izpis.phpNavodila za izdelavo aplikacije Knjige
- Določimo, koliko zapisov želimo prikazati na eni strani.
- Iz URL parametra preberemo začetni odmik.
- Preverimo, ali je začetni odmik veljavno nenegativno celo število.
- Z ukazom COUNT(*) pridobimo skupno število zapisov.
- Če je odmik previsok, ga prilagodimo na zadnji smiseln blok zapisov.
- Z ukazoma LIMIT in OFFSET pridobimo trenutni del rezultatov.
- Izračunamo trenutno stran, skupno število strani ter povezavi za nazaj in naprej.
- Na strani izpišemo tabelo zapisov in navigacijo med stranmi.
- Pri izpisu vrednosti uporabimo
htmlspecialchars().
Pozor: Pri paginaciji moramo obravnavati tudi primere, ko v tabeli ni zapisov. Takrat ne prikazujemo nepotrebne navigacije med stranmi, ampak jasno obvestilo.
Priporočila
- Za delni izpis uporabi
LIMITinOFFSET. - Za skupno število zapisov uporabi
COUNT(*). - Rezultate vedno uredi z
ORDER BY. - Parameter
startpreveri kot nenegativno celo število. - Če je odmik previsok, ga prilagodi na zadnji smiseln blok zapisov.
- Uporabniku prikaži trenutno stran in skupno število strani.
- Pri številkah strani označi trenutno aktivno stran.
- Pri izpisu podatkov uporabi
htmlspecialchars().
Pogoste napake
- Parameter
startni preverjen. - Začetni odmik je negativen.
- Začetni odmik je večji od števila zapisov in ni prilagojen.
- Manjka ukaz
COUNT(*), zato navigacija ni pravilno izračunana. - Ukaza
LIMITinOFFSETsta uporabljena brezORDER BY. - Trenutna stran ni jasno označena.
- Pri prazni tabeli se še vedno prikazuje navigacija med stranmi.
- Pri izpisu vrednosti manjka
htmlspecialchars().
Pri delnem izpisu mora biti izračun strani usklajen s skupnim številom zapisov. Napačen izračun lahko povzroči prazne strani, nepravilne povezave ali ponavljanje istih zapisov.