Načrtovanje in razvoj spletnih aplikacij

Delni izpis podatkovne zbirke in navigacija

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 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 pogosto potrebujemo še skupno število zapisov:

SELECT COUNT(*) AS total
FROM imeTabele;

Na podlagi števila vseh zapisov nato izračunamo, koliko strani potrebujemo, katera stran je trenutna in ali lahko uporabniku pokažemo povezavo na prejšnjo ali naslednjo stran.

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);
?>

Osnovni primer s PDO

Tudi z vmesnikom PDO lahko enostavno 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();
}
?>

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 lahko prilagodimo na zadnji smiselni blok zapisov.

Pomembnosti pri delnem izpisu

  • delni izpis je uporaben pri tabelah z veliko zapisi,
  • za pridobivanje dela rezultatov uporabimo LIMIT in OFFSET,
  • za navigacijo med stranmi potrebujemo tudi COUNT(*),
  • rezultate je priporočljivo pred paginacijo urediti z ORDER BY,
  • uporabniku pogosto prikažemo še trenutno stran, število vseh strani in število zapisov.

📘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.

Primer: aplikacija Knjige – 14_delni-izpis.php

Navodila za izdelavo aplikacije Knjige

  1. Določimo, koliko zapisov želimo prikazati na eni strani.
  2. Iz URL parametra preberemo začetni odmik.
  3. Preverimo, ali je začetni odmik veljavno nenegativno celo število.
  4. Z ukazom COUNT(*) pridobimo skupno število zapisov.
  5. Z ukazoma LIMIT in OFFSET pridobimo trenutni del rezultatov.
  6. Izračunamo trenutno stran, skupno število strani ter povezavi za nazaj in naprej.
  7. Na strani izpišemo tabelo zapisov in navigacijo med stranmi.

Pri učenju je smiselno poznati oba pristopa:

  • mysqli za klasičen delni izpis zapisov,
  • PDO za sodobnejši pristop s pripravljenimi parametri,
  • aplikacijski pristop, kjer uporabnik prehaja med stranmi rezultatov s klikom na navigacijo.