Jump to content

Recommended Posts

I am new to OOP, and created a general pagination class to gather, calculate, etc, all the data I need to generate for several applications (blog, gallery, etc).  It is working fine, but I wanted to get some feedback.  What would you do differently?  What could I improve on?  Etc.

 

Thank you all in advance!

 

<?php

class Pagination {
    
    //Declaring variables
    protected $paginationFor;
    protected $totalItems;
    protected $totalPages;
    protected $page;
    protected $defaultDisplayNumber;
    protected $numberDisplayed;

    public function __construct($paginationFor) {
        //Sets the paginationFor variable
        $this->paginationFor = $paginationFor;
    }
        
    public function setTotalItems($totalItems) {
        $this->totalItems = $totalItems;
    }
    
    public function getTotalItems() {
        return $this->totalItems;
    }
    
    public function setCurrentPageNumber($currentPage) {
        //Sets total number of pages (required for following line of code)
        $this->setTotalPages();
        
        /* Resets page number to total number of pages if current page value is
         * greater than total pages
         */ 
        $this->page = ($currentPage > $this->getTotalPages()) ? $this->getTotalPages() : $currentPage;
        
        /* Resets position values for the first and last items on a particular
         * page in case the page number value was changed by the above line
         */ 
        $this->setFirstLastPosition();
    }
    
    public function getCurrentPageNumber() {
        return $this->page;
    }
    
    public function setDefaultDisplayNumber($defaultDisplayNumber) {
        
        //Creates numberDisplayed array session variable if not already present 
        if (!isset($_SESSION['numberDisplayed'])) {
            $_SESSION['numberDisplayed'] = array();
        }
        
        /* If user has provided a new number to display from an HTML form, that
         * value will be added/updated in the numberDisplayed array session
         * variable.  If no new value has been provided, then, if the key is
         * present, the existing session variable key/value pair will be used,
         * or a new pair will be created based on a provided default value
         */ 
        if (isset($_POST['numberDisplayed'])) {
            $this->setNumberDisplayed($this->paginationFor, $_POST['numberDisplayed']);
            $this->setCurrentPageNumber($this->page); //Resets current page
        } elseif (!$this->getNumberDisplayed('notes')) {
            $this->setNumberDisplayed($this->paginationFor, $defaultDisplayNumber);
        }
        
    }
    
    public function setNumberDisplayed($paginationFor, $numberDisplayed) {
        //Checks that the $numberDisplayed variable only contains numbers
        $regex = '/[^0-9]++/'; //Only numbers allowed
        $this->numberDisplayed = preg_replace($regex, '', $numberDisplayed);
        
        //Adds key/value pair to session array
        $_SESSION['numberDisplayed'][$paginationFor] = $this->numberDisplayed;  
    }
    
    public function getNumberDisplayed() {
        //Either returns the key's value or returns false
        if (empty($_SESSION['numberDisplayed'][$this->paginationFor])) {
            return false;   
        } else {
            return $_SESSION['numberDisplayed'][$this->paginationFor];
        }
    }
    
    public function setTotalPages() {
        /* Calculates total number of pages based on total items and number of
         * items displayed per page
         */ 
        $this->totalPages = ceil($this->getTotalItems() / $this->getNumberDisplayed());        
    }
    
    public function getTotalPages() {
        return $this->totalPages;
    }
    
    public function setFirstLastPosition() {
        /* Calculates the numerical position of the first and last items on any
         * particular page
         */
        $this->firstPageItemPosition = ($this->getCurrentPageNumber() * $this->getNumberDisplayed()) - $this->getNumberDisplayed();
        $this->lastPageItemPosition = $this->firstPageItemPosition + $this->getNumberDisplayed();
    }
    
    public function getFirstPageItemPosition() {
        return $this->firstPageItemPosition;
    }
    
    public function getLastPageItemPosition() {
        return $this->lastPageItemPosition;
    }
    
}

?>

Link to comment
https://forums.phpfreaks.com/topic/120638-pagination-class-looking-for-feedback/
Share on other sites

bump

 

 

Below is an updated version of the pagination class and an example of its implementation...

 

Instantiation of pagination class in a controller helper class...

 
class NotesActions extends ActionController {
    
...SNIP...
    
    public function doNotes() {

       ...SNIP...

        /* Instantiates new Notes class, then gathers all entries from the
         * database, places that data into an array, and then passes the object
         * to the registry
         */ 
        $notes = new Notes($this->mysqli);
        $notes->findEntries();
        $this->registry->set('notesObject', $notes);
        
        /* Instantiates new Pagination class, passes all the required data for
         * generating pagination, and then passes the object to the registry
         */ 
        $pagination = new Pagination('notes');
        $pagination->setTotalItems($notes->getDataCount());
        $pagination->setDefaultDisplayNumber(4);
        $pagination->setCurrentPageNumber($this->page);
        $this->registry->set('paginationObject', $pagination);

    }
}

 

Example of implementation of the pagination object...

 
<?php

//Sets note and pagination objects from the registry
$notes = $this->registry->get('notesObject');
$pagination = $this->registry->get('paginationObject');

//Ouputs HTML header and openning div
echo "\t\t<div class=\"notesContainer\">\n";
echo "\t\t\t<h2 class=\"notes\">Notes:: More from me..</h2>\n";
echo "\t\t\tI use this area of my site to share random thoughts, experiences, etc.\n\t\t\t<br />\n\n";

//Ouputs navigation div
echo "\t\t\t<div class=\"notesNavigationContainer\">\n";
echo "\t\t\t\t<div class=\"notesNavigationRight\">\n";

//If there are more pages beyond the current one, a "Next" link is provided
if ($pagination->getTotalItems() > $pagination->getLastPageItemPosition()) { 
    echo "\t\t\t\t\t<a href=\"http://" . $_SERVER['SERVER_NAME'] . '/notes/' . ($pagination->getCurrentPageNumber() + 1) . "\">Next</a>\n";
    $addNextLink = true;
} else {
    $addNextLink = false;
}

echo "\t\t\t\t</div>\n";
echo "\t\t\t\t<div class=\"notesNavigationLeft\">\n";

//If the user is beyond the first page, a "Previous" link is provided
if ($pagination->getCurrentPageNumber() > 1) {
    echo "\t\t\t\t\t<a href=\"http://" . $_SERVER['SERVER_NAME'] . '/notes/' . ($pagination->getCurrentPageNumber() - 1) . "\">Previous</a>\n";
} else {
    echo "\t\t\t\t\t<span style=\"color:#ffffff;\">_</span>\n";
}

echo "\t\t\t\t</div>\n";
echo "\t\t\t\t<div class=\"notesNavigationCenter\">\n\t\t\t\t\t";

//Calculating the starting pagination number
$startingPaginationNumber = $pagination->getCurrentPageNumber() - 2;

//If the user is on page four or beyond, a link to page one is provided
if ($startingPaginationNumber <= 1) {
    $startingPaginationNumber = 1;
} else {
    echo '<a href="http://' . $_SERVER['SERVER_NAME'] . '/notes/1" title="First Page">«</a> ';
}

//Calculating the ending pagination number
$endingPaginationNumber = $pagination->getCurrentPageNumber() + 2;

if ($endingPaginationNumber > $pagination->getTotalPages()) {
    $endingPaginationNumber = $pagination->getTotalPages();
}

/* Navigation via a numerical index will be provided with links directly to the
* two most adjacent pages on either side of the current page number, as well as
* the additional links to the starting and ending pages,  all such that the
* output will resemble "<< 3 4 5 6 7 >>" where 5 is the current page 
*/
for ($i = $startingPaginationNumber; $i <= $endingPaginationNumber; $i++) {
    if ($i == $pagination->getCurrentPageNumber()) {
        echo '<span style="font-weight:800;text-decoration:underline;">' . $i . '</span> ';
    } else {
        echo '<a href="http://' . $_SERVER['SERVER_NAME'] . "/notes/$i\">$i</a> ";
    }
}

/* If the user is three or more pages from the end, a link to the last page is
* provided
*/ 
if ($endingPaginationNumber < $pagination->getTotalPages()) {
    echo '<a href="http://' . $_SERVER['SERVER_NAME'] . '/notes/' . $pagination->getTotalPages() . '" title="Last Page">»</a>';
}

echo "\n\t\t\t\t</div>\n";
echo "\t\t\t</div>\n\n";

//Outputting entry data
$noteData = $notes->getSlicedData($pagination->getFirstPageItemPosition(), $pagination->getDisplayNumber());
foreach($noteData as $note) {
    echo "\t\t\t<div class=\"noteContainer\">\n";
    echo "\t\t\t\t<h2 class=\"notes\">" . $note['title'] . "</h2>\n";
    echo "\t\t\t\t" . $note['date'] . " | <a href=\"http://" . $_SERVER['SERVER_NAME'] . '/notes/entry/' . $note['id'] . "\">Permalink</a>\n";
    echo "\t\t\t\t<div class=\"noteBody\">\n\t\t\t\t\t" . stripslashes(str_replace("\n" , "\t\t\t\t\t<br />\n\t\t\t\t\t", $note['note'])) . "\n\t\t\t\t</div>";
    echo "\n\t\t\t</div>\n";
}

echo "\t\t</div>";

?>


        <form method="post" action="<?php $_SERVER['PHP_SELF'] ?>" class="notesNumberDisplayed">
            <div class="notesNumberDisplayed">
                        Display
                <select name="displayNumber" size="1" class="notesNumberDisplayed" onchange="form.submit()">
                    <option value="2" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 2) {echo "selected=\"selected\"";} ?>>2</option>
                    <option value="4" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 4) {echo "selected=\"selected\"";} ?>>4</option>
                    <option value="6" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 6) {echo "selected=\"selected\"";} ?>>6</option>
                    <option value="8" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == <!-- s8) --><img src=\"{SMILIES_PATH}/icon_cool.gif\" alt=\"\" title=\"Cool\" /><!-- s8) --> {echo "selected=\"selected\"";} ?>>8</option>
                    <option value="10" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 10) {echo "selected=\"selected\"";} ?>>10</option>
                    <option value="20" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 20) {echo "selected=\"selected\"";} ?>>20</option>
                    <option value="40" class="notesNumberDisplayed" <?php if ($pagination->getDisplayNumber() == 40) {echo "selected=\"selected\"";} ?>>40</option>
                </select>
<?php

if ($addNextLink) { 
    echo "\n\t\t\t<a href=\"http://" . $_SERVER['SERVER_NAME'] . '/notes/' . ($pagination->getCurrentPageNumber() + 1) . "\">Next</a>\n";
}

?>                    
                <noscript><p class="no_style">JavaScript required to change the display number!</p></noscript>
                    </div>
        </form>

 

Pagination class (updated)

 
<?php

class Pagination {
    
    //Declaring variables
    protected $paginationFor;
    protected $totalItems;
    protected $totalPages;
    protected $currentPage;
    protected $defaultDisplayNumber;
    protected $displayNumber;

    public function __construct($paginationFor) {
        //Sets the paginationFor variable
        $this->paginationFor = $paginationFor;
    }
        
    public function setTotalItems($totalItems) {
        $this->totalItems = $totalItems;
    }
    
    public function getTotalItems() {
        return $this->totalItems;
    }
    
    public function setCurrentPageNumber($page) {
        //Sets total number of pages (required for following line of code)
        $this->setTotalPages();
        
        /* Resets page number to total number of pages if current page value is
         * greater than total pages
         */ 
        $this->currentPage = ($page > $this->getTotalPages()) ? $this->getTotalPages() : $page;
        
        /* Resets position values for the first and last items on a particular
         * page in case the page number value was changed by the above line
         */ 
        $this->setFirstLastPosition();
    }
    
    public function getCurrentPageNumber() {
        return $this->currentPage;
    }
    
    public function setDefaultDisplayNumber($defaultDisplayNumber) {
        
        //Sets default number of items displayed
        $this->defaultDisplayNumber = $defaultDisplayNumber;
        
        /* Creates displayNumber array session variable, if not already
         * present, containing the default number of items to display
         */ 
        if (empty($_SESSION['displayNumber'][$this->paginationFor])) {
            $_SESSION['displayNumber'][$this->paginationFor] = $this->defaultDisplayNumber;
        }
        
        /* If user has provided a new number to display from an HTML form, that
         * value will be added/updated in the displayNumber array session
         * variable, followed by an update of the current page number.
         */ 
        if (isset($_POST['displayNumber'])) {
            $this->setDisplayNumber($_POST['displayNumber']);
            $this->setCurrentPageNumber($this->currentPage);
        }         
    }
    
    public function setDisplayNumber($displayNumber) {
        //Checks that the $displayNumber variable only contains numbers
        $regex = '/[^0-9]++/'; //Only numbers allowed
        $this->displayNumber = preg_replace($regex, '', $displayNumber);
        
        //Adds key/value pair to session array
        $_SESSION['displayNumber'][$this->paginationFor] = $this->displayNumber;
    }
    
    public function getDisplayNumber() {
        //Either returns the key's value or returns false
        if (empty($_SESSION['displayNumber'][$this->paginationFor])) {
            return false;  
        } else {
            return $_SESSION['displayNumber'][$this->paginationFor];
        }
    }
    
    public function setTotalPages() {
        /* Calculates total number of pages based on total items and number of
         * items displayed per page
         */
        $this->totalPages = ceil($this->getTotalItems() / $this->getDisplayNumber());        
    }
    
    public function getTotalPages() {
        return $this->totalPages;
    }
    
    public function setFirstLastPosition() {
        /* Calculates the numerical position of the first and last items on any
         * particular page
         */
        $this->firstPageItemPosition = ($this->getCurrentPageNumber() * $this->getDisplayNumber()) - $this->getDisplayNumber();
        $this->lastPageItemPosition = $this->firstPageItemPosition + $this->getDisplayNumber();
    }
    
    public function getFirstPageItemPosition() {
        return $this->firstPageItemPosition;
    }
    
    public function getLastPageItemPosition() {
        return $this->lastPageItemPosition;
    }
    
}

?>

The only data I get from the user, in this case,  is the (1) page number or (2) user selected number of items to display per page, both of which I filter/validate as follows...

 


        //Sets page variable
        $regex = '/[^0-9]++/'; //Only numbers allowed
        $this->page = isset($_GET['page']) ? preg_replace($regex, '', $_GET['page']) : 1;

...SNIP...

        //Checks that the $displayNumber variable only contains numbers
        $regex = '/[^0-9]++/'; //Only numbers allowed
        $this->displayNumber = preg_replace($regex, '', $displayNumber);

 

Do you think that is an ok way to protect against XSS attacks?  Also, any other feedback on the class or implementation?

 

Regardless, thanks again!

When even I'm expecting integers, I usually just type cast.

 

 

<?php

$number = (isset($_GET['number'])) ? (int) $_GT['number'] : 0;

//you might actually want to put a conditional in the if block, but since the default is 0 anyway, and type casting returns a value of 0 if it's not castable (or it's 0), then it's the same in this situation.

 

 

Or I use http://php.net/ctype_number

 

 

 

In my opinion, you shouldn't need to be operating on the values outside of the class.  For example:

 

$startingPaginationNumber = $pagination->getCurrentPageNumber() - 2;

 

I personally would try to avoid things like that, but I guess which ever way works.

 

 

Wow I'm rambling and this post was entirely useless.  Oh well.

 

I wanted a lot of flexibility with the class, so I that is why there are not specific methods to generate starting and ending pagination numbers.  For example, in this case, I wanted the output to look like:

 

<< 3 4 5 6 7 >>  (with 5 being the current page number)

 

Therefore, I am able to get that range of numbers based off the current page number +/- 2.

 

 

However, in another case I might want to display all the page numbers like so...

 

1 2 3 4 5 6 7 8 (with 5 being the current page number)

 

...which I would do based on the current page number and total number of pages.

 

 

Does that make sense?  Or would you still use a method to achieve this?  If so, what would it look like?

 

Also, thank you for all the other feedback, I am working on integrating it now.  Anything else I can work on?

<?php

$number = (isset($_GET['number'])) ? (int) $_GT['number'] : 0;

//you might actually want to put a conditional in the if block, but since the default is 0 anyway, and type casting returns a value of 0 if it's not castable (or it's 0), then it's the same in this situation.

 

Actually you code do this:

 


$number = (int)$_GET['number'];

 

And it would do the same thing. However if $_GET['number'] has a value of say "39hv40", $number will be 3940

Any error reporting level not including E_NOTICE will not throw notices ;p.

 

 

Edit:  Bleh....  Removed something about type casting.  Thoughts strings were always casted to 0 if not entirely numeric ;p.  Apparently strings starting with numbers retain numbers.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.