Zend_Paginator
Zend_Paginator 是 Zend Framework 1.6 的新功能之一
是用來提供作資料分頁的 Component,雖然分頁是個簡單的小功能,可是有時候自己寫又嫌麻煩,所以拿現成的元件來套用也蠻方便的。
Controller
要使用 Zend_Paginator 前,要知道 Zend_Paginator 支援下列四種方式:
- Array – 將資料集合以 Array 的形式傳入。
- DbSelect – 將資料庫查詢所需的 Select Query 以 Zend_Db_Select 或字串的形式傳入,會根據 Query 向 DB 抓取對應所需的資料。
- Iterator – 傳 Iteraotr ,沒仔細看,不過使用上應該跟 Array 差不多。
- Null – 不處理資料,只用來處理分頁控制的部份。
以 Array Adapter 為例,在 Controller 裡可以用
$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_Array($array));
或是透過 factory pattern
$paginator = Zend_Paginator::factory($array);
接著設定頁數及每頁項目數量
$paginator->setCurrentPageNumber($page) ->setItemCountPerPage($numPerPage); // Default is 10 $this->view->paginator = $paginator;
View
而顯示的部份則交由 view script 來處理。這 View 的處理可分為兩個部份,一個是資料項目的顯示,另一個是分頁功能表的顯示。
資料項目的部份,由於 Zend_Paginator 實做 SPL 的 IteratorAggregate 介面,所以可以使用 foreach() 很方便地來詢訪資料項目。
分頁功能表(用來選擇上一頁、下一頁、或跳頁的控制像) 則透過 paginationControl() 這個 View Helper 來處理
以下為範例的程式碼
<html><body> <h1>Example</h1> <?php if (count($this->paginator)): ?><ul> <?php foreach ($this->paginator as $item): ?> <li><?= $item; ?></li> <?php endforeach; ?> </ul><?php endif; ?> <?= $this->paginationControl($this->paginator, 'Sliding', 'my_pagination_control.phtml'); ?></body></html>
Zend_Paginator 預設提供四種 Scrolling (捲頁) Style: All、Elastic、Jumping和Sliding。Elastic 和 Sliding分別是 Google 和 Yahoo,不過除了 Elastic 會列出比較多頁數以外,我感覺好像沒什麼差別,下面這是 Sliding Style 的例子:
![]()
All 則是會把所有頁數全部列出來,可以用在使用 select box 選擇頁數的時候。
Manual 裡除了範例程式外,還提供了幾個常用的分頁控制項的的例子,其中有提到 YDN 的一些資源,是有關一些 UI 或 Web UI 常見的 pattern,還蠻不錯的,可以參考看看
Advance
再來討論一些我遇到的問題跟解決方法
第一個是 Zend_Db_Table 和 Zend_Paginator 的配合,目前雖然有 DbSelect Adapter 可以用,不過傳回來的東西會是 Array,但是因為我把一些邏輯寫在 Zend_Db_Table_Row 裡面,所以希望資料項目能是 Zend_Db_Table_Rowset 或 Zend_Db_Table_Row,所以有人寫了Paginator_Adapter_DbTable ,改寫 getItem() 的部份,透過 Zend_Db_Table 去作 fetchAll(),不過這個 Adapter 目前還沒有被官方正式採納,所以我就改成使用 Null Adapter 並且自己管理 Data Item。
$select = $table->select(); $select->where(...)->limitPage($page, $numPerPage); $data = $table->fetchAll($select); $selectCount = $table->select(); $selectCount->from(array("t"=>"table"), array("cnt"=>'COUNT(*)')->where(...); $cnt = $table->fetchRow($selectCount); $paginator = Zend_Paginator::factory($cnt); $paginator->setCurrentPageNumber($page) ->setItemCountPerPage($numPerPage);
再來另外一個問題是有關 Zend_Db_Table 的 Relationship Operation,前面我自己寫兩次 Query 分別去取得資料跟總數已經是個爛方法了,可是如果我要用的資料是透過 findManyToManyRowset() 得到的,那就有問題了,似乎不能使用 from() 去設定 COUNT(*)。
在 Google 上查查看,找到這個作法,發現在呼叫完 findManyToManyRowset() 之後,$select 會被改寫成包含 (inner) join 的 SQL Query,所以我可以拿著這個 $select 去請 Zend_Paginator 幫我處理總資料數目。裡面提到會發生 Exception 的問題似乎已經解決了,所以直接用就可以了
$bugsTable = new Bugs(); $bugsRowset = $bugsTable->find(1234)->current(); $select = $bugsTable->select(); $select->where(...)->limitPage($page, $numPerPage); $productsRowset = $bug1234->findManyToManyRowset('Products', 'BugsProducts', null, null, $select); $paginator = Zend_Paginator::factory($select); $paginator->setCurrentPageNumber($page) ->setItemCountPerPage($numPerPage);
另外原來自己查詢 COUNT(*)使用 Null Apdapter 的作法也可以同樣換掉
$select = $table->select(); $select->where(...)->limitPage($page, $numPerPage); $data = $table->fetchAll($select); $paginator = Zend_Paginator::factory($select); $paginator->setCurrentPageNumber($page) ->setItemCountPerPage($numPerPage);
這樣的作法在 Controller 中看起來會滿簡潔的,不過我不確定在校能上會不會有問題,例如說是多做了一次 Query、或是每次都查詢所有的資料。
參考資料
- Zend_Paginator and Zend_Db_Table
- Clear limitoffset and limitcount parts in Dbselect adapter when getting the total items count
- Join Problems with Zend_Paginator and Zend_Db_Select objects
相關文章:
Related posts brought to you by Yet Another Related Posts Plugin.
九月 14th, 2008 at 6:15 下午
[...] Zend_Paginator [...]
十一月 18th, 2008 at 3:20 下午
[...] support for Zend_Paginator, 應該是我之前想要的那個功能吧 [...]