Pagination (Halaman Data)

Jika tabel di database memiliki 1.000 data, menampilkannya sekaligus dalam satu halaman akan membuat website sangat lambat. Solusinya adalah Pagination — membagi data ke beberapa halaman (misal: 10 data per halaman).

Konsep Pagination

Pagination di PHP dan MySQL bekerja dengan perintah LIMIT dan OFFSET.

  • LIMIT: Berapa banyak data yang mau ditampilkan per halaman.
  • OFFSET: Berapa banyak data yang harus dilewati (skip).

Rumus OFFSET

Offset = (Halaman Saat Ini - 1) * Limit

Contoh jika Limit = 10:

  • Halaman 1: (1 - 1) * 10 = 0 (Mulai dari baris ke-1)
  • Halaman 2: (2 - 1) * 10 = 10 (Lewati 10 baris pertama, mulai dari baris ke-11)
  • Halaman 3: (3 - 1) * 10 = 20 (Lewati 20 baris pertama, mulai dari baris ke-21)

Implementasi Lengkap di PHP

Buat file pagination.php:

<?php
require 'config/database.php'; // Ganti sesuai file koneksi PDO-mu

// 1. Tentukan jumlah data per halaman
$limit = 5;

// 2. Cari tahu halaman ke berapa saat ini (dari URL: ?page=2)
// Jika tidak ada di URL, set default ke halaman 1
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;

// Mencegah input halaman minus atau 0
if ($page < 1) {
    $page = 1;
}

// 3. Hitung OFFSET
$offset = ($page - 1) * $limit;

// 4. Hitung total semua data di database
$stmtTotal = $pdo->query("SELECT COUNT(*) as total FROM buku_tamu");
$rowTotal = $stmtTotal->fetch();
$totalData = $rowTotal['total'];

// 5. Hitung total halaman (bulatkan ke atas menggunakan ceil)
$totalPages = ceil($totalData / $limit);

// 6. Ambil data dengan LIMIT dan OFFSET
$sql = "SELECT * FROM buku_tamu ORDER BY id DESC LIMIT :limit OFFSET :offset";
$stmt = $pdo->prepare($sql);

// Penting: Bind parameter LIMIT dan OFFSET harus bertipe INT
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();

$data = $stmt->fetchAll();
?>

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <title>Contoh Pagination</title>
    <style>
        body { font-family: sans-serif; padding: 20px; }
        table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
        th, td { border: 1px solid #ddd; padding: 10px; text-align: left; }
        th { background-color: #f4f4f4; }
        
        .pagination { display: flex; gap: 5px; list-style: none; padding: 0; }
        .pagination a { 
            padding: 8px 12px; 
            border: 1px solid #007bff; 
            color: #007bff; 
            text-decoration: none; 
            border-radius: 4px;
        }
        .pagination a.active { 
            background-color: #007bff; 
            color: white; 
        }
        .pagination a.disabled {
            color: #ccc;
            border-color: #ccc;
            pointer-events: none;
        }
    </style>
</head>
<body>

    <h2>Daftar Buku Tamu (Halaman <?= $page ?> dari <?= $totalPages ?>)</h2>
    <p>Total data: <?= $totalData ?></p>

    <!-- Tabel Data -->
    <table>
        <tr>
            <th>ID</th>
            <th>Nama</th>
            <th>Pesan</th>
        </tr>
        <?php foreach ($data as $row): ?>
        <tr>
            <td><?= $row['id'] ?></td>
            <td><?= htmlspecialchars($row['nama']) ?></td>
            <td><?= htmlspecialchars($row['pesan']) ?></td>
        </tr>
        <?php endforeach; ?>
        
        <?php if (count($data) === 0): ?>
        <tr><td colspan="3" style="text-align: center;">Tidak ada data.</td></tr>
        <?php endif; ?>
    </table>

    <!-- Navigasi Pagination -->
    <?php if ($totalPages > 1): ?>
    <ul class="pagination">
        <!-- Tombol Previous -->
        <li>
            <a href="?page=<?= $page - 1 ?>" class="<?= ($page <= 1) ? 'disabled' : '' ?>">
                &laquo; Prev
            </a>
        </li>

        <!-- Angka Halaman -->
        <?php for ($i = 1; $i <= $totalPages; $i++): ?>
            <li>
                <a href="?page=<?= $i ?>" class="<?= ($page == $i) ? 'active' : '' ?>">
                    <?= $i ?>
                </a>
            </li>
        <?php endfor; ?>

        <!-- Tombol Next -->
        <li>
            <a href="?page=<?= $page + 1 ?>" class="<?= ($page >= $totalPages) ? 'disabled' : '' ?>">
                Next &raquo;
            </a>
        </li>
    </ul>
    <?php endif; ?>

</body>
</html>

Memahami bindValue

Pada langkah ke-6, kita menggunakan bindValue:

$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);

Mengapa tidak menggunakan execute([$limit, $offset]) seperti biasa? Karena MySQL mengharuskan angka untuk LIMIT dan OFFSET. Jika menggunakan execute([...]), PDO akan mengirimnya sebagai String (teks), yang akan menyebabkan error Syntax Error di MySQL. PDO::PARAM_INT memaksa PHP mengirimnya sebagai tipe Integer (Angka).

Kesimpulan

Alur dasar pagination:

  1. Cari tahu page berapa dari $_GET['page'].
  2. Hitung total data di database.
  3. Hitung offset berdasarkan page dan limit.
  4. Ambil data dengan LIMIT dan OFFSET.
  5. Tampilkan tombol navigasi (1, 2, 3...) menggunakan perulangan for.

Setelah mahir membagi data menjadi halaman, mari kita pelajari cara menangani file dengan: Upload File →.