分頁

分頁也是很常見的功能,我們將會以 Joomla 內部所提供的Pagination物件來協助製作分頁功能。

準備測試資料

如果你的文章數量不夠多,我們來多新增幾筆測試資料,這裡我準備了 12 筆。可以考慮用 phpMyAdmin 的複製功能快速複製。

p-2015-01-17-21.jpg

分頁原理說明

一般來說,分頁需要三個數字來做計算,分別是 本次查詢總筆數 / 單頁顯示數量 / 第幾頁 (或第幾筆開始)

在 Joomla 中,這三個數字的專有名詞叫做 total / limit / start(也有些地方會叫做 limitstart, offset ,不過以 start 最常使用)。製作分頁功能最重要的就是要能拿到這三個數字。

至於如何取得 total 呢?我們要用上一個 MySQL 的專有功能: SQL_CALC_FOUND_ROWS,把這個字串放在 select 的最開頭,他可以幫助我們計算每一次 SQL 查詢時應該要有的最大回傳數量,不受 LIMIT 影響,接著再用第二個 Query SELECT FOUND_ROWS() 就能取得 Total 數字囉。

start 則是我們每一次按下分頁按鈕時,從 requerst 中送進來的。

至於 limit 可以隨你喜好來制定,這裡我們先用 5 比較有明顯的分頁效果。你也可以抓取全站設定的預設列表數。

實作分頁查詢

首先我們還是要準備 state,只要 limit 與 start 就好,start 會從 request 送進來,limit 則當成一個固定值就好。

// administrator\components\com_blog\models\articles.php

// ...

protected function populateState()
{
    // ...

    $this->setState('list.limit', 5);
    $this->setState('list.start', $app->getUserStateFromRequest('blog.articles.start', 'limitstart'));
}
 

下一步要更改 query,把 limit 跟 start 拿出來,setQuery 時當成 2, 3 個參數送進去,db 物件會自動幫我們產生 limit 語法。別忘了要加上 SQL_CALC_FOUND_ROWS 在 select 最前面,用空格分開後續的 select 欄位。

// administrator\components\com_blog\models\articles.php

// ...

public function getItems()
{
    $db = $this->_db;

    $query = $db->getQuery(true);

    $limit = (int) $this->getState('list.limit', 5);
    $start = (int) $this->getState('list.start', 0);

    // ...

    // select 前面要加上 SQL_CALC_FOUND_ROWS
    $query->select('SQL_CALC_FOUND_ROWS *')
        ->from('#__blog_articles')
        ->order($ordering . ' ' . $direction);

    // 把 limit 跟 start 拿出來,setQuery 時當成 2, 3 個參數送進去,db 物件會自動幫我們產生 limit 語法。
    $db->setQuery($query, $start, $limit);

    // If not thing found, return empty array.
    return $db->loadObjectList() ? : array();
}
 

接著我們要在 Model 中新增一個 getPagination() 方法,一口氣把三個數字都拿出來,放進 JPagination 物件。

// administrator\components\com_blog\models\articles.php

use Joomla\CMS\Pagination\Pagination;

// ...

    public function getPagination()
    {
        $total = $this->_db->setQuery('SELECT FOUND_ROWS()')->loadResult();
        $limit = (int) $this->getState('list.limit', 5);
        $start = (int) $this->getState('list.start', 0);

        return new Pagination($total, $start, $limit);
    }

// ...
 

好了,Model 準備好了,接著我們要從 View 裡面把 pagination 物件拿出來,先更改 Articles View,執行 getPagination():

// administrator\components\com_blog\views\articles\view.html.php

// ...

public function display($tpl = null)
{
    $this->state = $this->get('State');
    $this->items = $this->get('Items');
    $this->pagination = $this->get('Pagination'); // 要在 getItems() 的後面

    $this->addToolbar();

    parent::display($tpl);
}
 

然後我們在 view template 中把 pagination render 出來,放在表格的 <tfoot> 裡面:

<?php
// administrator\components\com_blog\views\articles\tmpl\default.php

// ...
?>

<!-- ... -->

<table class="table table-striped">

    <!-- ... -->

    <tfoot>
    <tr>
        <td colspan="10">
            <?php echo $this->pagination->getListFooter(); ?>
        </td>
    </tr>
    </tfoot>
</table>

<!-- ... -->
 

一口氣完成以上這些步驟以後,分頁功能應該就會出來啦,你可以點擊看看。

p-2015-01-17-22.jpg

p-2015-01-17-23.jpg

改用其他資料庫也支援的 COUNT(*) 來計算 Total

剛剛用的 SQL_CALC_FOUND_ROWS 方式很可惜只有 MySQL 支援,接下來我們改用另外一種比較普遍的方式來計算分頁 Total。

回到 Articles Model,把 select 改回 *:

// administrator\components\com_blog\models\articles.php

// ...

public function getItems()
{
    // ...

    $query->select('*')
        ->from('#__blog_articles')
        ->order($ordering . ' ' . $direction);

    // ...

 

然後來到 getPagination(),此時 query 應該已經查詢過一次了,我們把 query 從 DB 中拿出來,這次不加 true,意味著我們要拿回之前在 getItems() 放進去的舊 query。把 select 清除後,改用 COUNT(*) 做第二次查詢。

// administrator\components\com_blog\models\articles.php

// ...

public function getPagination()
{
    // 不加 true 拿回原本的 query
    $query = $this->_db->getQuery();

    // 更改 select 成 COUNT(*)
    $query->clear('select')
        ->clear('limit')
        ->select('COUNT(*)');

    // 進行第二次查詢,拿出 total 值
    $total = $this->_db->setQuery($query)->loadResult();
    $limit = (int) $this->getState('list.limit', 5);
    $start = (int) $this->getState('list.start', 0);

    return new Pagination($total, $start, $limit);
}
 

現在可以再測試一下,應該可以正常運作。


本章節的教學內容可以在 GitHub 上找到: Code / Commits

ukash birim çevirme saç ekimi estetik