TalkPHP
 
 
Account Login
Latest Articles
» The basic usage of PHPTAL, a XML/XHTML template library for PHP
» Vulnerable methods and the areas they are commonly trusted in.
» Simple way to protect a form from bot
» The Basics On: How Session Stealing Works
» How to keep your forms from double posting data
IRC Channel
IRC Speech Bubble Join the friendly bunch on IRC...
(#TalkPHP on Freenode)

...Also available via a web interface.

See this thread for information on the TalkPHP Free Hugs Initiative™. Subject to availability.
Associates
Associates
CSS Tutorials
Reply
 
LinkBack Thread Tools Search this Thread Display Modes
Old 01-11-2008, 03:53 PM   #1 (permalink)
The Prestige
Upcoming Programmer Inquisitive 
 
Tanax's Avatar
 
Join Date: Sep 2007
Location: Sweden, Stockholm
Posts: 1,080
Thanks: 115
Tanax is on a distinguished road
Default Please review my pagination class

Hello!

I've made a pagination class.
At the moment, it only has the basic features:

-Display pagelinks
-Display nextpage link
-Display prevpage link
-Display "Page: <currentpage> of <totalpages>"
-Display results depending on which page

I'm just wondering what you think of it.

example.php
php Code:
<?php

/**
||||||||||||||||||||||||||||||||||||||||||
|||| @author Tanax
|||| @copyright 2008
||||||||||||||||||||||||||||||||||||||||||
**/


    include('pagination.php');
    $p = $_GET['p'];
    $max = 10;
   
    // Create the object and set some basic values.
    $pagination = new pagination();
    $pagination->setMax($max)
   
    // Get the total results, and then calculate how many pages that becomes based on how many results per page.
    $totSql = "SELECT * FROM `table`";
    $totQuery = mysql_query($totSql) or die(mysql_error());
    $totResults = mysql_fetch_array($totQuery);
    $totPages = $pagination->getPages($totResults);
   
    // Set the current page, and get the first result on it.
    $first = $pagination->setPage($p);
   
    // Get the results of the current page.
    $exSql = "SELECT * FROM `table` LIMIT $first, $max";
    $exQuery = mysql_query($exSql) or die(mysql_error());
    $exResults = mysql_fetch_array($exQuery);
   
    // Echo out the current page, and the total amount of pages.
    $page = $pagination->getCurrentPage();
    echo 'Page: '.$page[0].' of '.$page[1];
   
    // Get previous page link, and check if it's valid.
    $prevLink = $p - 1;
    if($pagination->checkLink($prevLink)) {
       
        echo 'Previous Page';
       
    }
   
    // Print all the pages
    foreach($totPages as $pageNumber) {
       
        if($pageNumber == $p) {
           
            echo '<strong>'.$pageNumber.'</strong>';
           
        }
       
        else {
           
            echo $pageNumber;
           
        }
       
    }
   
    // Get the next page link, and check if it's valid.
    $nextLink = $p + 1;
    if($pagination->checkLink($nextLink)) {
       
        echo 'Next Page';
       
    }
   
    // Echo the results...
   

?>

pagination.php
php Code:
<?php

/**
||||||||||||||||||||||||||||||||||||||||||
|||| @author Tanax
|||| @copyright 2008
||||||||||||||||||||||||||||||||||||||||||
**/


    class pagination {
       
        // The total value.
        private $totalPages;
        private $totalResults;
        private $totalPerPage;
       
        // The current value.
        private $currentPage;
        private $currentSpan;
       
        private $firstResult;
       
        public function setMax($max) {
           
            if(is_numeric($max)) {
               
                $this->totalPerPage = $max;
               
            }
           
        }
       
        public function setPage($page) {
           
            if(is_numeric($page)) {
               
                $this->currentPage = mysql_real_escape_string($page);
                $this->firstResult = (($this->currentPage * $this->totalPerPage) - $this->totalPerPage);
               
                return $this->firstResult;
               
            }
           
        }
       
        public function getPages($results) {
           
            $this->totalResults = count($results);
            $totalPages = $this->totalResults / $this->totalPerPage;
            $this->totalPages = ceil($totalPages);
           
            $x = 1;
            $array = array();
           
            while($x <= $this->totalPages) {
               
                $array[] = $x;
                $x++;
               
            }
           
            return $array;
           
        }
       
        public function checkLink($pagenr) {
           
            if($pagenr <= $this->totalPages && $pagenr >= 1) {
               
                return true;
               
            }
           
            return false;
           
        }
       
        public function getCurrentPage() {
           
            $array = array();
            $array[] = $this->currentPage;
            $array[] = $this->totalPages;
           
            return $array;
           
        }
       
    }

?>

Yes, I know I didn't comment the functions inside the class. But meh, too lazy atm. Besides, I commented when calling the functions in example.php.

Anyhow!
What do you think of it?
Also.. how would I add the functionality for a span.
So it only displays the pagelinks within the set span.

".. 5 6 7 8 9 ..."
If the span was set to 2(2 at each direction).


Please comment
Tanax is offline  
Reply With Quote
Old 01-11-2008, 04:22 PM   #2 (permalink)
The Addict
Top Contributor Good Samaritan 
 
Join Date: Jan 2008
Location: USA
Posts: 217
Thanks: 16
RobertK is on a distinguished road
Default

Your class looks good and functional, but I think I see a few potential trip-wires.

The problems I see aren't related to your object, but your queries. For instance, it'd be better to query:
sql Code:
SELECT COUNT(*) AS `count` FROM `table`
Otherwise you are getting every single row from the database to walk through to find the count. On a table with lots of rows this'd take quite some time.

This would necessitate a slight change in how you assign the page count and limit modulo.


If you were to improve the object itself, I'd suggest that: you make it independent of the data passed, and that its output can handle "first prev ... 1 2 3 4 5 ... next last" as an option. From there the only thing to change is the number of rows on a page, and localization support. Then you'd never need to write another one again!
__________________
Programmers are in a race with the Universe to create bigger and better idiot-proof programs, while the Universe is trying to create bigger and better idiots. So far the Universe is winning. - Rich Cook
RobertK is offline  
Reply With Quote
Old 01-11-2008, 04:24 PM   #3 (permalink)
The Frequenter
 
xenon's Avatar
 
Join Date: Dec 2007
Location: Bucharest, Romania
Posts: 438
Thanks: 3
xenon is on a distinguished road
Default

Quote:
Originally Posted by Tanax View Post
Also.. how would I add the functionality for a span.
So it only displays the pagelinks within the set span.

".. 5 6 7 8 9 ..."
If the span was set to 2(2 at each direction).
Sorry about not commenting on your class, I'm just too lazy to read the whole code right now :D For the matter quoted above, you would have to loop a little each side of the current page ('span' times). That's how I did it for myself, however. If you find a better alternative, please share.
__________________
I have optimistic thoughts, even though sometimes (if not always) life's a bitch.
xenon is offline  
Reply With Quote
Old 01-11-2008, 04:36 PM   #4 (permalink)
The Addict
Top Contributor Good Samaritan 
 
Join Date: Jan 2008
Location: USA
Posts: 217
Thanks: 16
RobertK is on a distinguished road
Default

Missed your request Tanax and went right to the issue I saw, apologies.

A way would be to use a function/method like this:
PHP Code:
function showPages($current$span 2)
{
  
$leftMost $current $span;
  echo 
'First ... ';
  while(
$leftMost <= $current+$span)
  {
    
$tag = ($leftMost == $current) ? 'b' 'span';
    echo 
"<$tag>$leftMost</$tag> ";
    
$leftMost++;
  }
  echo 
'... Last';

Yields (on a span of 3):
Quote:
First ... 5 6 7 8 9 10 11 ... Last
You'll have to tweak it to not get a negative number when on the first page. However, I figured that I'd leave you with the concept.
__________________
Programmers are in a race with the Universe to create bigger and better idiot-proof programs, while the Universe is trying to create bigger and better idiots. So far the Universe is winning. - Rich Cook
RobertK is offline  
Reply With Quote
Old 01-11-2008, 04:56 PM   #5 (permalink)
The Prestige
Upcoming Programmer Inquisitive 
 
Tanax's Avatar
 
Join Date: Sep 2007
Location: Sweden, Stockholm
Posts: 1,080
Thanks: 115
Tanax is on a distinguished road
Default

@RobertK 1st Post- So.. what exactly is it better for? :-S
And what do you mean with that it should handle "first prev ... 1 2 3 4 5 ... next last" as an option? :O

@xenon- Yah, I did it before too, with loops on each side(see my gallery script that I released somewhere here..). I was just wondering how it would be solved in this case, and if it exists any easier way of accomplishing it.

@RobertK 2nd Post- Yah, that's almost exactly how I did it before, but it's quite annoying piece of code, and I was just wondering if there are any easier way xD
But thanks
Tanax is offline  
Reply With Quote
Old 01-11-2008, 05:48 PM   #6 (permalink)
The Addict
Top Contributor Good Samaritan 
 
Join Date: Jan 2008
Location: USA
Posts: 217
Thanks: 16
RobertK is on a distinguished road
Default

Quote:
Originally Posted by Tanax View Post
@RobertK 1st Post- So.. what exactly is it better for? :-S
You're getting the count of the rows with my query, instead of getting all rows to count (with the object) and then query again for the your portion shown by the page. This change from selecting all rows, and the megs of data it might entail, to selecting just the count of the rows gives a speed increase.

Quote:
Originally Posted by Tanax View Post
And what do you mean with that it should handle "first prev ... 1 2 3 4 5 ... next last" as an option? :O
It should be able to handle localization, other languages, and the option to include or exclude first/last/next/prev page links. Just further options you can bind into one class easily.

Quote:
Originally Posted by Tanax View Post
@RobertK 2nd Post- Yah, that's almost exactly how I did it before, but it's quite annoying piece of code, and I was just wondering if there are any easier way xD
But thanks
Not really. I know no other ways.
__________________
Programmers are in a race with the Universe to create bigger and better idiot-proof programs, while the Universe is trying to create bigger and better idiots. So far the Universe is winning. - Rich Cook
RobertK is offline  
Reply With Quote
Old 01-11-2008, 11:29 PM   #7 (permalink)
The Prestige
Upcoming Programmer Inquisitive 
 
Tanax's Avatar
 
Join Date: Sep 2007
Location: Sweden, Stockholm
Posts: 1,080
Thanks: 115
Tanax is on a distinguished road
Default

About language support..

This is a pagination class... not a complete SYSTEM
I will just have to use a language class, and then get the correct words..

That's why I in this pagination class just return raw data, and all the text are outputted outside of the class.

And if I wish to have the "option" to remove the prev link, then I'll just delete that part from example.php where it outputs the link...
Tanax is offline  
Reply With Quote
Old 01-11-2008, 11:33 PM   #8 (permalink)
The Addict
Top Contributor Good Samaritan 
 
Join Date: Jan 2008
Location: USA
Posts: 217
Thanks: 16
RobertK is on a distinguished road
Default

As I said,
Quote:
From there the only thing to change is the number of rows on a page, and localization support. Then you'd never need to write another one again!
It was only a statement of, "this is as far as you can go."

Nothing more.
__________________
Programmers are in a race with the Universe to create bigger and better idiot-proof programs, while the Universe is trying to create bigger and better idiots. So far the Universe is winning. - Rich Cook
RobertK is offline  
Reply With Quote
Old 01-12-2008, 12:07 AM   #9 (permalink)
The Prestige
Upcoming Programmer Inquisitive 
 
Tanax's Avatar
 
Join Date: Sep 2007
Location: Sweden, Stockholm
Posts: 1,080
Thanks: 115
Tanax is on a distinguished road
Default

Ahh, okey

But outputting text, or HTML within a class method, kind of destroys the purpose with classes; being able to create classes that can be used on ANY website, so people just download the core, and they build the user-side themselves
Tanax is offline  
Reply With Quote
Old 01-12-2008, 12:10 AM   #10 (permalink)
The Addict
Top Contributor Good Samaritan 
 
Join Date: Jan 2008
Location: USA
Posts: 217
Thanks: 16
RobertK is on a distinguished road
Default

Well, I never specified what or how it output, just that it should. I personally wouldn't have it directly set HTML either, that's for template engines, etc.
__________________
Programmers are in a race with the Universe to create bigger and better idiot-proof programs, while the Universe is trying to create bigger and better idiots. So far the Universe is winning. - Rich Cook
RobertK is offline  
Reply With Quote
Old 03-23-2009, 04:14 PM   #11 (permalink)
The Gregarious
 
allworknoplay's Avatar
 
Join Date: Feb 2009
Location: New York
Posts: 645
Thanks: 64
allworknoplay is on a distinguished road
Default

Quote:
Originally Posted by RobertK View Post
Your class looks good and functional, but I think I see a few potential trip-wires.

The problems I see aren't related to your object, but your queries. For instance, it'd be better to query:
sql Code:
SELECT COUNT(*) AS `count` FROM `table`
Otherwise you are getting every single row from the database to walk through to find the count. On a table with lots of rows this'd take quite some time.
Hopefully Tanax or someone else can answer this. I don't know if RobertK is still around? Anyways, this is more of a SQL question.


The way I count rows has always been this:

$query = "SELECT `table_id` FROM table";

$num_count = mysql_num_rows($query);


Then use the $num_count in my various loops...mainly "for" loops.

Anyways, what I read was never to use wildcard "*" because you only want the count, and you don't want to select every column in a table especially if it's huge. So that's why I pick the `table_id`, it can really be any column.

So according to RobertK's post, is there a BETTER way to get the number of rows in a table that is less resource intensive?

What is the fundamental significance of:

SELECT COUNT(*) AS `count` FROM `table`



I know this is an old post, sorry, I just felt like searching pagination and I found this thread...
allworknoplay is offline  
Reply With Quote
Old 03-23-2009, 05:12 PM   #12 (permalink)
The Frequenter
 
xenon's Avatar
 
Join Date: Dec 2007
Location: Bucharest, Romania
Posts: 438
Thanks: 3
xenon is on a distinguished road
Default

Well, selecting all columns, as well as selecting just one column for counting will always be extremely slow because the MySQL engine should go through each and every one of the rows in that table and get the requested data for you, where as select count(*) will determine the number of entries based on the metadata extracted from the index keys. It just performs a lookup, instead of reading every actual row from the db. I hope you understand the whole difference. If not, ask more :)
__________________
I have optimistic thoughts, even though sometimes (if not always) life's a bitch.
xenon is offline  
Reply With Quote
The Following User Says Thank You to xenon For This Useful Post:
allworknoplay (03-23-2009)
Old 03-23-2009, 05:51 PM   #13 (permalink)
The Gregarious
 
allworknoplay's Avatar
 
Join Date: Feb 2009
Location: New York
Posts: 645
Thanks: 64
allworknoplay is on a distinguished road
Default

Quote:
Originally Posted by xenon View Post
Well, selecting all columns, as well as selecting just one column for counting will always be extremely slow because the MySQL engine should go through each and every one of the rows in that table and get the requested data for you, where as select count(*) will determine the number of entries based on the metadata extracted from the index keys. It just performs a lookup, instead of reading every actual row from the db. I hope you understand the whole difference. If not, ask more :)
Ok gotchya. Yes I understand now. I will attempt to use this for future purposes as best practice.
allworknoplay is offline  
Reply With Quote
Reply



Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


All times are GMT. The time now is 01:39 PM.

 
     

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.1.0
Inactive Reminders By Icora Web Design