PHP Developers Network

A community of PHP developers offering assistance, advice, discussion, and friendship.
 
Loading
It is currently Mon Sep 28, 2020 2:43 pm

All times are UTC - 5 hours




Post new topic Reply to topic  [ 15 posts ] 
Author Message
 Post subject: PHP5 Paginator Class
PostPosted: Sat Aug 05, 2006 11:01 am 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London
Knocked up a simple Pagination class with the primary objective being as much flexibility as possible. :)

Thus instead of tieing it in directly with mysql_* functions, or even a database object, I have built it as a decorator/helper for any array.

As this is the Critique forum, please crticise away :)

Syntax: [ Download ] [ Hide ]
<?php



/**

 * Pagination Class

 * Used for easy creation of paginated data

 *  which is stored in an array

 */


class jmt_Paginator

{

    /**

     * Data to be paginated.

     * @var array data

     * @private

     */


    private $data;

    /**

     * Rows to be displayed per page

     * @var int itemsPerPage

     * @private

     */


    private $itemsPerPage;

    /**

     * Current Page

     * @var int currentPage

     * @private

     */


    private $currentPage;

    /**

     * The first page

     * @var int firstPage

     * @private

     */


    private $firstPage;

    /**

     * The last page of paginated data.

     * @var int lastPage

     * @private

     */


    private $lastPage;



    /**

     * Paginator constructor

     * sets default values of properties

     * @param object data

     * @param int itemsPerPage

     */


    public function __construct (array $data, $itemsPerPage = 10)

    {

        $this->data         = $data;

        $this->itemsPerPage = $itemsPerPage;

        $this->currentPage  = 1;

        $this->firstPage    = 1;

        $this->lastPage     = ceil(count($this->data) / $this->itemsPerPage);

    }



    /**

     * Retrieve the data of the current page.

     * @return array data

     */


    public function getPageData ()

    {

        $start  = ($this->itemsPerPage * ($this->currentPage - 1));



        return array_slice($this->data, $start, $this->itemsPerPage);

    }



    /**

     * Set the current page.

     * Will default to first/last if supplied page number out of range.

     * @param int page

     */


    public function setPage ($page)

    {

        if ($page > $this->lastPage) $page = $this->lastPage;

        if ($page < $this->firstPage) $page = $this->firstPage;



        $this->currentPage = $page;

    }



    /**

     * Get the current page number.

     * @return int pageNumber

     */


    public function getCurrentPage ()

    {

        return $this->currentPage;

    }



    /**

     * Get the first page number

     * @return int pageNumber

     */


    public function getFirstPage ()

    {

        return $this->firstPage;

    }



    /**

     * Get the last page number

     * @return int pageNumber

     */


    public function getLastPage ()

    {

        return $this->lastPage;

    }



    /**

     * Get the next page number

     * @return int pageNumber

     * @return bool noNextPage

     */


    public function getNextPage ()

    {

        if ($this->currentPage < $this->lastPage) {

            return ($this->currentPage + 1);

        } else {

            return false;

        }

    }



    /**

     * Get the previous page number

     * @return int pageNumber

     * @return bool noPrevPage

     */


    public function getPrevPage ()

    {

        if ($this->currentPage > $this->firstPage) {

            return ($this->currentPage - 1);

        } else {

            return false;

        }

    }



    /**

     * Get total number of pages

     * @return int totalPages

     */


    public function getTotalPages ()

    {

        return $this->lastPage;

    }

}



?>


The Test:
Syntax: [ Download ] [ Hide ]
class PaginationTest extends UnitTestCase

{



    var $array;

    function PaginationTest ()

    {

        $this->array = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);

        $this->UnitTestCase();

    }

   

    function testPaginationDefaultRowsPerPage () {

        // default items per page = 10; 15 items = 2pages.

        $pagin = new jmt_Paginator($this->array);

       

        $pagin->setPage(-99);

        $this->assertEqual($pagin->getPageData(), array(1,2,3,4,5,6,7,8,9,10));

       

        $pagin->setPage(1);

        $this->assertEqual($pagin->getPageData(), array(1,2,3,4,5,6,7,8,9,10));

       

        $pagin->setPage(2);

        $this->assertEqual($pagin->getPageData(), array(11,12,13,14,15));

       

        $pagin->setPage(99);

        $this->assertEqual($pagin->getPageData(), array(11,12,13,14,15));                

    }

   

    function testPaginationNonDefaultRowsPerPage () {

        // 5 items per page; 15 items = 3 pages.

        $pagin = new jmt_Paginator($this->array, 5);

       

        $pagin->setPage(-99);

        $this->assertEqual($pagin->getPageData(), array(1,2,3,4,5));

       

        $pagin->setPage(1);

        $this->assertEqual($pagin->getPageData(), array(1,2,3,4,5));

       

        $pagin->setPage(2);

        $this->assertEqual($pagin->getPageData(), array(6,7,8,9,10));

       

        $pagin->setPage(3);

        $this->assertEqual($pagin->getPageData(), array(11,12,13,14,15));

       

        $pagin->setPage(99);

        $this->assertEqual($pagin->getPageData(), array(11,12,13,14,15));        

    }

   

    function testPaginationGetPage () {

        // 5 items per page; 15 items = 3 pages.

        $pagin = new jmt_Paginator($this->array, 5);

       

        $this->assertEqual($pagin->getNextPage(), 2);

        $this->assertEqual($pagin->getPrevPage(), false);

        $this->assertEqual($pagin->getCurrentPage(), 1);

       

        $pagin->setPage(2);

        $this->assertEqual($pagin->getNextPage(), 3);

        $this->assertEqual($pagin->getPrevPage(), 1);

        $this->assertEqual($pagin->getCurrentPage(), 2);

       

        $pagin->setPage(99);

        $this->assertEqual($pagin->getNextPage(), false);

        $this->assertEqual($pagin->getPrevPage(), 2);

        $this->assertEqual($pagin->getCurrentPage(), 3);

    }

}


EDIT: update - binned iArrayObject, now accepts primitive type array in constructor and uses array_* functions.


Last edited by Jenk on Tue Aug 22, 2006 7:56 am, edited 3 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 05, 2006 1:39 pm 
Offline
DevNet Resident
User avatar

Joined: Fri Apr 07, 2006 5:13 am
Posts: 1640
Location: Israel
Haven't read it up to the end, but if you look at this:

Syntax: [ Download ] [ Hide ]
$this->rowsPerPage * $this->currentPage - $this->rowsPerPage


To make things easier... x = $this->rowsPerPage and y = $this->currentPage, now your code will look like this: x * y - x and...
x * y - x === x(y - 1)
Therefore your code can be replaced with this:

Syntax: [ Download ] [ Hide ]
$this->rowsPerPage * ($this->currentPage - 1)

:wink:


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 05, 2006 4:01 pm 
Offline
DevNet Master
User avatar

Joined: Tue Dec 28, 2004 6:57 pm
Posts: 2745
Location: Tallinn, Estonia


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 05, 2006 4:05 pm 
Offline
Neighborhood Spidermoddy
User avatar

Joined: Mon Mar 29, 2004 4:24 pm
Posts: 31559
Location: Bothell, Washington, USA
the offset calculation is

perPageCount * (pageNumber - 1) which does equate to perPageCount * pageNumber - perPageCount

Oren's math is correct.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 05, 2006 4:11 pm 
Offline
DevNet Master
User avatar

Joined: Tue Dec 28, 2004 6:57 pm
Posts: 2745
Location: Tallinn, Estonia


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 05, 2006 4:22 pm 
Offline
Forum Regular

Joined: Fri Jun 10, 2005 1:43 am
Posts: 592
Location: LT
It performs them the same way the whole civilized world does ;)


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 05, 2006 4:36 pm 
Offline
DevNet Master
User avatar

Joined: Mon Oct 25, 2004 9:29 pm
Posts: 3698
Location: New Jersey, US


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 05, 2006 4:48 pm 
Offline
DevNet Master
User avatar

Joined: Mon Oct 25, 2004 9:29 pm
Posts: 3698
Location: New Jersey, US


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 05, 2006 5:22 pm 
Offline
DevNet Master

Joined: Tue Jan 20, 2004 12:11 am
Posts: 4897
Location: Leuven, Belgium
I find the 'iArrayObject' a bit of a confusing name... If you look at you'll see that we decided to name it 'PageableDataSource' or something like that... (Personally i found the code in that thread pretty well-designed, so i can only advise to look at it and get inspiration ;))


Top
 Profile  
 
 Post subject:
PostPosted: Sun Aug 06, 2006 1:59 pm 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London
Thanks all for feedback :)

I'll try to answer what I can:

iArrayObject is the interface to a class that is an Array contained within an Object.

This is the interface:
Syntax: [ Download ] [ Hide ]
interface iArrayObject

{

    public function hasItems();

    public function itemCount ();

    public function getRange ($start = 0, $length = null, $keys = false);

    public function getItem ($ind = null);

    public function addItem ($val, $ind = null);

    public function addRange ($arr, $ind = null);

    public function keyExists ($key);

    public function inArray ($val);    

}
(Some of those can be optional, but I've put them all in regardless.)

Once I have completed the ArrayObject class I use to a satisfactory level, I'll post that too :) Currently am rewotking the class to accept associative arrays, as at the moment it only accepts numerical 0 index arrays :)

The properties are private, as I am a firm believer of setters and getters. All but one property is immutable post instantiation, and thus I like to keep things locked down. :) Even for the property that is not immutable, I like to keep things 'secure' and thus if in future I need to make any changes to the process of assignment for $currentPage, I can do it in setPage(); :)

I've updated the class with a getTotalPages method, and have changed the $start calculation to that suggested. Original post to be updated very shortly :)


Top
 Profile  
 
 Post subject:
PostPosted: Sun Aug 06, 2006 3:09 pm 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London
Oh, and re: assertEqual(s) being backwards - technically, it doesn't matter - however this is the first time I have come to use SimpleTest and I simply followed the lead in :)


Top
 Profile  
 
 Post subject:
PostPosted: Sun Aug 06, 2006 3:16 pm 
Offline
DevNet Master
User avatar

Joined: Mon Oct 25, 2004 9:29 pm
Posts: 3698
Location: New Jersey, US
Hmm... that's interesting... (may need to go rewrite unit tests).


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 15, 2006 9:47 am 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London
edit: updated orignal post


Last edited by Jenk on Tue Aug 22, 2006 7:50 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 15, 2006 6:41 pm 
Offline
Forum Contributor

Joined: Wed Jul 12, 2006 12:18 am
Posts: 140
return an iterator from the paginator may be useful


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 15, 2006 7:43 pm 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London
that is true, but at the same time I am allowing for flexibility so for those situations where the application(s) require use of an iterator, they can use :
Syntax: [ Download ] [ Hide ]
<?php



$pagedata = new jmt_Paginator($array);

$iterator = new Iterator($pagedata->getPageData());

//etc..



?>


Rather than the class 'forcing' them to use it :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group