2.3 Pagination

What is pagination?

One of the commonest situations in a system is the need to list several data, like an user list for example. But sometimes this list is too big to be displayed just in only one page, because of this we split the results in separated pages. This is what we call pagination.

To do a list pagination we need to think about some details:

  • We need to build the query on database;
  • Define pagination parameters;
  • Number of items per page,
  • Number of links on each page,
  • Number of the current page
  • Build the HTML for show the results;

Database query (SQL)

To create the pagination the building of the query SQL does not must to have any change, the only one change is that on the return from Gateway must to be the pagination object from SuitUp which is the method paginate from db instance, it means return $this->db->paginate($query);.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
namespace ModuleDefault\Model\Gateway;

use SuitUp\Database\Gateway\AbstractGateway;

class User extends AbstractGateway
{
    protected $name = 'user';
    protected $primary = array('pk_user');

    /**
     * Generate the paginated users list
     * 
     * @param array $filters Filters list
     * @return SuitUp\Paginate\Paginate
     */
    public function listUsers(array $filters = array()) {

        $query = $this->select("SELECT u.* FROM {$this->name} u")
            ->columns(array(
                'id_user' => 'id',
                'name',
                'age',
                'document',
                'email',
            ))
            ->innerJoin("profile p", "p.id_profile = u.id_profile")
            ->innerJoin("sector r", "r.id_sector = p.id_sector")
            ->where("u.status = 1");

        if (isset($filters['sector']) && $filters['sector']) {
            $query->where("r.id_sector = ?", $filters['sector']);
        }

        // This line is what really make the splitting of the results.
        return $this->db->paginate($query);
    }
}

Pagination parameters

From the controller is possible to change some default values from pagination like quantity of the page items, quantity of links of the other pages and the number of the current page. Isn't need to change this configurations, but you can do it if default values is not appliable to your needs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
namespace ModuleDefault\Controllers;

use ModuleDefault\Model\UserBusiness;

class UserController extends AbstractController
{
    public function indexAction()
    {
        $filters = $this->getPost();

        // Realize that's not the GATEWAY
        // See why it is need in
        // https://github.com/braghimsistemas/suitup-php/wiki/5.-Database#business-rules

        $userBo = new UserBusiness();
        $list = $userBo->listUsers($filters);

        /** Here you can change the pagination configs if want. That not required **/

        // Number of the links for other pages
        $list->setPageRange(7); // Default is 5

        // Current page number
        $list->setCurrentPage($this->getParam('page', 1)); // default = $_GET['pagina']

        // Items per page numbers
        $list->setNumberPerPage(100); // Default = 50

        $this->addViewVar(array(
            'list' => $list
        ));
    }
}

Realize that above there is a solution to a problem that can give you nightmares, is the name of the parameter pagina (which means 'page' in portuguese). Remember that to change it is need to change on the HTML pagination file too.

Default parameters

  1. The system gets $this->getParam('pagina', 1); to know what is the current page.
  2. The page range is 5. This is the number of links to other pages which will appear to the user choose.
  3. Quantity of the rows to the list per page is 50.

Pagination object methods

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// Change the total number of itens which will appear on page list to select
public function setPageRange($pageRange);

// Gets the number total of items which appear on the list to select the page
public function getPageRange();

// Indicates the current page number
public function setCurrentPage($currentPage);

// Return the current page number.
public function getCurrentPage();

// Set number of results from query which will appear on each page.
public function setNumberPerPage($numberPerPage);

// Get number of results from query which will appear on each page.
public function getNumberPerPage();

// Total number of pages that this query will return.
public function getTotalPages();

HTML

Showing the result

On the HTML the pagination object can be used with a foreach with no problems.

Pages

To show the pages just write the following code on your HTML.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<!-- Your list HTML -->
<table class="table table-striped">
    <tr>
        <td>ID</td>
        <td>Nome</td>
    </tr>
    <!-- $list is the pagination instance -->
    <?php foreach($list as $key => $item): ?>
        <tr>
            <td><?php echo $item['id']; ?></td>
            <td><?php echo $item['nome']; ?></td>
        </tr>
    <?php endforeach; ?>
</table>
<!-- /end table -->

<!-- Pagination links -->
<?php echo paginateControl($list); ?>

Pagination HTML

Add the following file to the ModuleDefault/views/paginacao.phtml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php if(count($items)): ?>
    <nav>
        <ul class="pagination">
            <?php if($previousPage): ?>
                <li><a href="<?php echo $baseUrl; ?>page=<?php echo $previousPage; ?>" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
            <?php else:?>
                <li class="disabled"><a href="javascript:void(0);" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
            <?php endif; ?>

            <?php foreach($items as $key => $page): ?>
                <?php if($page != $currentPage): ?>
                    <li><a href="<?php echo $baseUrl; ?>page=<?php echo $page; ?>"><?php echo $page; ?></a></li>
                <?php else: ?>
                    <li class="active"><a href="javascript:void(0);"><?php echo $page; ?> <span class="sr-only">(current)</span></a></li>
                <?php endif; ?>
            <?php endforeach; ?>

            <?php if($nextPage): ?>
                <li><a href="<?php echo $baseUrl; ?>page=<?php echo $nextPage; ?>" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>
            <?php else:?>
                <li class="disabled"><a href="javascript:void(0);" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>
            <?php endif; ?>
        </ul>
    </nav>
<?php endif; ?>

Remember that to change the parameter pagina is necessary to capture this new parameter on the controller with $this->('page', 1);. See an example here.