จากตอนที่แล้ว เราได้ศึกษาวิธีการแบ่งหน้ารายการข้อมูล แล้ว
เนื้อหาในตอนนี้เราจะมาดูเพิ่มเติม สำหรับการประยุกต์ต่อ กรณีที่
เราต้องการค้นหาข้อมูลในรายการข้อมูลที่แบ่งหน้าแล้ว จะสามารถทำได้อย่างไร
รวมทั้งจะพูดถึงรายละเอียดการ query ข้อมูลแบบมี เงื่อนไขในการใช้งาน query builder
ซึ่งเคยพูดถึงไปแล้วในบางส่วน
เนื้อหาตอนที่แล้ว
การแบ่งหน้าข้อมูลด้วย pagination class ใน codeigniter
https://www.ninenik.com/content.php?arti_id=673 via @ninenik
การสร้างฟอร์มค้นหา และการส่งค่า การค้นหาไปใช้งานใน model
ก่อนอื่นมาทำความข้าใจ URL รูปแบบหน้าการค้นหาที่เราจะใช้งาน
นี่คือ url หน้ารายการปกติที่มีการแบ่งหน้าแล้ว แต่นี้เป้นหน้าแรก
http://localhost/learnci/admin/service
ต่อไป url ของหน้ารายการที่มีการเลือกหน้าข้อมูล ตัวอย่างหน้า 2
http://localhost/learnci/admin/service/page/2
url ตัวอย่างหน้าที่มีการส่งค่าข้อมูลการค้นหาเข้าไป
http://localhost/learnci/admin/service?keyword=f&btn_search= http://localhost/learnci/admin/service/page/2?keyword=f&btn_search=
พอได้เห็นรุปแบบของ url ไปแล้ว
ทีนี้เรามาถึงขึ้นตอนการสร้างฟอร์มค้นหาข้อมูล ในที่นี้จะมีแค่ช่องค้นหา เพียงรายการเดียว
ใครที่ประยุกต์สามารถเพิ่มได้ตามต้องการ
ให้เปิดไฟล์ admin_service.php ในโฟลเดอร์ apps > views > admin
ดูโค้ดในส่วนของของ $action เท่ากับ null หรือ page
เราจะเพิ่มโค้ดใหม่ตามนี้เข้าไป
<?php $query_str = $this->input->get(); $keyword = $this->input->get('keyword'); $result = $this->service_model->getlist($id,$query_str); ?>
ขออธิบายตามส่วนๆ ไป
$query_str = $this->input->get(); // เอาค่าตัวแปร $_GET ทั้งหมด มาไว้ในตัวแปร $query_str
$keyword = $this->input->get('keyword'); // เอาค่าตัวแปร $_GET['keyword'] มาไว้ในตัวแปร $keyword
การใช้งาน input class ของ codeigniter โดยการใช้ $this->input->get('keyword')
แทน $_GET['keyword'] จะดีตรงที่เราไม่ต้องตรวจสอบการมีของตัวแปร
เพราะถ้าเรากำหนดเป็น
$keyword = $_GET['keyword'];
ระบบจะแจ้ง error (ใน php เวอร์ชั่นใหม่ๆ) เมื่อไม่มีการกำหนดตัวแปรมาก่อน ซึ่งแก้โดยใช้เป็น
if(isset($_GET['keyword']) && $_GET['keyword']!=""){ $keyword = $_GET['keyword']; }
แต่ก็จะยาวเกินความจำเป็นดังนั้นเราจึงใช้ $this->input->get('keyword') แทน
และต่อมา
$result = $this->service_model->getlist($id,$query_str); // มีการส่งค่า argument เพิ่มจากเดิม ส่งแค่เลขหน้าปัจจุบัน ก็เพิ่มตัวแปร $_GET // ท้ั้งหมดเข้าไปในรูปแบบ array
ถัดมาก็คือ ฟอร์ม โค้ดตามด้านล่าง action ชื่อไปที่ หน้ารายการหลัก method กำหนด
เป็น get และ มีการนำค่าข้อมูลเดิม มาแสดง เช่นพอเราค้นคำไหน ให้คำนั้นยังแสดง
ในช่องค้นหา
<form class="form-horizontal" action="<?=base_url('admin/service')?>" method="get"> <div class="row"> <div class="col-xs-10"> <div class="form-group"> <label for="query" class="col-xs-2 text-right" style="padding-top:6px;padding-right:0px;">คำค้น</label> <div class="col-xs-10"> <input type="text" class="form-control" name="keyword" value="<?=$keyword?>" placeholder="พิมพ์คำค้น"> </div> </div> </div> <div class="col-xs-2"> <button type="submit" name="btn_search" class="btn btn-primary btn-block">ค้นหา</button> </div> </div> </form> <br>
เป็นอันเสร็จในส่วนของการสร้างฟอร์มการค้นหา และการส่งข้อมูลเข้าไปใช้งานใน model
เราจะได้ไฟล์ admin_service.php ในส่วนของ $action เท่ากับ null หรือ page ดังนี้
<?php if($action==null || $action=='page'){?> <?php $query_str = $this->input->get(); $keyword = $this->input->get('keyword'); $result = $this->service_model->getlist($id,$query_str); ?> <a href="<?=base_url('admin/service/create')?>" class="btn btn-primary btn-sm">Create</a> <br><br> <form class="form-horizontal" action="<?=base_url('admin/service')?>" method="get"> <div class="row"> <div class="col-xs-10"> <div class="form-group"> <label for="query" class="col-xs-2 text-right" style="padding-top:6px;padding-right:0px;">คำค้น</label> <div class="col-xs-10"> <input type="text" class="form-control" name="keyword" value="<?=$keyword?>" placeholder="พิมพ์คำค้น"> </div> </div> </div> <div class="col-xs-2"> <button type="submit" name="btn_search" class="btn btn-primary btn-block">ค้นหา</button> </div> </div> </form> <br> <table class="table table-striped table-bordered table-condensed"> <thead> <tr> <th width="50" class="text-center">#</th> <th>Title</th> <th width="150" class="text-center">Modify Date</th> <th width="150" class="text-center">Manage</th> </tr> </thead> <tbody> <?php $i_num=0; if(!isset($id)){ $id=1; } if(count($result)>0){ foreach($result as $row){ $i_num++; ?> <tr> <td class="text-center"><?=(($id-1)*5)+$i_num?></td> <td><?=$row['service_title']?></td> <td class="text-center"><?=$row['service_update']?></td> <td class="text-center"> <a href="<?=base_url('admin/service/edit/'.$row['service_id'])?>" class="btn btn-success btn-sm"> <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> </a> <a href="<?=base_url('admin/service/delete/'.$row['service_id'])?>" class="btn btn-danger btn-sm"> <span class="glyphicon glyphicon-remove" aria-hidden="true"></span> </a> </td> </tr> <?php } ?> <?php } ?> </tbody> </table> <?php echo $this->pagination->create_links(); ?> <?php } ?>
การกำหนดการ query แบบมีเงื่อนไขพร้อมแบ่งหน้า
ทีนี้เรามาดูในส่วนของฟังก์ชั่น getlist() ในไฟล์ Service_model.php ในโฟลเดอร์ apps > models > admin
ขอยกโค้ดเดิมของต้นที่แล้วมา จะเป็นดังนี้
public function getlist($id){ $config['base_url'] = base_url('admin/service/page/'); // url เพจข้อมูลของเรา $config['per_page'] = 5; // จำนวนแสดงต่อหน้า $config['num_links'] = 2; // จำนวนเลขซ้ายขวา เช่น 1 2 3 4 5 คือหน้า 2 หลัง 2 $config['use_page_numbers'] = TRUE; // แสดงเลขหน้าตามจริง เช่นหน้า 1 ก็เป็นเลข 1 // ส่วนของการกำหนดหน้าตาของ การแบ่งหน้า เนื่องจากเราใช้ bootstrap css จึงสามารถนำมาใช้ได้เลย $config['full_tag_open'] = '<nav><ul class="pagination">'; // เปิดแท็กทั้งหมด $config['full_tag_close'] = '</ul><nav>'; // ปิดแท็กทั้งหมดด้วย $config['first_link'] = 'First'; // ข้อความแสดงหน้าแรก $config['first_tag_open'] = '<li>'; // แท็กเปิดข้อความหน้าแรก $config['first_tag_close'] = '</li>'; // แท็กปิดข้อความหน้าแรก $config['first_url'] = ''; //url หน้าแรก $config['last_link'] = 'Last'; // ข้อความสแดงหน้าสุดท้าย $config['last_tag_open'] = '<li>'; // แท็กเปิดข้อความหน้าสุดท้าย $config['last_tag_close'] = '</li>'; // แท็กปิดข้อความหน้าสุดท้าย $config['next_link'] = '>'; // ข้อความหน้าก่อนหน้า ในที่นี้ใช้สัญลักษณ์ < $config['next_tag_open'] = '<li>'; // แท็กเปิดข้อความแสดงหน้าก่อนหน้า $config['next_tag_close'] = '</li>'; // แท็กปิดข้อความแสดงหน้าก่อนหน้า $config['prev_link'] = '<'; // ข้อความหน้าถัดไป ในที่นี้ใช้สัญลักษณ์ > $config['prev_tag_open'] = '<li>'; // แท็กเปิดข้อความหน้าถัดไป $config['prev_tag_close'] = '</li>'; // แท็กปิดข้อความหน้าถัดไป $config['cur_tag_open'] = '<li class="active"><a href="javascript:void();">'; // แท็กหน้าเลขเพจปัจจุบัน $config['cur_tag_close'] = '</a></li>'; // แท้กปิดหน้าเพจปัจจุบัน $config['num_tag_open'] = '<li>'; // แท็กเปิดหน้าเพจเลขต่างๆ $config['num_tag_close'] = '</li>'; // แท็ปิดหน้าเพจเลขต่างๆ // หาจำนวนทั้งหมด $config['total_rows'] = $this->db->count_all('tbl_service'); // จำนวนทั้งหมด $this->pagination->initialize($config); // ตั้งค่าการกำหนด การแบ่งหน้า $begin=(isset($id) && $id>1)?($id-1)*$config['per_page']:0; $query = $this->db->get('tbl_service',$config['per_page'],$begin); return $query->result_array(); }
จากโค้ดหน้า views ที่เรามีการส่งค่าเพิ่มเข้ามา ดังนั้นฟังก์ชั่น getlist() เราจึงกำหนด parameter
เพิ่มมาอีกหนึ่งอัน เป็นส่วนของค่าตัวแปร ที่ใช้สำหรับเป็นเงื่อนไขการค้นหา จะได้เป็น
public function getlist($id,$query_str=null){
สิ่งที่ต้องกำหนดต่อมาคือ ให้หน้าแต่ละหน้า ที่เรากดเลือก ให้ส่งค่าตัวแปร GET ที่จะใช้ในการ
ค้นหาเข้าไปในลิ้งค์ด้วย ตามรูปแบบ
http://localhost/learnci/admin/service/page/2?keyword=f&btn_search=
โดยให้เพิ่มการกำหนดการตั้งค่าเพิ่ม ส่วนต่อไปนี้เข้าไป
$config['reuse_query_string'] = TRUE;
และส่วนสุดท้ายการเพิ่มเงื่อนไขการ query เข้าไป
ขอยกอ้างอิงโค้ดเดิม มาอธิบาย
// หาจำนวนทั้งหมด $config['total_rows'] = $this->db->count_all('tbl_service'); // จำนวนทั้งหมด $this->pagination->initialize($config); // ตั้งค่าการกำหนด การแบ่งหน้า $begin=(isset($id) && $id>1)?($id-1)*$config['per_page']:0; $query = $this->db->get('tbl_service',$config['per_page'],$begin); return $query->result_array();
โค้ดเดิมจำนวนรายการทั้งหมด จะเป็น
$this->db->count_all('tbl_service');
ก็คือนับทั้งหมดจากตาราง แต่โค้ดใหม่(query builder) จะนับจากผลลัพธ์ตามเงื่อนไขที่เพิ่มมา โดยใช้
$this->db->count_all_results('tbl_service',FALSE);
นั้นหมายความว่า ค่าอาจน้อยกว่า เท่ากับ หรือเป็น 0 ขึ้นกับเงื่อนไขนั้นๆ
และส่วนของการกำหนดขอบเขตของข้อมูล เดิมเราจะใช้
$this->db->get('tbl_service',$config['per_page'],$begin);
เราจะเปลี่ยนมาเป็น (query builder)
$this->db->limit($config['per_page'], $begin); $this->db->get();
แต่ก่อนเข้าไปสู่การ query ข้อมูล จะข้อกล่าวถึง การใช้ค่า parameter ตัวที่สองที่ส่งค่ามาใช้
ร่วมกับการ query ข้อมูล
ตัวแปร parameter ตัวที่สองเราใช้ชื่อว่า $query_str หากไม่มีการส่งค่าใดๆ มาให้ค่าเริ่มต้นเป็น null
ค่าที่ส่งเข้ามาเป็นชุด array ของตัวแปร $_GET ทั้งหมด
ดังนั้นถ้าส่งตัวแปร $_GET['keyword'] เข้ามา
เราก็สามารถเรียกใช้งานค่าเป็น $query_str['keyword'] แบบนี้เป็นต้น
ถ้าต้องการตรวจสอบว่ามีการส่งค่าตัวไหนมาบ้าง
ให้ใช้คำสั่ง
echo "<pre>"; print_r($query_str); echo "</pre>";
ต่อไปมาถึงส่วนของการ query แบบมีเงื่อนไข ตามที่เราได้อ้างจากข้อความด้านบน
ว่าแบบใหม่เราจะใช้แบบ query builder แต่สำหรับบางกรณี หรือผูเริ่มต้น การใช้แบบ
query standard ก็เป็นวิธีที่ดีและรวดเร็ว เพราะการใช้แบบ query builder เราอาจจะต้องใช้บ่อยๆ
หรือต้องจำวิธีการใช้ให้คล่องก่อน จึงจะทำงานได้เร็ว เพราะฉะนั้นทั้งสองแบบจึงมีข้อมดีแตกต่างกัน
ดังนั้นจะขออธิบายทั้งสองแบบ คือแบบใช้ query standard และแบบใช้ query builder
การกำหนดเงื่อนไขการ query แบบใช้ query standard
สามารถทำได้ดังนี้
$sql_more = ""; if(isset($query_str['keyword']) && $query_str['keyword']!=""){ $sql_more .=" AND service_title LIKE '%".$query_str['keyword']."%' "; } $sql = " SELECT * FROM tbl_service WHERE 1 $sql_more "; $query = $this->db->query($sql); $config['total_rows'] = $query->num_rows(); $this->pagination->initialize($config); // ตั้งค่าการกำหนด การแบ่งหน้า $begin=(isset($id) && $id>1)?($id-1)*$config['per_page']:0; $sql.=" LIMIT ".$begin.",".$config['per_page']." "; $query = $this->db->query($sql); return $query->result_array();
แบบแรกนี้จะไม่มีอะไร เน้นตรงเขียนคำสั่ง sql เข้าไปตามเงื่อนไขที่ต้องการ จะเห็นว่าค่อนข้าง
ง่ายไม่ซับซ้อน หรือต้องจำคำสั่งใหม่ๆ อะไร
การกำหนดเงื่อนไขการ query แบบใช้ query builder
สามารถทำได้ดังนี้
if(isset($query_str['keyword']) && $query_str['keyword']!=""){ $this->db->like('service_title',$query_str['keyword'] ); } $config['total_rows'] = $this->db->count_all_results('tbl_service',FALSE); $this->pagination->initialize($config); // ตั้งค่าการกำหนด การแบ่งหน้า $begin=(isset($id) && $id>1)?($id-1)*$config['per_page']:0; $this->db->limit($config['per_page'], $begin); $query = $this->db->get(); return $query->result_array();
จะเห็นว่าแบบที่สองจะค่อนข่างกระทัดรัด หรือเขียนโค้ดน้อยลงกว่าเดิม แต่ก็ไม่สะดวกสำหรับ
ผู้เริ่มต้นหรือผู้ที่ยังใช้งาน query builder ยังไม่คล่อง
ดังนั้นกรณีเนื้อหาตอนนี้เราจะใช้แบบ query builder ก็จะได้ไฟล์ Service_model.php ดังนี้
<?php class Service_model extends CI_Model { public function __construct() { parent::__construct(); $this->load->library('form_validation'); $this->form_validation->set_error_delimiters('<div class="bg-danger" style="padding:3px 10px;">', '</div>'); $this->load->library('upload'); $this->load->helper('path'); $this->load->library('pagination'); } public function getlist($id,$query_str=null){ $config['base_url'] = base_url('admin/service/page/'); // url เพจข้อมูลของเรา $config['per_page'] = 5; // จำนวนแสดงต่อหน้า $config['num_links'] = 2; // จำนวนเลขซ้ายขวา เช่น 1 2 3 4 5 คือหน้า 2 หลัง 2 $config['use_page_numbers'] = TRUE; // แสดงเลขหน้าตามจริง เช่นหน้า 1 ก็เป็นเลข 1 // ส่วนของการกำหนดหน้าตาของ การแบ่งหน้า เนื่องจากเราใช้ bootstrap css จึงสามารถนำมาใช้ได้เลย $config['full_tag_open'] = '<nav><ul class="pagination">'; // เปิดแท็กทั้งหมด $config['full_tag_close'] = '</ul><nav>'; // ปิดแท็กทั้งหมดด้วย $config['first_link'] = 'First'; // ข้อความแสดงหน้าแรก $config['first_tag_open'] = '<li>'; // แท็กเปิดข้อความหน้าแรก $config['first_tag_close'] = '</li>'; // แท็กปิดข้อความหน้าแรก $config['first_url'] = ''; //url หน้าแรก $config['last_link'] = 'Last'; // ข้อความสแดงหน้าสุดท้าย $config['last_tag_open'] = '<li>'; // แท็กเปิดข้อความหน้าสุดท้าย $config['last_tag_close'] = '</li>'; // แท็กปิดข้อความหน้าสุดท้าย $config['next_link'] = '>'; // ข้อความหน้าก่อนหน้า ในที่นี้ใช้สัญลักษณ์ < $config['next_tag_open'] = '<li>'; // แท็กเปิดข้อความแสดงหน้าก่อนหน้า $config['next_tag_close'] = '</li>'; // แท็กปิดข้อความแสดงหน้าก่อนหน้า $config['prev_link'] = '<'; // ข้อความหน้าถัดไป ในที่นี้ใช้สัญลักษณ์ > $config['prev_tag_open'] = '<li>'; // แท็กเปิดข้อความหน้าถัดไป $config['prev_tag_close'] = '</li>'; // แท็กปิดข้อความหน้าถัดไป $config['cur_tag_open'] = '<li class="active"><a href="javascript:void();">'; // แท็กหน้าเลขเพจปัจจุบัน $config['cur_tag_close'] = '</a></li>'; // แท้กปิดหน้าเพจปัจจุบัน $config['num_tag_open'] = '<li>'; // แท็กเปิดหน้าเพจเลขต่างๆ $config['num_tag_close'] = '</li>'; // แท็ปิดหน้าเพจเลขต่างๆ $config['reuse_query_string'] = TRUE; if(isset($query_str['keyword']) && $query_str['keyword']!=""){ $this->db->like('service_title',$query_str['keyword'] ); } $config['total_rows'] = $this->db->count_all_results('tbl_service',FALSE); $this->pagination->initialize($config); // ตั้งค่าการกำหนด การแบ่งหน้า $begin=(isset($id) && $id>1)?($id-1)*$config['per_page']:0; $this->db->limit($config['per_page'], $begin); $query = $this->db->get(); return $query->result_array(); } public function create(){ $config['upload_path'] = './upload/'; // โฟลเดอร์ ตำแหน่งเดียวกับ root ของโปรเจ็ค $config['allowed_types'] = 'gif|jpg|png'; // ปรเเภทไฟล์ $config['max_size'] = '0'; // ขนาดไฟล์ (kb) 0 คือไม่จำกัด ขึ้นกับกำหนดใน php.ini ปกติไม่เกิน 2MB $config['max_width'] = '1024'; // ความกว้างรูปไม่เกิน $config['max_height'] = '768'; // ความสูงรูปไม่เกิน $config['file_name'] = 'mypicture'; // ชื่อไฟล์ ถ้าไม่กำหนดจะเป็นตามชื่อเพิม $this->upload->initialize($config); // เรียกใช้การตั้งค่า $this->upload->do_upload('service_image'); // ทำการอัพโหลดไฟล์จาก input file ชื่อ service_image $file_upload=""; // กำหนดชื่อไฟล์เป็นค่าว่าง if(!$this->upload->display_errors()){ // ถ้าไม่มี error อัพไฟล์ได้ ให้เอาใช้ไฟล์ใส่ตัวแปร ไว้บันทึกลงฐานข้อมูล $file_upload=$this->upload->data('file_name'); } $newdata = array( 'service_id' => NULL, 'service_title' => $this->input->post('service_title'), 'service_detail' => $this->input->post('service_detail'), 'service_img' => $file_upload, 'service_update' => date("Y-m-d H:i:s") ); return $this->db->insert('tbl_service', $newdata); } public function view($id){ // มี $id เป็น parameter ไว้กำหนดเงื่อนไข $query = $this->db->get_where('tbl_service',array('service_id'=>$id)); return $query->row_array(); // ส่งข้อมูลผลัพธ์กลับเป็น array แถวข้อมูล } public function edit($id){ $config['upload_path'] = './upload/'; // โฟลเดอร์ ตำแหน่งเดียวกับ root ของโปรเจ็ค $config['allowed_types'] = 'gif|jpg|png'; // ปรเเภทไฟล์ $config['max_size'] = '0'; // ขนาดไฟล์ (kb) 0 คือไม่จำกัด ขึ้นกับกำหนดใน php.ini ปกติไม่เกิน 2MB $config['max_width'] = '1024'; // ความกว้างรูปไม่เกิน $config['max_height'] = '768'; // ความสูงรูปไม่เกิน $config['file_name'] = 'mypicture'; // ชื่อไฟล์ ถ้าไม่กำหนดจะเป็นตามชื่อเพิม $this->upload->initialize($config); // เรียกใช้การตั้งค่า $fileExist=$this->input->post('d_service_image'); if(file_exists($fileExist) && is_file($fileExist)){ unlink($fileExist); $file_upload=""; }else{ $file_upload=$this->input->post('h_service_image'); // เก็บชื่อไฟล์เพิมถ้ามี $fileCheck = './upload/'.$file_upload; $full_fileCheck = set_realpath($fileCheck); if(!file_exists($full_fileCheck) || !is_file($full_fileCheck)){ $file_upload=""; } } $this->upload->do_upload('service_image'); // ทำการอัพโหลดไฟล์จาก input file ชื่อ service_image if(!$this->upload->display_errors()){ // ถ้าไม่มี error อัพไฟล์ได้ ให้เอาใช้ไฟล์ใส่ตัวแปร ไว้บันทึกลงฐานข้อมูล $file_upload=$this->upload->data('file_name'); // เก็บชื่อไฟล์ใหม่ }else{ // ถ้า error ในกรณีเลือกไฟล์แล้วไม่ผ่าน if($this->upload->data('file_type')){ // เช่น ประเภทไม่ถูกต้อง return; // ต้อง return เพื่อให้แสดง error } } $newdata = array( 'service_title' => $this->input->post('service_title'), 'service_detail' => $this->input->post('service_detail'), 'service_img' => $file_upload, 'service_update' => date("Y-m-d H:i:s") ); return $this->db->update('tbl_service', $newdata,array('service_id'=>$id)); } public function delete($id){ return $this->db->delete('tbl_service', array('service_id' =>$id)); // คืนค่าผลการคิวรี่ } }
เนื้อหาตอนหน้าเรามาดู ลงลึกไปในการใช้งาน query builder ต่างๆ