Posts Tagged ‘Web Development’

Pagination component for the Skeleton Framework

Sunday, July 19th, 2009

Arborint and I have been hard at work on a pagination component that can be used standalone or as part of the Skeleton framework. We’re looking for feedback from other developers, so take a look and let us know what you think.

Executive Summary
We made these classes first and foremost to make it drop-dead easy to paginate data. Our goal was not to make a one size fits all solution, but rather to provide a layered range of solutions in which developers can pick and choose to tailor the classes to their needs.

Specific Goals

  • Account for as many use cases as possible
  • Stay flexible for extendability
  • Take care of the messy details of pagination: url generation, maintaining state, dealing with the request.

Basics
The base object in this pagination system is a Value Object that holds the values for the list and does the necessary calculations. This class can be used alone, but you are required to initialize it.

$pager = new A_Pagination_Core($datasource);
$pager->setCurrentPage(intval($_GET['mypagevar']));
$pager->setNumItems(intval($_GET['mycountvar']));

This component also provides a class that extends the Core class and initializes itself from the request so you don’t have to. This class adds a process() method that will initialize the object for you:

$pager = new A_Pagination_Request($datasource);
$pager->process();

This Core object does the necessary calculation and will return page numbers for the current first, last, next and previous pages, plus a range of page numbers around the current page. These are intended to provide the basic functionality on which to build classes to render paginated output.

This class takes a Datasource object passed to the constructor. These Datasources comply to a simple Adapter interface. This component will provide Adapters for arrays, PDO, MySQL, etc. A getItems() method is provided to retrieve the records for the currently displayed page.

The basic methods in its interface are:

class A_Pagination_Core {
function __construct($datasource)
function isPage($number)
function getPage($number)
function getCurrentPage()
function getFirstPage()
function getLastPage()
function getPageRange()
function getNumItems()
function getItems()
}

This component is not monolithic. There are several levels of classes that use a Core object and provide support for rendering output. The lowest level of output support uses page numbers from a Core object and builds URLs. Using this class you can have complete control of your template:

$url = new A_Pagination_Helper_Url($pager);
$out .= ‘<a href=”‘ . $url->previous() . ‘”>Prev</> “;
$out .= ‘<a href=”‘ . $url->next(’Next’) . ‘”>Next</> “;

The next level of output support uses page numbers from a Core object and builds complete links (<a> tags). You an pass the name of a CSS class to this object to control link style:

$link = new A_Pagination_Helper_Link($pager);
$out .= $link->previous(’Prev’, ‘mylinkclass’);
$out .= $link->next(’Next’, ‘mylinkclass’);

Use Case Example
Here is an example of combining the classes to do a basic paginated list with links:

// create a data object that has the interface needed by the Pager object
$datasource = new Datasource();

// create a request processor to set pager from GET parameters
$pager = new A_Pagination_Request($datasource);

// initialize using values from $_GET
$pager->process();

// create a “standard” view object to create pagination links
include ‘A/Pagination/View/Standard.php’;
$view = new A_Pagination_View_Standard($pager);

// display the data
echo ‘<table border=”1″>’;
foreach ($pager->getItems() as $row) {
echo ‘<tr>’;
echo ‘<td>’ . $row['id'] . ‘</td><td>’ . $row['name'] . ‘</td>’;
echo ‘</tr>’;
}
echo ‘</table>’;

// display the pagination links
echo $view->render();

Additional Features

  • There are a number of examples that show different ways the classes can be used — from do-it-yourself to standalone.
  • There is support for ORDER BY functionality to sort the list. There are methods to generate column heading links to sort any column ascending/descending. Sort order is maintained while paging.
  • The total number of items in the datasource is persisted RESTfully so, for example, COUNT() is only called one for database datasources.
  • Request parameter names can be changed to remove conflicts and allow multiple pagers on one page.
  • Pagination state values can be saved in the session if you want to be able to resume in the list where you left off — when editing records in CRUD for example.

Feedback Wanted

  • Do these classes provide everything you need for pagination?
  • What modifications would you make before using this in a project?
  • What can we do to improve the code?

Discussions

This component is being discussed on two forums: SitePoint and the DevNetwork. Feel free to join in the discussion.

DataGrid
For the most automated use case, we will be providing a DataGrid that takes care of all HTML once the core classes have been finalized.