เนื้อหาเกี่ยวกับการสร้าง php ฟังก์ชั่น สำหรับจัดการการแบ่งหน้ารายการข้อมูล
ที่ดึงมาจากฐานข้อมูล เราเคยมีตัวอย่างไปแล้วในบทความ
แนวทาง การค้นหาจาก หลายรูปแบบ และแบ่งหน้า อย่างง่าย http://niik.in/573
https://www.ninenik.com/content.php?arti_id=573 via @ninenik
และเนื้อหาต่อไปนี้ ก็จะมีรูปแบบคล้ายๆ กัน แต่เป็นการประยุก์เพิ่มเติม โดยสร้างฟังก์ชั่นสำหรับแบ่ง
หน้าโดยใช้งานร่วมกับ Pagination Component ของ Bootstrap 4 โดยในที่นี้จะนำเสนอใน
2 รูปแบบ คือแบบแรกเป็นการดึงข้อมูลมาแสดง โดยมีแค่เพียงการแบ่งหน้าข้อมูลเท่านั้น
และแบบที่สอง คือมีการแบ่งหน้าข้อมูล และรองรับการค้นหา
แนวทางการประยุกต์จะยึดเนื้อหาของบทความจากลิ้งค์ด้านบนเป็นแนวทาง คือเป็นการดึงราย
การข้อมูลจังหวัดในประเทศไทย มาแสดงในตาราง
รูปแบบที่ 1 แสดงแบบแบ่งหน้าอย่างเดียว
ไฟล์ demo_001.php ไฟล์เริ่มต้นใช้งาน bootstrap
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>Document</title> <link rel="stylesheet" href="https://unpkg.com/bootstrap@4.1.0/dist/css/bootstrap.min.css" > <style type="text/css"> html{ font-family:tahoma, Arial,"Times New Roman"; font-size:14px; } body{ font-family:tahoma, Arial,"Times New Roman"; font-size:14px; } </style> </head> <body> <br> <br> <div class="container"> </div> <script src="https://unpkg.com/jquery@3.3.1/dist/jquery.min.js"></script> <script src="https://unpkg.com/bootstrap@4.1.0/dist/js/bootstrap.min.js"></script> <script type="text/javascript"> $(function(){ }); </script> </body> </html>
ไฟล์ dbconnect.php
<?php $mysqli = new mysqli("localhost", "root","","test"); /* check connection */ if ($mysqli->connect_errno) { printf("Connect failed: %s\n", $mysqli->connect_error); exit(); } if(!$mysqli->set_charset("utf8")) { printf("Error loading character set utf8: %s\n", $mysqli->error); exit(); }
ไฟล์ pagination_function.php
<?php function page_navi($total_item, $cur_page, $per_page=10, $query_str="", $min_page=5){ $total_page = ceil($total_item/$per_page); $cur_page = (isset($cur_page))?$cur_page:1; $diff_page = NULL; if($cur_page>$min_page){ $diff_page = $total_page-$cur_page; } $limit_page = $min_page; $f_num_page = ($cur_page<=$min_page)?1:(floor($cur_page/$min_page)*$min_page)+1; if($diff_page>$min_page){ $limit_page = ($min_page + $f_num_page)-1; }else{ if(isset($diff_page)){ $limit_page = $total_page; }else{ $limit_page = $min_page; } } $show_page = ($total_page<=$min_page)?$total_page:$limit_page; $l_num_page = 1; $prev_page = $cur_page-1; $next_page = $cur_page+1; $temp_query_str = $query_str; $query_str = ""; if($temp_query_str && is_array($temp_query_str) && count($temp_query_str)>0){ array_pop($temp_query_str); $query_str = http_build_query($temp_query_str); if($query_str!=""){ $query_str = "?".$query_str; } } $mark_char = ($query_str!="")?"&":"?"; echo '<nav> <ul class="pagination justify-content-center"> <li class="page-item"> <a class="page-link" href="'.$query_str.$mark_char.'page=1"> First</a> </li> '; echo ' <li class="page-item '.(($cur_page==1)?"disabled":"").'"> <a class="page-link" href="'.$query_str.$mark_char.'page='.$prev_page.'"> Previous</a> </li> '; for($i = $f_num_page; $i<=$show_page;$i++){ echo ' <li class="page-item '.(($i==$cur_page)?"active":"").'"> <a class="page-link" href="'.$query_str.$mark_char.'page='.$i.'"> '.$i.' </a> </li> '; } echo ' <li class="page-item '.(($next_page>$total_page)?"disabled":"").'"> <a class="page-link" href="'.$query_str.$mark_char.'page='.$next_page.'"> Next</a> </li> '; echo ' <li class="page-item"> <input type="number" class="form-control" min="1" max="'.$total_page.'" style="width:80px;" onClick="this.select()" onchange="window.location=\''.$query_str.$mark_char.'page=\'+this.value" value="'.$cur_page.'" /> </li> '; echo ' <li class="page-item"> <a class="page-link" href="'.$query_str.$mark_char.'page='.$total_page.'"> Last</a> </li> </ul> </nav> '; } ?>
ในฟังก์ชั่น page_navi() เรามีการใช้งาน paginaton component ของ bootstrap มาจัดรูปแบบ โดยตัว
ฟังก์ชั่นสำหรับแบ่งหน้าที่เราขึ้น จะมีรูปแบบตามรูปด้านล่าง
สามารถเลื่อนไปหน้าแรก ไปหน้าสุดท้าย หรือเลือกหน้าที่ต้องการ หรือไปหน้าก่อนหน้า หรือหน้าถัดไป
สามารถเลือกเปลี่ยนเลขหน้าที่ช่อง input เพื่อไปหน้าที่ต้องการได้
ตัวฟังก์ชั่น จะรับค่า parameter ต่างๆ ตามรูปแบบดังนี้
page_navi($total_item, $cur_page, $per_page=10, $query_str="", $min_page=5)
- $total_item จำนวนรายการข้อมูลทั้งหมด
- $cur_page หน้าปัจจุบัน
- $per_page=10 จำนวนรายการทีแสดงในแต่ละหน้า ถ้าไม่มีการส่งค่าจะใช้ค่าเท่ากับ 10
- $query_str="" สำหรับรองรับการส่งค่าเพิ่มเติมกรณีมีการค้นหา ถ้าไม่มีการกำหนดจะเป็นค่าว่าง
- $min_page=5 จำนวนเลขหน้าอย่างน้อยที่ต้องการแสดง ถ้าไม่กำหนด จะแสดงเลขหน้าไม่เกิน 5 ปุ่ม
ต่อไปเราจะนำไฟล์ต่างๆ มารวมกัน และประยุกต์ดึงข้อมูลจากฐานข้อมูลจังหวัดมาแสดง และแบ่งหน้า
จะได้ไฟล์ demo_001.php ปรับโค้ดเป็นดังนี้
ไฟล์ demo_001.php
<?php require_once("dbconnect.php"); require_once("pagination_function.php"); ?> <!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>Document</title> <link rel="stylesheet" href="https://unpkg.com/bootstrap@4.1.0/dist/css/bootstrap.min.css" > <style type="text/css"> html{ font-family:tahoma, Arial,"Times New Roman"; font-size:14px; } body{ font-family:tahoma, Arial,"Times New Roman"; font-size:14px; } </style> </head> <body> <br> <br> <div class="container"> <div class="table-responsive-sm"> <table class="table table-bordered table-striped table-hover table-sm"> <thead > <tr class="table-primary"> <th class="text-center" scope="col" width="30">#</th> <th class="text-left" scope="col">ชื่อจังหวัด</th> </tr> </thead> <tbody> <?php $num = 0; $sql = " SELECT * FROM province_th WHERE 1 "; $result=$mysqli->query($sql); $total=$result->num_rows; $e_page=10; // กำหนด จำนวนรายการที่แสดงในแต่ละหน้า $step_num=0; if(!isset($_GET['page']) || (isset($_GET['page']) && $_GET['page']==1)){ $_GET['page']=1; $step_num=0; $s_page = 0; }else{ $s_page = $_GET['page']-1; $step_num=$_GET['page']-1; $s_page = $s_page*$e_page; } $sql.=" ORDER BY province_id LIMIT ".$s_page.",$e_page"; $result=$mysqli->query($sql); if($result && $result->num_rows>0){ // คิวรี่ข้อมูลสำเร็จหรือไม่ และมีรายการข้อมูลหรือไม่ while($row = $result->fetch_assoc()){ // วนลูปแสดงรายการ $num++; ?> <tr> <th class="text-center" scope="row"><?=($step_num*$e_page)+$num?></th> <td class="text-left" ><?=$row['province_name']?></td> </tr> <?php } } ?> </tbody> </table> <?php page_navi($total,(isset($_GET['page']))?$_GET['page']:1,$e_page); ?> </div> <br> </div> <script src="https://unpkg.com/jquery@3.3.1/dist/jquery.min.js"></script> <script src="https://unpkg.com/bootstrap@4.1.0/dist/js/bootstrap.min.js"></script> <script type="text/javascript"> $(function(){ }); </script> </body> </html>
บรรทัดที่เราสามารถแก้ไข กรณีนำไปประยุกต์ใช้ คือบรรทัดที่ highlight ไว้ ได้แก่
บรรทัดที่ 40-42 เป็นส่วนของคำสั่ง SQL ที่ต้องการ ในตัวอย่างเรากำหนด WHERE 1 ไว้เพื่อรองรับ
การเพิ่มเงื่อนไขที่อาจจะมีในอนาคต
บรรทัดที่ 46 จำนวนรายการที่จะแสดงในแต่ละหน้า
บรรทัดที่ 57 เงื่อนไขการเรียงข้อมูล เปลี่ยนไปตามรูปแบบที่ต้องการ แต่ให้คง LIMIT ".$s_page.",$e_page ไว้
ในส่วนบรรทัดที่ 75 การเรียกใช้งานฟังก์ชั่นแบ่งหน้า page_navi()
page_navi($total,(isset($_GET['page']))?$_GET['page']:1,$e_page);
เรามีการส่งค่าไปทั้งหมด 3 ค่า คือ
$total
จำนวนรายการทั้งหมด
จำนวนรายการทั้งหมด
(isset($_GET['page']))?$_GET['page']:1
หน้าปัจจุบัน ใช้การเช็คว่ามีการส่งค่าหน้าหรือไม่ ถ้า
หน้าปัจจุบัน ใช้การเช็คว่ามีการส่งค่าหน้าหรือไม่ ถ้า
ยังไม่มีการส่งค่าหน้าผ่านตัวแปร $_GET'page'] ให้หน้าเริ่มต้นเป็นหน้าที่ 1
$e_page
จำนวนรายการที่แสดงแต่ละหน้า เราใช้ค่าจากตัวแปรที่กำหนดด้านบท คือ 10 รายการต่อหน้า
จำนวนรายการที่แสดงแต่ละหน้า เราใช้ค่าจากตัวแปรที่กำหนดด้านบท คือ 10 รายการต่อหน้า
ทดสอบตัวอย่างและผลลัพธ์ได้ที่ https://www.ninenik.com/demo/bootstrap4/demo_001.php
สมมติเราเพิ่มจำนวนการแสดงปุ่มเลขหน้า เข้าไปเป็น 10 ด้วยการเรียกใช์ดังนี้
page_navi($total,(isset($_GET['page']))?$_GET['page']:1,$e_page,'',10);
จะได้ผลลัพธ์ในส่วนของการแบ่งหน้าเป็นดังนี้
เนื่องเรามีรายชื่อจังหวัดทั้งหมดเพียง 77 จังหวัด แสดงหน้าละ 10 เราจะสามารถแบ่งได้ทั้งหมด 8 หน้า
ดังนั้นเมื่อเรากำหนดให้แสดงปุ่มเลขหน้าอย่างน้อย 10 ปุ่ม จำนวนปุ่มที่แสดงจริง จึงเท่ากับ 8 ตาม
จำนวนหน้าทั้งหมดที่มีอยู่จริง
แต่กรณีแรก เราไม่ได้มีการกำหนดจำนวนปุ่ม ทำให้มีการใช้ค่าเริ่มต้นคือ 5 เราจึงเห็นจำนวนปุ่มแสดง
แค่เพียง 5 รายการ และถ้าเรากดไปที่หน้าที่ 6 ก็จะแสดงปุ่มหน้าที่ 6-8 โดยเริ่มปุ่มแรกที่ปุ่มหน้าที่ 6
ตามรูปด้านล่างประกอบ
รูปแบบที่ 2 แสดงแบบแบ่งหน้า และการค้นหาข้อมูล
รูปแบบที่สองนี้ ก็จะเป็นการประยุกต์เพิ่มเติมจากรูปแบบแรก คือ การแบ่งหน้า จะรองรับกรณีการค้นหาข้อมูล
ด้วยเงื่อนไขต่างๆ ด้วย ซึ่งเมื่อมีการค้นหาข้อมูล รายการข้อมูล ก็จะแปรเปลี่ยนไปตามเงื่อนไขของตัวแปร
ที่ส่งเข้ามา ให้เราใช้ตัวอย่างจากไฟล์แรก แล้วเปลี่ยนชื่อไฟล์เป็น demo_002.php แล้วปรับโค้ดใหม่
เป็นดังนี้
ไฟล์ demo_002.php
<?php require_once("dbconnect.php"); require_once("pagination_function.php"); ?> <!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>Document</title> <link rel="stylesheet" href="https://unpkg.com/bootstrap@4.1.0/dist/css/bootstrap.min.css" > <style type="text/css"> html{ font-family:tahoma, Arial,"Times New Roman"; font-size:14px; } body{ font-family:tahoma, Arial,"Times New Roman"; font-size:14px; } .margin_top_5{ margin-top: 5px; } </style> </head> <body> <br> <br> <div class="container"> <form name="form1" method="get" action=""> <div class="form-group row"> <label for="keyword" class="col-sm-4 col-form-label text-right"> พิมพ์บางคำ บางตัว หรือไม่พิมพ์ก็ได้ </label> <div class="col-sm-3"> <input type="text" class="form-control" name="keyword" id="keyword" value="<?=(isset($_GET['keyword']))?$_GET['keyword']:""?>"> </div> </div> <div class="form-group row"> <label for="myselect" class="col-sm-4 col-form-label text-right"> เลือกอย่างหนึ่งอย่างใด หรือไม่เลือกก็ได้ </label> <div class="col-sm-3"> <select class="custom-select" name="myselect" id="myselect"> <option value="">เลื่อกเงื่่อนไข</option> <option value="ก" <?=(isset($_GET['myselect']) && $_GET['myselect']=="ก")?" selected":""?> >ขึ้นต้นด้วย ก</option> <option value="อุ" <?=(isset($_GET['myselect']) && $_GET['myselect']=="อุ")?" selected":""?> >ขึ้นต้นด้วย อุ</option> </select> </div> </div> <div class="form-group row"> <label for="" class="col-sm-4 col-form-label text-right"> เลือกอย่างหนึ่งอย่างใด หรือไม่เลือกก็ได้ </label> <div class="col-sm-3"> <div class="custom-control custom-radio custom-control-inline margin_top_5"> <input type="radio" id="myradio1" name="myradio" value="จ" <?=(isset($_GET['myradio']) && $_GET['myradio']=="จ")?" checked":""?> class="custom-control-input"> <label class="custom-control-label" for="myradio1">มี "จ"</label> </div> <div class="custom-control custom-radio custom-control-inline margin_top_5"> <input type="radio" id="myradio2" name="myradio" value="ม" <?=(isset($_GET['myradio']) && $_GET['myradio']=="ม")?" checked":""?> class="custom-control-input"> <label class="custom-control-label" for="myradio2">มี "ม"</label> </div> <div class="custom-control custom-radio custom-control-inline margin_top_5"> <input type="radio" id="myradio3" name="myradio" value="ส" <?=(isset($_GET['myradio']) && $_GET['myradio']=="ส")?" checked":""?> class="custom-control-input"> <label class="custom-control-label" for="myradio3">มี "ส"</label> </div> </div> </div> <div class="form-group row"> <label for="" class="col-sm-4 col-form-label text-right"> เลือกอย่างหนึ่งอย่างใด หรือเลือกทั้งสอง หรือไม่เลือกก็ได้ </label> <div class="col-sm-3"> <div class="custom-control custom-checkbox custom-control-inline margin_top_5"> <input type="checkbox" id="mycheckbox1" name="mycheckbox1" value="นี" <?=(isset($_GET['mycheckbox1']) && $_GET['mycheckbox1']=="นี")?" checked":""?> class="custom-control-input"> <label class="custom-control-label" for="mycheckbox1">ลงท้ายด้วย "นี"</label> </div> <div class="custom-control custom-checkbox custom-control-inline margin_top_5"> <input type="checkbox" id="mycheckbox2" name="mycheckbox2" value="คร" <?=(isset($_GET['mycheckbox2']) && $_GET['mycheckbox2']=="คร")?" checked":""?> class="custom-control-input"> <label class="custom-control-label" for="mycheckbox2">ลงท้ายด้วย "คร"</label> </div> </div> </div> <div class="form-group row"> <div class="col-sm-4 offset-sm-4"> <button type="submit" class="btn btn-primary" name="btn_search" id="btn_search">ค้นหา</button> <a href="demo_002.php" class="btn btn-danger">ล้างค่า</a> </div> </div> </form> <div class="table-responsive-sm"> <table class="table table-bordered table-striped table-hover table-sm"> <thead > <tr class="table-primary"> <th class="text-center" scope="col" width="30">#</th> <th class="text-left" scope="col">ชื่อจังหวัด</th> </tr> </thead> <tbody> <?php $num = 0; $sql = " SELECT * FROM province_th WHERE 1 "; //////////////////// MORE QUERY // เงื่อนไขสำหรับ radio if(isset($_GET['myradio']) && $_GET['myradio']!=""){ // ต่อคำสั่ง sql $sql.=" AND province_name LIKE '%".trim($_GET['myradio'])."%' "; } // เงื่อนไขสำหรับ input text if(isset($_GET['keyword']) && $_GET['keyword']!=""){ // ต่อคำสั่ง sql $sql.=" AND province_name LIKE '%".trim($_GET['keyword'])."%' "; } // เงื่อนไขสำหรับ select if(isset($_GET['myselect']) && $_GET['myselect']!=""){ // ต่อคำสั่ง sql $sql.=" AND province_name LIKE '".trim($_GET['myselect'])."%' "; } // เงื่อนไขสำหรับ checkbox if((isset($_GET['mycheckbox1']) && $_GET['mycheckbox1']!="") || (isset($_GET['mycheckbox2']) && $_GET['mycheckbox2']!="")){ // ต่อคำสั่ง sql if($_GET['mycheckbox1']!="" && $_GET['mycheckbox2']!=""){ $sql.=" AND (province_name LIKE '%".trim($_GET['mycheckbox1'])."' OR province_name LIKE '%".trim($_GET['mycheckbox2'])."' ) "; }elseif($_GET['mycheckbox1']!=""){ $sql.=" AND province_name LIKE '%".trim($_GET['mycheckbox1'])."' "; }elseif($_GET['mycheckbox2']!=""){ $sql.=" AND province_name LIKE '%".trim($_GET['mycheckbox2'])."' "; }else{ } } //////////////////// MORE QUERY $result=$mysqli->query($sql); $total=$result->num_rows; $e_page=10; // กำหนด จำนวนรายการที่แสดงในแต่ละหน้า $step_num=0; if(!isset($_GET['page']) || (isset($_GET['page']) && $_GET['page']==1)){ $_GET['page']=1; $step_num=0; $s_page = 0; }else{ $s_page = $_GET['page']-1; $step_num=$_GET['page']-1; $s_page = $s_page*$e_page; } $sql.=" ORDER BY province_id LIMIT ".$s_page.",$e_page"; $result=$mysqli->query($sql); if($result && $result->num_rows>0){ // คิวรี่ข้อมูลสำเร็จหรือไม่ และมีรายการข้อมูลหรือไม่ while($row = $result->fetch_assoc()){ // วนลูปแสดงรายการ $num++; ?> <tr> <th class="text-center" scope="row"><?=($step_num*$e_page)+$num?></th> <td class="text-left" ><?=$row['province_name']?></td> </tr> <?php } } ?> </tbody> </table> <?php page_navi($total,(isset($_GET['page']))?$_GET['page']:1,$e_page,$_GET); ?> </div> <br> <br> </div> <script src="https://unpkg.com/jquery@3.3.1/dist/jquery.min.js"></script> <script src="https://unpkg.com/bootstrap@4.1.0/dist/js/bootstrap.min.js"></script> <script type="text/javascript"> $(function(){ }); </script> </body> </html>
สำหรับในรูปแบบที่สอง สิ่งที่เราเพิ่มเข้ามาก็คือส่วนของฟอร์ม ที่เป็นเงื่อนไขเพิ่มเติมในการค้นหา
หรือใช้ในการกรองข้อมูล โดยเราจะใช้วิธีการส่งค่าแบบ GET
เมื่อมีฟอร์มแล้ว เราก็ต้องมีส่วนของการกำหนดเงื่อนไขคำสั่ง sql เพิ่มเติม โดยใช้ค่าจาก element
ต่างๆ ในฟอร์มที่ส่งมา ใช้เป็นตัวกำหนดเงื่อนไข ตามบรรทัดที่ 117-153
ส่วนสุดท้ายที่เพิ่มเข้ามาเล็กน้อย ในการส่ง parameter เข้าไปในฟังก์ชั่นแบ่งหน้าคือตัวแปร $_GET
ตามรูปแบบการเรียกใช้งานในบรรทัดที่ 186
ทดสอบตัวอย่างและผลลัพธ์ได้ที่ https://www.ninenik.com/demo/bootstrap4/demo_002.php
แนวทางการประยุกต์ข้างต้น เราสามารถนำไปดัดแปลงเพิ่มเติม เช่น อาจจะสร้างในรูปแบบ class ไว้ใช้งาน
หรือปรับแต่ง เพิ่มเติมได้ตามต้องการ หวังว่าแนวทางนี้ จะทำให้เราสามารถนำไปใช้งานในส่วนของ
การแบ่งหน้าได้สะดวกและง่ายขึ้น