Trang

Thứ Năm, 18 tháng 7, 2013

Phân trang cơ bản với Zend_Paginator [Zend Framework]

Phân trang là kỹ thuật có lẽ đã không còn xa lạ gì với những ai đã và đang viết web. Việc phân trang sẽ giúp cho ứng dụng của bạn thao tác nhanh hơn và gọn hơn mỗi khi đổ dữ liệu ra bên ngoài, vì thế có thể xem nó là một lớp quan trọng trong mọi ứng dụng hiện nay.
I. Lý thuyết:

1. Khởi tạo đối tượng:


   $all = array(); // mảng dữ liệu cần phân trang
   $pa = Zend_Paginator::factory($all);

2. Bảng các thuộc tính

Các thuộc tính này có tác dụng tại file tạo hiển thị điều khiển phân trang.


3. Bảng các phương thức cấu hình



4. Các dạng hiển thị khi click chuyển trang
- Jumping: chỉ chọn các trang đang hiển thị, muốn sang nhóm khác phải click next

- Sliding: tự động tiến tới một trang so với trang được chọn (đang 1 2 3 chọn 3 thì sẽ hiện 2 3 4). (Giống phân trang kết quả tìm kiếm của Google, thường hay dùng cách này).

- Elastic: Hiển thị hai trang đầu, hai trang cuối.

- All: Hiện thị tất cả các trang.

5. Tạo cache khi phân trang

Một nhược điểm của Zend_Paginator là nó mang theo toàn bộ dữ liệu lấy ra để phân trang để mang từ trang này sang trang khác, chứ không phải dùng từ khóa limit trong câu SQL, điều này làm cho site của chúng ta chậm lại. Tuy nhiên, chúng ta có thể cải thiện điều này bằng việc tạo cache cho các trang. Khi ghé thăm mỗi trang, chúng ta sẽ cache lại và mỗi lần ghé thăm sau chúng ta không cần phải làm lại mọi việc từ đầu.

Thực hiện tạo cache:
Bước 1: Vào thư mục public tạo một thư mục tên tmp

Bước 2: Thực hiện cài đặt các thông số cho phân trang.

Bước 3: Tạo cache và khởi động cache cho phân trang
$fO = array('lifetime' => 3600, 'automatic_serialization' => true);
$bO = array('cache_dir'=>APPLICATION_PATH.'/../public/tmp');
$cache = Zend_Cache::factory('Core', 'File', $fO, $bO);
Zend_Paginator::setCache($cache);
$pa->getCurrentItems();

lifetime: thời gian sống của cache(ms)
cache_dir: nơi lưu cache

II. Thực hiện: Liệt kê các bài viết có phân trang

Bước 1: Tạo Model
Tạo trang chitiettin.php trong models với nội dung:
<?php
  class Model_Chitiettin extends Zend_Db_Table_Abstract
   {
       protected $_name="chitiettin";
       protected $_primary="idTin";
       protected $_db;
       
       public function __construct()
        {
            $this->_db=Zend_Registry::get('db');
        }

        public function getTin()
         {
            $se=$this->select();
            $kq=$this->fetchAll($se);
            if($kq)
            { return $kq->toArray(); }else{ return false; }
         }
   }
?>

Bước 2: Viết Controller
Trong Controller ta tạo gettinAction() với nội dung
public function gettinAction()
 {
     $ctt=new Model_Chitiettin();
     $getTin=$ctt->getTin();
     
      //phan trang
      $pa=Zend_Paginator::factory($getTin);
      $pa->setItemCountPerPage(4); // so bai viet tren moi trang la 4
      $pa->setPageRange(5); // so trang hien thi trong dieu khien phan trang la 5 
      $current = $this->_request->getParam('page',1); // lay trang, mac dinh luc dau la trang 1
      $pa->setCurrentPageNumber($current); // lay du lieu cua trang hien hanh

      //view
      $this->view->pa=$pa;
 }

Bước 3: Hiển thị tại View
Tạo file gettin.phtml trong views/scripts/index với nội dung
<div class="phantrang">
<?php
foreach($this->pa as $item)
 {?>
   <div><?php echo $item['TieuDe'] ?></div>
 <?php }
?>

<?php
    echo $this->paginationControl($this->pa,'Sliding','control.phtml');  
?>

</div>

Ta thấy ở phần cuối có đoạn:
<?php
    echo $this->paginationControl($this->pa,'Sliding','control.phtml');  
?>

Đây là phần ta nạp 1 file phtml với mục đích hiển thị các liên kết tới, lùi, số trang của ứng dụng. Hay còn gọi là điều khiển phân trang.

Tại views/scripts/ ta tạo 1 file control.phtml với nội dung
<?php if ($this->pageCount): ?>
<div class="paginationControl">

<!--hien thi so item dang hien thi trong tong so item-->
<span class="thongke_pa" >
<?php echo $this->firstItemNumber ?> - <?php echo $this->lastItemNumber ?> of <?php echo $this->totalItemCount ?>
</span>

<!--First page link-->
<?php if($this->first == $this->current ): ?>
    <!--<span class="disabled" > First </span>-->
<?php else: ?>
     <a class="tk_pre" href="<?php echo $this->url(array('page'=>$this->first)); ?>" > First </a>
<?php endif; ?>
 
<!-- Previous page link -->
<?php if (isset($this->previous)): ?>
  <a class="tk_pre" href="<?php echo $this->url(array('page' => $this->previous)); ?>">
   &lt; Previous
  </a>  
<?php endif; ?>
 
<!-- Numbered page links -->
<?php foreach ($this->pagesInRange as $page): ?>
  <?php if ($page != $this->current): ?>
    <a class="tk_page_0" href="<?php echo $this->url(array('page' => $page)); ?>">
        <?php echo $page; ?>
    </a> 
  <?php else: ?>
     <span class="disabled_page"><?php echo $page; ?></span> 
  <?php endif; ?>
<?php endforeach; ?>
 
<!-- Next page link -->
<?php if (isset($this->next)): ?>
  <a class="tk_next" href="<?php echo $this->url(array('page' => $this->next)); ?>">
    Next &gt;
  </a>
<?php endif; ?>


<!--Last page link-->
<?php if($this->last == $this->current): ?>
   <!--<span class="disabled" > Last </span>-->
<?php else: ?>
   <a class="tk_pre" href="<?php echo $this->url(array('page'=>$this->last)); ?>" > Last </a>
<?php endif; ?>

</div>

<?php endif; ?>

Css cho file điều khiển phân trang control.phtml
/*phan trang*/
 /*dinh dang link phan trang*/
   .paginationControl{overflow:hidden;background-color:#FFF;height:40px;line-height:40px}
.thongke_pa{font-weight:bold;padding:10px 10px 10px 10px;background-color:#06F;color:#FFF;
                border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
            }
.paginationControl a.tk_pre:link, .paginationControl a.tk_pre:visited{background-color: #06F;color:#FFF;font-weight:bold;margin-right:4px ;
       border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
    padding:10px 10px 10px 10px;
    }
.paginationControl a.tk_pre:hover{background-color:#F90;color:#FFF}

.paginationControl a.tk_page_0:link, .paginationControl a.tk_page_0:visited{background-color:#06F;color:#FFF;font-weight:bold;margin-right:4px; 
       border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
    padding:10px 15px 10px 15px;
    }
.paginationControl a.tk_page_0:hover{background-color:#F90;color:#FFF}

.paginationControl a.tk_next:link, .paginationControl a.tk_next:visited{background-color:#06F;color:#FFF;font-weight:bold;margin-right:4px ;
       border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
    padding:10px 15px 10px 15px;
    }
.paginationControl a.tk_next:hover{background-color:#F90;color:#FFF}
.paginationControl .disabled {background-color: #BAD3ED;color:#FFF;font-weight:bold;margin-right:4px ;
       border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
    padding:10px 15px 10px 15px;
    }
.paginationControl .disabled_page {background-color:#BAD3ED;color:#FFF;font-weight:bold;margin-right:4px ;
       border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
    padding:10px 15px 10px 15px;
    }    
 /*End dinh dang link phan trang*/
/*end phan trang*/

Bước 4: Xem kết quả:



Tối ưu hóa phân trang

Như đã nói ở trên, Zend_Paginator sẽ mang toàn bộ dữ liệu từ trang này sang trang khác để phân trang. Điều này trên thực tế thì chỉ có thể đáp ứng được với mô hình dữ liệu nhỏ, vì nếu dùng với hàng trăm ngàn dòng dữ liệu thì có lẽ việc đem chúng đổ vào mảng thôi cũng là điều không đơn giản.

Chúng ta sử dụng thêm phương thức bên dưới với các tham số truyền vào, trước khi gọi lớp Zend_Paginator.
new Zend_Paginator_Adapter_DbSelect();
Chúng ta sẽ sửa lại một số chỗ như sau:
Trong Model:
<?php
  class Model_Chitiettin extends Zend_Db_Table_Abstract
   {
       protected $_name="chitiettin";
       protected $_primary="idTin";
       protected $_db;
       
       public function __construct()
        {
            $this->_db=Zend_Registry::get('db');
        }

        public function getTin()
         {
           $se=$this->_db->select()
                       ->from('chitiettin',array('idTin','TieuDe','TieuDe_KhongDau'));
           return $se;
         }
   }
?>
Chúng ta sẽ truy vấn với Zend_Db_Select, không fetchAll() dữ liệu nữa mà đơn giản chỉ việc chọn bảng, chọn số lượng cột để hiện thị. Kết quả trả về ở đây là một đối tượng Zend_Db_Select

Trong Controller:
public function gettinAction()
 {
     $ctt=new Model_Chitiettin();
     $getTin=$ctt->getTin();
     
      //phan trang
      $adapter = new Zend_Paginator_Adapter_DbSelect($getTin);
      $pa = new Zend_Paginator($adapter);

      $pa->setItemCountPerPage(4); 
      $pa->setPageRange(5); 
      $current = $this->_request->getParam('page',1); 
      $pa->setCurrentPageNumber($current); 

      //view
      $this->view->pa=$pa;
 }
Ta tạo một adapte bằng cách truyền kết quả trả về từ Model vào lớp Zend_Paginator_Adapter_DbSelect . Tại đó, tự nó sẽ biết phải lấy dữ liệu như thế nào. Cuối cùng, thay vì ta dùng Zend_Paginator::factory() thì nay ta khởi tạo hẳn một phương thức và truyền dữ liệu mà ta đã cấu hình ở trên vào.

Tới đây ta có thể sử dụng thêm cache để tối ưu hóa việc phân trang.

Phân trang cache dữ liệu
Chúng ta sẽ viết lại ứng dụng phân trang trên nhưng sẽ thêm phần cache vào ứng dụng. Các bước thực hiện tương tự như trên, riêng bước tạo action của controller ta viết lại như sau:
public function gettinAction()
 {
    $ctt=new Model_Chitiettin();
    $getTin=$ctt->getTin();

    //phan trang
     $adapter = new Zend_Paginator_Adapter_DbSelect($getTin);
     $pa = new Zend_Paginator($adapter);

     $pa->setItemCountPerPage(4);
     $pa->setPageRange(5);
     $current = $this->_request->getParam('page',1);
     $pa->setCurrentPageNumber($current);

    //cache
    $fO = array('lifetime' => 3600, 'automatic_serialization' => true);
    $bO = array('cache_dir'=>APPLICATION_PATH.'/../public/tmp');
    $cache = Zend_Cache::factory('Core', 'File', $fO, $bO);
    Zend_Paginator::setCache($cache);
    $pa->getCurrentItems();

     //view
     $this->view->pa=$pa;
 }
Tiếp theo vào thư mục public tạo một thư mục tên tmp.

Tới đây các bạn đã làm quen và tìm hiểu được lớp Zend_Paginator, từ đó sử dụng chúng cho công việc phân trang dữ liệu trong ứng dụng. 
Nguồn: Sưu tầm Internet

Không có nhận xét nào:

Đăng nhận xét