PHP Pagination with a Collection Class
Recently in my work I had begun using some of the code offered from WROX’s Professional PHP 5 book. Earlier, I even wrote about the UserSession class that I ported from PHP 5 to ASP 3.
It’s been in my experience with WROX’s code that one of the most invaluable classes that I couldn’t live without is the Collection (and associated CollectionIterator) class. The Collection class, as it sounds, essentially lets you build a collection of any type of variables or objects you desire (a Collection of arrays, or integers, or more commonly GenericObjects — also from the WROX code).
The Collection class also implements the CollectionIterator class, which itself implements the native Iterator interface, allowing for seamless looping:
<php
$colIntegers = new Collection();
// fill it:
for ($i = 0; $i < 50; $i++) $colIntegers->addItem($i, $i);
// and reiterate back through the collection just as easily:
foreach($colIntegers as $integer) print $integer;
?>
As great as this was, it needed pagination in order to be more useful. Included in the WROX code was a GenericObjectCollection class which offered some pagination, but I hated the idea of having to switch back and forth between standard Collections and GenericObjectCollections, so I added a few methods to each the Collection and CollectionIterator class to allow for some hacked-up pagination. You can download the code below:
collectionandinterator.php.txt (Plain Text Format, 355 lines, 8.8kb)
It may certainly be beneficial to split the classes up into two separate files. There’s a bit too much code to analyze properly here, and make note of everything that I modified, but here’s a quick list of changes:
Collection
- Added
$per_pageproperty: indicates how many items in theCollectionfor each desired page. - Added
$page_numberproperty: specifies the current page number - Added
canPaginate()method: indicate whether theCollectionhas all required data (per_page, page_number) for paginating properly - Added
paginate()method: Called prior to iterating, sets up theCollectionfor proper pagination, by providing per_page and page_number values. - Added
per_page(),page_number(), andnum_pages()methods: Return the number of items per page, the current page number, and the number of pages based on total items respectively. - Added
pageMenu()method: Creates and prints a basic HTML menu listing off page numbers, each as links to the specified page, with the current page highlighted in bold.
There are some changes to the CollectionIterator class as well:
CollectionIterator
- Added
$_currPosproperty: keeps track of which element of the current page is currently in iteration - Added
goToPage()method: “fast-forwards” theCollectionIteratorto the appropriate starting position for the current page, as indicated byCollection::page_number() - Modified
rewind()method: If pagination is available, goes back to the start of the current page rather than back to the beginning of the entireCollection - Modified
next()method: Added$ignoreparameter which, if enabled, does not count towardspage_numberitems as it iterates towards the appropriate starting position (seeCollectionIterator::goToPage()). If$ignoreis false, it properly iterates through items of the current page, while keeping track of the number if items it’s iterated through ($_currPos), ensuring it’s still within the bounds of the page (Collection::per_page()). If it reaches the end of the items of that page, it simply stop any iteration by moving the$_currIndexbeyond the bounds ofCollection::length()(makingCollectionIterator::valid()return false, thus exiting any loops).
To use in context, here’s a quick example:
<php
/* create collection, fill it with items */
$colIntegers->paginate(5, (int) $_GET["p"]);
$colIntegers->pageMenu($_SERVER["REQUEST_URI"]);
print "<ul>\n";
foreach($colIntegers as $integer) {
print "<li>{$integer}</li>";
}
print "</ul>\n";
?>
This will simply use the Collection of integers, as created above, and create a paginated list, with 5 integers per “page”.
Nothing extravagant. It’s pretty quick and dirty in fact. If you’re not familiar with the WROX code where these classes originated, it’s definitely worth checking out and getting to use them. They’re extremely useful, and hopefully I just made it a little more useful.