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_page property: indicates how many items in the Collection for each desired page.
  • Added $page_number property: specifies the current page number
  • Added canPaginate() method: indicate whether the Collection has all required data (per_page, page_number) for paginating properly
  • Added paginate() method: Called prior to iterating, sets up the Collection for proper pagination, by providing per_page and page_number values.
  • Added per_page(), page_number(), and num_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 $_currPos property: keeps track of which element of the current page is currently in iteration
  • Added goToPage() method: “fast-forwards” the CollectionIterator to the appropriate starting position for the current page, as indicated by Collection::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 entire Collection
  • Modified next() method: Added $ignore parameter which, if enabled, does not count towards page_number items as it iterates towards the appropriate starting position (see CollectionIterator::goToPage()). If $ignore is 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 $_currIndex beyond the bounds of Collection::length() (making CollectionIterator::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&quot]);
    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.

Leave a Reply