Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Pagination and sorting

When there are hundreds of posts, they are shown in parts: ten per page, with links "1, 2, 3". This is called pagination. In Yii the Pagination class calculates the number of pages and the offset, and the LinkPager widget draws the links.

Pagination in a controller

// controllers/PostController.php
use yii\data\Pagination;
 
public function actionIndex(): string
{
    $query = Post::find()->where(['status' => 1]);
 
    $pages = new Pagination([
        'totalCount' => $query->count(),
        'pageSize' => 10,
    ]);
 
    $posts = $query
        ->orderBy(['created_at' => SORT_DESC])
        ->offset($pages->offset)
        ->limit($pages->limit)
        ->all();
 
    return $this->render('index', ['posts' => $posts, 'pages' => $pages]);
}

Pagination receives the total number of rows and the page size, reads the page number from the page URL parameter and calculates offset and limit for the query.

In the view views/post/index.php print the widget after the list of posts:

<?php
// views/post/index.php
 
use yii\bootstrap5\LinkPager;
?>
 
<?= LinkPager::widget(['pagination' => $pages]) ?>

Page links appear under the list. The second page opens at /posts?page=2. If there is only one page, the widget prints nothing.

Sorting

The Sort class lets the visitor choose the order of rows:

use yii\data\Sort;
 
$sort = new Sort([
    'attributes' => ['title', 'created_at'],
    'defaultOrder' => ['created_at' => SORT_DESC],
]);
 
$posts = Post::find()->orderBy($sort->orders)->all();

attributes lists the columns that may be used for sorting. Pass $sort to the view and print a link: <?= $sort->link('title') ?>. A click on it opens /posts?sort=title, a second click /posts?sort=-title with the reverse order.

The data provider

ActiveDataProvider joins a query, pagination and sorting in one object:

use yii\data\ActiveDataProvider;
 
public function actionIndex(): string
{
    $dataProvider = new ActiveDataProvider([
        'query' => Post::find()->where(['status' => 1]),
        'pagination' => ['pageSize' => 10],
        'sort' => ['defaultOrder' => ['created_at' => SORT_DESC]],
    ]);
 
    return $this->render('index', ['dataProvider' => $dataProvider]);
}

You no longer count rows or set offset by hand.

CallWhat it returns
$dataProvider->getModels()The posts of the current page
$dataProvider->getTotalCount()The total number of posts
$dataProvider->paginationThe Pagination object for LinkPager
$dataProvider->sortThe Sort object

The data provider is the basis of the ready-made tables and lists covered in the lesson on data widgets.

Common mistake

Do not call all(), limit() or offset() on the query for a data provider. It needs a query that has not run yet: it counts the rows and adds the limits itself. Passing Post::find()->all() causes an error, because that is already an array, not a query.

Thanks for reading!

Donate to the site — we work hard for you.