2014年6月20日 星期五

yii framework - 分頁功能要怎麼做? 運用CPagination+CLinkPager

分頁是一個網站的常見功能, 所以勢必要學會如何使用! 那我們開始吧!


首先是Controller的部分:
function actionIndex(){
    $criteria = new CDbCriteria();
    $count=Article::model()->count($criteria);
    $pages=new CPagination($count);

    $pages->pageSize=10;
    $pages->applyLimit($criteria);
    $models = Post::model()->findAll($criteria);

    $this->render('index', array(
    'models' => $models,
         'pages' => $pages
    ));
}

說明:
1. CDbCriteria把你要抓的資料條件都設好 ( 查詢資料大解密之"CDbCriteria到底是什麼? )
2. count得到符合條件的資料筆數
3. 把得到的資料筆數丟到CPagination
4. pageSize設定每個分頁要顯示幾筆
5. applyLimit 設定SQL的limit跟offset, 來得到當下選擇的分頁資料 ( 官方的applyLimit-detail說明 )
6. 將$pages渲染 (render)到view去

再來是View的部分:
<?php foreach($models as $model): ?>
    // 顯示一個模型
<?php endforeach; ?>

// 顯示分頁
<?php $this->widget('CLinkPager', array(
    'pages' => $pages,
)) ?>

1. 輸出你的資料
2. 使用小工具widget的CLinkPager來顯示分頁按鈕 (超屌的) ( 官方的CLinkPager說明 )


以我目前的需求, 配置如下:

$this->widget('CLinkPager', array(
'header' => '',
'prevPageLabel' => '上一頁',
'nextPageLabel' => '下一頁',
'pages' => $pages,
'maxButtonCount' => 10
));

1. header -> 在分頁按鈕上多行文字說明
2. prevPageLabel nextPageLabel -> 不用多說了吧!
3. pages -> 返回此分頁的分頁訊息
4. maxButtonCount -> 顯示的最多分頁按鈕數


上面內容引用自官方說明 (中文):

接下來才是重點:
講到這, 如果你有google過的話, 你會發現都大同小異吧!因為網路上幾乎都不講原裡的.

運作原理:
applyLimitlimit跟offset, 其實指的是每個分頁的資料數跟移到開始抓資料的基準點 (大陸翻譯偏移量, 鬼看的懂阿!可能我資質不好吧~)

ex: 
總資料數有32筆, 我們的pageSize設為5, 那就會有7個分頁.
然後當我們按第三個分頁的時候 (ex: index.php?r=food/list&page=3), 程式就會將位置 (基準點)移到第10筆, 然後開始抓5筆, 所以就會得到11~15的資料了!

你也許會想說為什麼位置會移到第10筆呢?問的好, 有好奇心, 答案就在這

我們先看看applyLimit的code

public function applyLimit($criteria)
{
    
$criteria->limit=$this->getLimit();
    
$criteria->offset=$this->getOffset();
}


我們接著看getLimit()

public function getLimit()
{
    return 
$this->getPageSize();
}


再看看getPageSize()

public function getPageSize()
{
    return 
$this->_pageSize;
}


哦~ 原來就是我們設定的pageSize嘛~ 也就是"5".

ok, good~ 我們再來乘勝追擊, 來查查看getOffset()

public function getOffset()
{
    return 
$this->getCurrentPage()*$this->getPageSize();
}


哦~ 所以是getCurrentPage()乘上5

getCurrentPage()是什麼呢?

public function getCurrentPage($recalculate=true)
{
    if(
$this->_currentPage===null || $recalculate)
    {
        if(isset(
$_GET[$this->pageVar]))
        {
            
$this->_currentPage=(int)$_GET[$this->pageVar]-1;
            if(
$this->validateCurrentPage)
            {
                
$pageCount=$this->getPageCount();
                if(
$this->_currentPage>=$pageCount)
                    
$this->_currentPage=$pageCount-1;
            }
            if(
$this->_currentPage<0)
                
$this->_currentPage=0;
        }
        else
            
$this->_currentPage=0;
    }
    return 
$this->_currentPage;
}

恩...有點長,

說明一下:
這支程式會GET我們前端傳來的page變數, 我查過發現pageVar預設的就是page這個變數名. 然後getPageCount()的code如下:

public function getPageCount()
{
    return (int)((
$this->_itemCount+$this->_pageSize-1)/$this->_pageSize);
}


itemCount是我們new CPagination($count)的$count值, 依我們的舉例就是32.
(32+5-1)/5 = 7.2 也就符合我們前面說的7個分頁.

如果page傳來的是7那_currentPage就是6, 6沒有大於7.2也沒有小於0, 所以getCurrentPage就直接返回6.

在回到getOffset(), 6*5=30, 所以就會從30開始抓5筆, 由於我們總資料只有32筆,  所以第7個分頁只會有2筆資料顯示.

把yii的code翻了個底朝天才終於搞清楚來龍去脈, 呼~ 真是各種折騰啊T.T, 不過完全搞清楚的感覺真的好爽, 哈哈哈哈.



最後:
我當時試半天搞不定的原因是, 當我按下分頁的時候, 當初的搜尋條件沒有跟著帶過去, 所以抓不到資料、出錯! 最後我是用Cookie將那些條件存起來, 要用的時候再拿出來, 這樣就解決嘍!

不過記得, 如果是重要的資料千萬不要存到Cookie裡喔^^

不過yii真的好厲害, 把分頁這樣的東西封裝成這麼好操作的物件, 真的很屌^^

好東西:
這個是國外大大寫的線上範例 (可操作, 會更好理解!)
http://www.yiiplayground.com/index.php?r=UiModule/pagination/basicPager

沒有留言:

張貼留言