[Nâng cao] Phân trang trong PHP và MySQL

Ở bài trước mình đã hướng dẫn các bạn phân trang ở mức cơ bản. Nếu các bạn chưa xem bài viết trước của mình thì mình nghĩ bạn cần xem lại một chút. Thuật toán phân trang với PHP và MySQL Điểm yếu trong bài viết phân trang cơ bản là chúng ta sẽ hiển thị hết tất cả danh sách các trang. Nếu bạn có ...

Ở bài trước mình đã hướng dẫn các bạn phân trang ở mức cơ bản. Nếu các bạn chưa xem bài viết trước của mình thì mình nghĩ bạn cần xem lại một chút. Thuật toán phân trang với PHP và MySQL

Điểm yếu trong bài viết phân trang cơ bản là chúng ta sẽ hiển thị hết tất cả danh sách các trang. Nếu bạn có khoảng 100 trang mà hiển thị hết ra thì nhìn nó không đẹp mắt chút nào. Trong bài viết này mình sẽ hướng dẫn các bạn nâng cao một chút là làm thế nào để có thề giới hạn số lượng trang cần hiển thị.

Xem demo

Thì để làm được điều này bạn cần cung cấp thêm một số đối số đầu vào nữa.

  • $pageNum: Số trang sẽ hiển thị trên một webpage.
  • $pageStart: Số trang bắt đầu
  •  $pageEnd: Số trang kết thúc
  • $numLink: Khoảng lùi trang và khoảng tiến trang so với trang hiện tại.

Các bạn follow theo hình vẽ.

 Tôi muốn hiển thị 5 trang/webpage $pageNum = 5

Ở đây thì mình đang ở trang số 5. Thì mình muốn nó sẽ hiển thị 2 trang trước và sau so với trang hiện tại.

$numLink = 2;

Nhưng đây là cách tính tĩnh. Nếu bây giờ mình đặt

  • $pageNum = 6 Thì mình sẽ hiển thị 3 trang trước và 2 trang sau.
  • $pageNum = 7 Thì mình sẽ hiển thị 3 trang trước và trang sau.
  • $pageNum = 8 Thì mình sẽ hiển thị 4 trang trước và 3 trang sau.

Từ đó mình suy ra:

$numLink = floor($pageNum/2);

Đểm mấu chốt trong cách tính này là phải tính toán được hai tham số là $pageStart và $pageEnd. Thì dưới đây là cách tính của mình.

Vì số lượng records trong CSDL mẫy có hạn nên mình sẽ giảm có $recordPerPage = 3. Nghĩa là cứ ba records sẽ nằm trong một trang.

Mình sẽ sét hai trường hợp.

Trường hợp 1: $currentPage >= $pageNum

$pageStart = $currentPage - $numLink;
if($totalPage > $currentPage+$numLink)
{
    $pageEnd = $currentPage+$numLink;
}
else if($currentPage  $totalPage-($pageNum-1))
{
    $pageStart = $totalPage-($pageNum-1);
    $pageEnd = $totalPage;
}
else
{
    $pageEnd = $totalPage;
}

Trường hợp 2: $currentPage

Bạn đang ở trang Trang hiện tại nhỏ hơn trang s

// Mặc định $pageStart = 1
$pageStart = 1; 
if ($totalPage > $pageNum)
    $pageEnd = $pageNum;
else
    $pageEnd = $totalPage;

Ghép hai trường hợp trên:

if($currentPage >= $pageNum)
{
    $pageStart = $currentPage - $numLink;
    if($totalPage > $currentPage+$numLink)
    {
        $pageEnd = $currentPage+$numLink;
    }
    else if($currentPage  $totalPage-($pageNum-1))
    {
        $pageStart = $totalPage-($pageNum-1);
        $pageEnd = $totalPage;
    }
    else
    {
        $pageEnd = $totalPage;
    }
}
else
{
    $pageStart = 1;
    if ($totalPage > $pageNum)
        $pageEnd = $pageNum;
    else
        $pageEnd = $totalPage;
}

Code hoàn chỉnh:

<?php
    define("DB_HOST", "localhost");
    /** The name of the database for demo */
    define("DB_NAME", "demo_db");
    /** MySQL database username */
    define("DB_USER", "demo_db");
    /** MySQL database password */
    define("DB_PASS", "Gu5ZwYzL");
    
    // Bước 1: Kết nối tới CSDL
    $dbconn = mysql_connect(DB_HOST,DB_USER,DB_PASS) or die('Không thể kết nối tới CSDL');
    mysql_select_db(DB_NAME, $dbconn) or die('Không thể kết nối tới CSDL!');
    
    // Bước 2: Tính tổng $totalRecords
    $query = "SELECT count(*) AS totalRecords FROM employees";
    $result = mysql_query($query, $dbconn);
    $row = mysql_fetch_assoc($result);
    $totalRecords = !empty($row) ? $row['totalRecords'] : 0;
    
    // Bước 3: Lấy $currentPage và thiết lập $recordPerPage
    $currentPage = isset($_GET['page']) && (int) $_GET['page'] > 0 ? (int) $_GET['page'] : 1;
    // Thiết lập số records/1 trang
    $recordPerPage = 3;
    // Thiết lập số trang
    $pageNum = 5;
    // Khoảng lùi và tiến danh sách trang
    $numLink = floor($pageNum/2);
    
    // Bước 4: Tính tổng số trang($totalPage) và tính $offset
    $totalPage = ceil($totalRecords/$recordPerPage);
    // Tính $offset
    $offset = ($currentPage-1)*$recordPerPage;
    $limit = "LIMIT $offset,$recordPerPage";
    
    $query = "SELECT * FROM employees ".$limit; 
    $result = mysql_query($query, $dbconn);
    
    // PHẦN HIỂN THỊ DANH SÁCH
?>
<div class="container">
    <?php if(mysql_num_rows($result) > 0){ ?>
        <table class="tbl-grid" cellpadding="0" cellspacing="0" awidth="100%">
            <thead><tr>
                <td class="gridheader">employeeNumber</td>
                <td class="gridheader">lastName</td>
                <td class="gridheader">firstName</td>
                <td class="gridheader">extension</td>
                <td class="gridheader">email</td>
                <td class="gridheader">officeCode</td>
                <td class="gridheader">reportsTo</td>
                <td class="gridheader">jobTitle</td>
            </tr></thead>
        <?php while ($row = mysql_fetch_assoc($result)){?>
            <tr>
                <td><?php echo $row['employeeNumber'] ?></td>
                <td><?php echo $row['lastName'] ?></td>
                <td><?php echo $row['firstName'] ?></td>
                <td><?php echo $row['extension'] ?></td>
                <td><?php echo $row['email'] ?></td>
                <td><?php echo $row['officeCode'] ?></td>
                <td><?php echo $row['reportsTo'] ?></td>
                <td><?php echo $row['jobTitle'] ?></td>
            </tr>
        <?php } ?>
        </table>
    <?php } ?>
    
    <br />
    <div class="pagination">
        <?php
        // Button trang trước
        if($currentPage > 1 && $totalPage > 0){
            echo '<a href="index[nc].php?page='.($currentPage-1).'&t='.time().'">&larr;</a>';
        }
        // Danh sách trang
        if($currentPage >= $pageNum){
            $pageStart = $currentPage - $numLink;
            if($totalPage > $currentPage+$numLink){
                $pageEnd = $currentPage+$numLink;
            }
            else if($currentPage <=$totalPage && $currentPage > $totalPage-($pageNum-1)){
                $pageStart = $totalPage-($pageNum-1);
                $pageEnd = $totalPage;
            }
            else{
                $pageEnd = $totalPage;
            }
        }else{
            $pageStart = 1;
             if ($totalPage > $pageNum)
                $pageEnd = $pageNum;
            else
                $pageEnd = $totalPage;
        }
        // Lặp và in danh sách trang
        for($i=$pageStart; $i<=$pageEnd; $i++){
            echo '<a'.($currentPage==$i?' class="current"':').' href="index[nc].php?page='.$i.'&t='.time().'">'.$i.'</a>';
        }
        
        // Button trang kế tiếp
        if($currentPage < $totalPage && $totalPage > 1){
            echo '<a href="index[nc].php?page='.($currentPage+1).'&t='.time().'">&rarr;</a>';
        }
        ?>
    </div>
</div>

Tổng kết:

OK ! Như vậy là mình đã hướng dẫn các bạn hoàn thành phần phân trang trong PHP kết hợp với MySQL. Nếu có thể mình sẽ hướng dẫn các bạn tạo một class phân trang hoàn chỉnh.

0