[Tutorial] Pagination - Creating Pages for mySQL Results... (class_resultpaging.php)

Discussion in 'PHP' started by NetStar, Jul 9, 2012.

  1. #1
    I have noticed a lot of members inquiring about mySQL Pagination (creating pages for mySQL results) so I decided to write a tutorial on how to use my pagination class: class_resultpaging.php.

    I believe the class I wrote (originally back in 2008) is the best mysql pagination class for PHP. It's object oriented and extremely easy to use and understand. Unlike many pagination classes mine will return the rendered HTML page links in a neat professional layout and also the LIMIT code for your SQL statement. It also has support for PDO or the standard way to interact with a database.

    Name this class: class_resultpaging.php
    
    <?php
    
    /**************************************************************************************************
    * =================================================================================================
    * PHP mySQL Paging Class
    * class_resultpaging.php v2.0
    * - DESCRIPTION
    *     A PHP class which paginates an sql result set and can return rendered HTML page links
    *     and mySQL Limit code.
    * =================================================================================================
    * Author:  Jay Juliano - jayjuliano@gmail.com
    * Created: 12/23/2008    Modified: 6/29/2012
    * =================================================================================================
    * Copyright 2008-2012 - NetStar Interactive LLC
    * =================================================================================================
    * You are free to use, distribute, and modify this software under the terms of the
    * GNU General Public License.  See http://www.gnu.org/copyleft/gpl.html for more details.
    **************************************************************************************************/
    
    
    class ResultPaging {
       private $__ResultPaging_DisplayPages   = 5;
       private $__ResultPaging_ResultsPerPage = 10;
       private $__ResultPaging_PageParam      = "page";
       private $__ResultPaging_PageParams     = "";
       private $__ResultPaging_Url            = ""; // Must implement
    
       private $__ResultPaging_UsePDO         = 0; // 0: No; 1: Yes. Default: 0.
    
       private $__ResultPaging_HtmlLinks;
       private $__ResultPaging_StartingResult;
       private $__ResultPaging_EndingResult;
       private $__ResultPaging_CurrentPage;
       private $__ResultPaging_LimitCode;
       private $__ResultPaging_TotalResults;
       
       private $dbh;
       private $sql;
       
    
       public function __construct($dbh = null)
       {
          if (isset($dbh))
          {
             $this->__ResultPaging_UsePDO = 1;
             $this->dbh = $dbh;
    
          } else
          {
              $this->__ResultPaging_UsePDO = 0;
          }
       }
       
    
       public function sql($sql = null)
       {
          if (!isset($sql) || !$sql) die("ResultPaging Error: Missing SQL statement for sql().\n");
          if (!preg_match("/\;$/", $sql)) $sql .= ";"; // Add trailing semi-colon if accidentally omitted
          $this->sql = $sql;
       }
    
    
       public function setPageParam($pageParam = null)
       {
          if (isset($pageParam)) $this->__ResultPaging_PageParam = $pageParam;
       }
    
    
       public function setDisplayPages($displayPages = null)
       {
          if (!is_numeric($displayPages)) die("ResultPaging Error: setDisplayPages() must be a numeric value.");
          if (isset($displayPages)) $this->__ResultPaging_DisplayPages = $displayPages;
       }
    
    
       public function setResultsPerPage($resultsPerPage = null)
       {
          if (!is_numeric($resultsPerPage)) die("ResultPaging Error: setResultsPerPage() must be a numeric value.");
          if (isset($resultsPerPage)) $this->__ResultPaging_ResultsPerPage = $resultsPerPage;
       }
    
    
       public function setPageParams($params = null)
       {
          $params = isset($params) ? $params : "";
          if ($params && !preg_match("/&$/", $params)) $params .= "&";
          $params = preg_replace("/^&/", "", $params);
          $params = preg_replace("/^\?/", "", $params);
          
          $this->__ResultPaging_PageParams = $params;
       }
    
    
       public function setPageURL($pageURL = null)
       {
          if (isset($pageURL)) $this->__ResultPaging_Url = $pageURL;
       }
    
    
       public function getPageLinks()
       {
          if (!isset($this->sql)) die("ResultPaging Error: Trying to fetch page links via getPageLinks() without first setting SQL with sql().\n");
          if (!isset($this->__ResultPaging_HtmlLinks)) $this->generatePageLinks();
          return $this->__ResultPaging_HtmlLinks;
       }
       
    
       public function getLimit()
       {
          if (!isset($this->sql)) die("ResultPaging Error: Trying to fetch SQL Limit code via getLimit() without first setting SQL with sql().\n");
          if (!isset($this->__ResultPaging_HtmlLinks)) $this->generatePageLinks();
          return $this->__ResultPaging_LimitCode;
       }
    
    
       public function getTotalResults()
       {
          if (!isset($this->__ResultPaging_HtmlLinks)) die ("ResultPaging Error: Can't fetch total results via getTotalResults() before calling paginate().\n");
          return $this->__ResultPaging_TotalResults;
       }
    
    
       public function getStartingResult()
       {
          if (!isset($this->__ResultPaging_HtmlLinks)) die ("ResultPaging Error: Can't fetch pages starting result via getStartingResult() before calling paginate().\n");
          return $this->__ResultPaging_StartingResult;
       }
    
    
       public function getEndingResult()
       {
          if (!isset($this->__ResultPaging_HtmlLinks)) die ("ResultPaging Error: Can't fetch pages ending result via getEndingResult() before calling paginate().\n");
          return $this->__ResultPaging_EndingResult;
       }
    
    
       public function getCurrentPage()
       {
          if (!isset($this->__ResultPaging_HtmlLinks)) die ("ResultPaging Error: Can't fetch current page number via getCurrentPage() before calling paginate().\n");
          return $this->__ResultPaging_CurrentPage;
       }
    
    
       public function paginate($mysql = null)
       {
          if (isset($mysql)) $this->sql($mysql);
          if (!isset($this->sql)) die("ResultPaging Error: Trying to paginate via paginate() without specifying SQL or setting SQL with sql().\n");
          $this->generatePageLinks();
          // Perhaps return results as array too
          // return array($this->__ResultPaging_HtmlLinks), $this->__ResultPaging_HtmlLinks));
       }
       
       
       //
       // The magic
       //
       private function generatePageLinks()
       {
          $page = "";
          if (!isset($_GET[$this->__ResultPaging_PageParam]) || !is_numeric($_GET[$this->__ResultPaging_PageParam]) || $_GET[$this->__ResultPaging_PageParam] == 0)
          {
             $page = 1;
          } else
          {
              $page = $_GET[$this->__ResultPaging_PageParam];
          }
          
          $this->__ResultPaging_CurrentPage = $page;
          
          $total_results = 0;
          if ($this->__ResultPaging_UsePDO) // The PDO way
          {
             //$sql = "SELECT count(*) FROM `table` WHERE foo = bar";
             $sth = $this->dbh->prepare($this->sql);
             $sth->execute();
             $total_results = $sth->rowCount();
          } else
          {
              $total_results  = mysql_num_rows(mysql_query($this->sql)); // Standard PHP
          }
          
          $this->__ResultPaging_TotalResults = $total_results;
          
          $total_pages = 0;
          
          if ($this->__ResultPaging_TotalResults) $total_pages = ceil($this->__ResultPaging_TotalResults / $this->__ResultPaging_ResultsPerPage);
            
          if ($page > $total_pages) $page = $total_pages;
                   
          $starting_record = ($page * $this->__ResultPaging_ResultsPerPage) - $this->__ResultPaging_ResultsPerPage;
                   
          if ($starting_record < 0) $starting_record = 0;
          
          $start_page = "";
          $end_page   = "";
          if ($total_pages == 0)
          {
             $start_page = 0;
             $end_page   = 0;
          } else if ($total_pages <= $this->__ResultPaging_DisplayPages)
          {
              $start_page = 1;
              $end_page   = $total_pages;
          } else
          {
              $page_set   = ceil($page / $this->__ResultPaging_DisplayPages) - 1;
              $start_page = ($page_set * $this->__ResultPaging_DisplayPages) + 1;
                           
              if ($total_pages < $start_page + $this->__ResultPaging_DisplayPages - 1)
              {
                 $end_page = $total_pages;
              } else
              {
                  $end_page = ($start_page + $this->__ResultPaging_DisplayPages) - 1;
              }
          }
                   
          $previous_pageset_end   = $start_page - 1;
          $next_pageset_start     = $end_page   + 1;
          $previous_pageset_start = $previous_pageset_end - $this->__ResultPaging_DisplayPages + 1;
          $next_pageset_end       = $next_pageset_start   + $this->__ResultPaging_DisplayPages - 1;
                   
          $previous_page    = $page - 1;
          $next_page        = $page + 1;
    
          $first_record  = $starting_record + 1;
          $last_record   = $first_record    + $this->__ResultPaging_ResultsPerPage - 1;
    
          if ($this->__ResultPaging_TotalResults < $last_record) $last_record = $this->__ResultPaging_TotalResults;
          
          $this->__ResultPaging_StartingResult = $first_record;
          $this->__ResultPaging_EndingResult   = $last_record;
    
          /**************************************************************************************************
          * Format Link Pages
          **************************************************************************************************/
          $this->__ResultPaging_HtmlLinks = "<div id=\"pagesHTML\" style=\"width: 100%; border-bottom: 1px solid #000000; font-family: verdana, arial; font-size: 8pt;\">";
                   
          if ($first_record == 1 && $this->__ResultPaging_TotalResults < 1) $first_record = 0;
                   
          $this->__ResultPaging_HtmlLinks .= "<div id=\"pagesHTMLListing\" style=\"width: 30%; float: left; font-weight: normal;\">Listing $first_record-$last_record of $this->__ResultPaging_TotalResults</div>";
                   
          $this->__ResultPaging_HtmlLinks .= "<div id=\"pagesHTMLPages\" style=\"width: 45%; float: left; font-weight: bold; z-index: 105;\">";
                   
          if ($this->__ResultPaging_TotalResults > 0)
          {
             if ($start_page > $this->__ResultPaging_DisplayPages) $this->__ResultPaging_HtmlLinks .= "<a href=\"" . $this->__ResultPaging_Url . "?" . $this->__ResultPaging_PageParams . $this->__ResultPaging_PageParam . "=1\" title=\"Page 1\" style=\"font-weight: bold;\">1</a>&nbsp;&nbsp;&nbsp;<a href=\"" . $this->__ResultPaging_Url . "?" . $this->__ResultPaging_PageParams . $this->__ResultPaging_PageParam . "=$previous_pageset_end\" title=\"&lsaquo;&lsaquo; Pages $previous_pageset_start-$previous_pageset_end\" style=\"font-weight: bold;\">&lsaquo;&lsaquo;</a>&nbsp;&nbsp;&nbsp;";
                   
             for ($i = $start_page; $i <= $end_page; $i++)
             {
                 if ($i == $page)
                 {
                    $this->__ResultPaging_HtmlLinks .= "<span style=\"\">$i</span>&nbsp;&nbsp;&nbsp;";
                 } else
                 {
                     $this->__ResultPaging_HtmlLinks .= "<a href=\"" . $this->__ResultPaging_Url . "?" . $this->__ResultPaging_PageParams . $this->__ResultPaging_PageParam . "=$i\" title=\"Page $i\" style=\"z-index: 110;\">$i</a>&nbsp;&nbsp;&nbsp;";
                 }
             }
    
             if ($end_page != $total_pages) $this->__ResultPaging_HtmlLinks .= "<a href=\"" . $this->__ResultPaging_Url . "?" . $this->__ResultPaging_PageParams . $this->__ResultPaging_PageParam . "=$next_pageset_start\" title=\"Pages $next_pageset_start-$next_pageset_end &rsaquo;&rsaquo;\" style=\"font-weight: bold; z-index: 100;\">&rsaquo;&rsaquo;</a>&nbsp;&nbsp;<span style=\"font-weight: normal;\">of</span>&nbsp;<a href=\"" . $this->__ResultPaging_Url . "?" . $this->__ResultPaging_PageParams . $this->__ResultPaging_PageParam . "=$total_pages\" title=\"Page $total_pages\" style=\"font-weight: bold; z-index: 100;\">$total_pages</a>";
          }
                   
          $this->__ResultPaging_HtmlLinks .= "</div>";
                   
          $this->__ResultPaging_HtmlLinks .= "<div id=\"pagesHTMLPageSwitches\" style=\"width: 25%; float: left; text-align: right; font-weight: bold;\">";
          if (($page > 1 && $page <= $total_pages) || ($page < $total_pages))
          {
             $this->__ResultPaging_HtmlLinks .= "&nbsp;&nbsp;&nbsp;";
             if ($page > 1 && $page <= $total_pages) $this->__ResultPaging_HtmlLinks .= "<a href=\"" . $this->__ResultPaging_Url . "?" . $this->__ResultPaging_PageParams . $this->__ResultPaging_PageParam . "=$previous_page\" title=\"&lsaquo; Previous Page $previous_page\" style=\"\">&lsaquo; Previous</a>";
             if (($page > 1 && $page <= $total_pages) && ($page < $total_pages)) $this->__ResultPaging_HtmlLinks .= "&nbsp;|&nbsp;";
             if ($page < $total_pages) $this->__ResultPaging_HtmlLinks .= "<a href=\"" . $this->__ResultPaging_Url . "?" . $this->__ResultPaging_PageParams . $this->__ResultPaging_PageParam . "=$next_page\" title=\"Next Page $next_page &rsaquo;\" style=\"\">Next &rsaquo;</a>";
          }
          $this->__ResultPaging_HtmlLinks .= "</div>";
    
          $this->__ResultPaging_HtmlLinks .= "<div style=\"clear: left;\"></div>";
                   
          $this->__ResultPaging_HtmlLinks .= "</div>";
          
          //
          // Set SQL Limit
          //
          $this->__ResultPaging_LimitCode = "LIMIT " . $this->__ResultPaging_StartingResult . ", " . $this->__ResultPaging_ResultsPerPage;
       }
    }
    
    ?>
    
    PHP:

    Example of Usage:

    
    include("class_resultpaging.php"); // Includes class
       
    $p = new ResultPaging(); // Creates object 
     
    // Your SQL statement. The class will use this to determine total results
    $sql = "SELECT whatever From SomeTable WHERE somecol = 'someval'"; // Omit semi-colon as we will be extending this SQL
     
    $p->paginate($sql); // This does all the magic
     
    $sql = $sql . " " . $p->getLimit() . ";"; // This generates the final SQL code to be executed for current page
     
    mysql_query($sql); // Executes SQL
     
    print $p->getPageLinks(); // Prints page links
    
    // Continue with script to fetch and display results etc.
    
    PHP:

    Overview of Functions


    include("class_resultpaging.php");

    Includes class to be used in PHP script.

    $p = new ResultPaging([optional $dbh]);

    Initiates class and creates $p object.
    Accepts optional database handle to use PDO since class will execute a single sql statement.

    $p = new ResultPaging(); // Use regular mySQL
    $p = new ResultPaging($dbh); // Use PDO and pass the $dbh database handle to the class.

    $p->paginate([optional $sql]);

    Processes the pagination, renders the HTML page links, and creates the SQL LIMIT code.
    Accepts optional SQL code, if you wish to not use $p->sql().
    Example:
    $p->paginate("SELECT blah FROM SomeTable WHERE foo = 'bar';"); // With SQL
    $p->paginate(); // Without SQL

    $p->sql([SQL]);

    Mandatory if NOT passing SQL via paginate().
    Sets the SQL code to paginate. Do NOT include LIMIT code.
    Example: $p->sql("SELECT blah FROM SomeTable WHERE foo = 'bar';"); // Don't forget to escape sensitive variables

    $p->setPageURL()[/b] Optional. Default is blank..."play" with your URLs..but it may work as-is.
     
    NetStar, Jul 9, 2012 IP
  2. NetStar

    NetStar Notable Member

    Messages:
    2,471
    Likes Received:
    541
    Best Answers:
    21
    Trophy Points:
    245
    #2
    Made a slightly shorter example to give you a better understanding how to use it:

    
    include("class_resultpaging.php");
    
    $p = new ResultPaging();
    $p->paginate("SELECT name FROM People WHERE state = 'NJ';");
    
    $sql = "SELECT name FROM People WHERE state = 'NJ' " . $p->getLimit() . ";";
    $result = mysql_query($sql);
    
    print $p->getPageLinks();
    
    // Fetch results etc...
    
    PHP:
     
    NetStar, Jul 9, 2012 IP
  3. extraspecial

    extraspecial Member

    Messages:
    788
    Likes Received:
    4
    Best Answers:
    1
    Trophy Points:
    45
    #3
    Thanks buddy, thats a long code :)
     
    extraspecial, Jul 10, 2012 IP
  4. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #4
    Interesting, in a "If this is your idea of simple and easy to follow..." sort of way :(

    The output is bad, with the endless non-semantic DIV, likelyhood the user might want to call it more than once in which case the ID is broken, use of slow double quotes meaning you're escaping values for no reason, static presentation inlined in the markup, z-index for christmas only knows what reason, pointless title attributes (if it's basically the same text as what's inside the tag, there's no legitimate reason to use title), non-breaking spaces doing padding's job... It's a laundry list of how not to make PHP or HTML! Though, admittedly it's entirely what I've come to expect from throwing objects at a problem for nothing and your typical back-end code.

    Much less your non-PDO code being 100% non-functional since num_rows wouldn't work on the same query (would always return 1)... endless pointless PRIVATE declarations where a tab and some commas would be simpler, endless pointless getters (what I mean when I say overuse of getters/setters -- it's right there)

    I mean, you'd have two important queries, and that's it... If I was to approach that, I'd be using semantic markup, getting rid of unneccessary classes and ID's, and moving the markup out into a separate function to make skinners lives easier.

    pageList.php
    
    <?php
    /*
    	pageList Class, 11 July 2012
    	
    	Can create pagination for a table and allow you to pull those pages
    	Also moves a current item number to a page boundary.
    	
    	(C) Jason M. Knight, Released to the Public Domain
    	admin@deathshadow.com - http://www.deathshadow.com
    	
    	Use as you see fit so long as credit to the original author is
    	provided somewhere.
    	
    	If you're going to give something away for **** sake just give it
    	away!!! 
    	
    	If you need some fatass idiotic end-user agreement of legalese --
    		1) That's larger than the forming document of most world governments
    		2) To circumvent copyright and property laws
    		3) On something you're giving away
    	-- well, does the term snake oil ring a bell? Someone seriously needs
    	to explain the word 'freedom' to the FSF.	Someone get me -- Dr. Hipp!
    */
    
    class pageList {
    
    	private
    		$db,
    		$current,
    		$perPage,
    		$table,
    		$total=-1,
    		$qHandle=null;
    	
    	public function __construct($table,$current,$perPage=5,$database=null) {
    		$this->db=$database;
    		$this->setPerPage($perPage);
    		$this->setCurrent($current);
    		$this->setTable($table); // also resets row count
    	} // __construct
    	
    	// let's make it so that current always resets to a page boundary
    	public function setCurrent($current) {
    		$this->current=$current-($current % $this->perPage);
    	} // pullPages::setCurrent
    	
    	// double check when this is set that it's non-zero, avoid divide by zero error
    	public function setPerPage($perPage) {
    		$this->perPage=($perPage==0 ? 5 : $perPage);
    	} // setPerPage
    	
    	// sanitize just in case since prepared queries can't take table name
    	// which is annoyingly ****tarded.
    	public function setTable($table) {
    		$this->table=(
    			isset($this->db) ?
    			$table :
    			mysql_real_escape_string($table)
    		);
    		// new table, might as well pull row count now
    		$this->getTotalRows();
    	} // setTable
    	
    	// if we've not counted yet, do so. otherwise, just return saved value
    	public function getTotalRows() {
    		if ($this->total<0) {
    			$query='SELECT COUNT(*) AS count FROM '.$this->table;
    			if (isset($this->db)) {
    				// PDO
    				$statement=$this->db->query($query);
    				$this->total=$statement->fetchColumn();
    			} else { 
    				// mysql_
    				$result=mysql_query($query);
    				$row=mysql_fetch_row($result);
    				$this->total=$row[0];
    			}
    		}
    		return $this->total;
    	} // getTotalRows
    	
    	public function buildRows() {
    		if (isset($this->db)) {
    			// PDO
    			$this->qHandle=$this->db->prepare(
    				"SELECT * FROM $this->table LIMIT :start , :count"
    			);
    			// have to use bind because LIMIT is a re-re about array
    			$this->qHandle->bindParam(':start', $this->current, PDO::PARAM_INT);
    			$this->qHandle->bindParam(':count', $this->perPage, PDO::PARAM_INT);
    			$this->qHandle->execute();
    		} else {
    			// mysql_
    			// typecasting to int to sanitize -- oh noes, invalid values return zero
    			$this->qHandle=mysql_query(
    				"SELECT * FROM $this->table LIMIT ".(int) $this->current." , ".(int) $this->perPage
    			);
    		}
    	} // buildRows
    	
    	public function getRow() {
    		if ($this->qHandle) {
    			if (isset($this->db)) {
    				return $this->qHandle->fetch();
    			} else return mysql_fetch_array($this->qHandle);
    		} else die('
    			<p class="error">
    				ERROR - Attempt to get row when query handle has not been built. Call "Buildrows" first.
    			</p>
    		');
    	} // getRow
    	
    	// provide cleanup method
    	public function disposeRows() {
    		unset($this->qHandle);
    	} // disposeRows
    	
    	public function showPagination($linkBase) {
    		// linkBase is everything in the anchor before our count.
    		// for example 'index.php?page='
    		
    		if ($this->total>0) {
    		
    			if ($this->perPage==0) $this->perPage=5; // prevent divide by zero
    			
    			$currentPage=floor($this->current/$this->perPage);
    			$lastPage=floor(($this->total-1)/$this->perPage);
    			if ($lastPage>9) { 	// show maximum of 10 at once
    					// by moving the start up if neccessary
    				$counter=($currentPage<6) ? 0 : $currentPage-5;
    					// and adjusting the last page off that.
    				$endPage=$counter+9;
    					// while preventing it from going past the end.
    				if ($endPage>$lastPage) $endPage=$lastPage;
    			} else {
    					// otherwise start at zero
    				$counter=0;
    					// and end at last
    				$endPage=$lastPage;
    			}
    			
    			theme_pagination(
    				$linkBase,
    				$this->current,
    				$this->total,
    				$this->perPage,
    				$currentPage,
    				$lastPage,
    				$endPage,
    				$counter
    			);
    		} else echo '
    			<p class="noResults">No Results -- total:',$this->total,' perPage:',$this->perPage,'</p>';
    		
    	} // showPagination
    	
    } // class pageList
    ?>
    
    Code (markup):
    pageList.template.php
    
    <?php
    /* see pagelist.php for disclaimer */
    
    function theme_pagination(
    	$linkBase,
    	$current,
    	$total,
    	$perPage,
    	$currentPage,
    	$lastPage,
    	$endPage,
    	$counter
    ) {
    		
    	echo '
    	<div class="pageList">
    		<div>Listing ',$current,'-',(
    			$currentPage==$lastPage ?
    			$total :
    			$current+$perPage-1
    		),' of ',$total,'</div>
    		Pages:
    		<ul>';
    		
    	if (($lastPage>0) && ($currentPage>0)) {
    		// if more than one page, and not at first, show first and previous
    		echo '
    			<li><a href="',$linkBase,'0">First</a></li>
    			<li><a href="',$linkBase,($currentPage-1)*perPage,'">&laquo;</a></li>';
    	}
    
    	// span for non-anchor/current is simpler to style
    	while ($counter<=$endPage) {
    		$noAnchor=$counter==$currentPage;
    		echo '
    			<li>',(
    				$noAnchor ? 
    				'<span>' : 
    				'<a href="'.$linkBase.$counter*perPage.'">'
    			),++$counter,(
    				$noAnchor ?
    				'</span>' :
    				'</a>'
    			),'</li>';
    	}
    
    	if (($lastPage>0) && ($currentPage<$lastPage)) {
    		// more than one page and not at last, show next and last
    		echo '
    			<li><a href="',$linkBase,($currentPage+1)*perPage,'">&raquo;</a></li>
    			<li><a href="',$linkBase,$lastPage*perPage,'">Last</a></li>';
    	}
    	echo '
    		</ul>
    	<!-- .pageList --></div>';
    	
    } // theme_pagination
    ?>
    
    Code (markup):
    ... and of course some simple CSS to make it pretty; CSS that has no business being in the markup output by this.

    pagelist.screen.css
    
    /* null margins and padding to give good cross-browser baseline */
    html,body,address,blockquote,div,
    form,fieldset,caption,
    h1,h2,h3,h4,h5,h6,
    hr,ul,li,ol,ul,
    table,tr,td,th,p,img {
    	margin:0;
    	padding:0;
    }
    
    img,fieldset {
    	border:none;
    }
    
    .pageList {
    	margin:1em; /* just so we can see it in testing */
    	overflow:hidden; /* wrap floats */
    	zoom:1; /* trip haslayout, wrap floats IE */
    	text-align:right;
    	vertical-align:middle;
    	font:normal 100%/200% arial,helvetica,sans-serif;
    }
    
    .pageList div {
    	float:left;
    }
    
    .pageList ul {
    	list-style:none;
    	display:inline;
    }
    
    .pageList li {
    	display:inline;
    }
    
    .pageList li a,
    .pageList li span {
    	display:inline-block;
    	vertical-align:middle;
    	font-weight:bold;
    	padding:0.25em 0.5em;
    	line-height:1em;
    	text-decoration:none;
    	color:#000;
    	background:#DDD;
    	border:0.15em solid #666;
    	-moz-border-radius:0.5em;
    	-webkit-border-radius:0.5em;
    	border-radius:0.5em;
    }
    
    .pageList li span {
    	color:#666;
    	background:#EEE;
    	border-color:#666;
    }
    
    .pageList li a:active,
    .pageList li a:focus,
    .pageList li a:hover {
    	color:#008;
    	background:#DEF;
    }
    
    Code (markup):
    Which at 6.9k total is a fraction what you have. Assuming you were using PDO and had a table all nice and ready...

    A simple test page would look something like this:
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html
    	xmlns="http://www.w3.org/1999/xhtml"
    	lang="en"
    	xml:lang="en"
    ><head>
    
    <meta
    	http-equiv="Content-Type"
    	content="text/html; charset=utf-8"
    />
    
    <meta
    	http-equiv="Content-Language"
    	content="en"
    />
    
    <link
    	type="text/css"
    	rel="stylesheet"
    	href="pagelist.screen.css"
    	media="screen,projection,tv"
    />
    
    <title>
    	',$pageTitle,'
    </title>
    
    </head><body>
    
    <?php
    require_once('pagelist.template.php');
    require_once('pagelist.php');
    
    $db=new PDO(
    	'mysql:host=localhost;dbname=pagination',
    	'username',
    	'password'
    );
    
    $pages=new pageList('test',0,5,$db);
    $pages->showPagination('index.php?list=');
    $pages->buildRows();
    while ($row=$pages->getRow()) {
    	echo '<pre>',print_r($row),'</pre>';
    }
    $pages->disposeRows();
    $pages->showPagination('index.php?list='); // show second time at bottom!
    ?>
    
    </body></html>
    
    Code (markup):
    If you had say... 139 pages listing 5 per page, and you were on page 2, the markup output by the above would go something like this:

    
    	<div class="pageList">
    		<div>Listing 5-9 of 139</div>
    		Pages:
    		<ul>
    			<li><a href="index.php?list=0">First</a></li>
    			<li><a href="index.php?list=0">&laquo;</a></li>
    			<li><a href="index.php?list=0">1</a></li>
    			<li><span>2</span></li>
    			<li><a href="index.php?list=10">3</a></li>
    			<li><a href="index.php?list=15">4</a></li>
    			<li><a href="index.php?list=20">5</a></li>
    			<li><a href="index.php?list=25">6</a></li>
    			<li><a href="index.php?list=30">7</a></li>
    			<li><a href="index.php?list=35">8</a></li>
    			<li><a href="index.php?list=40">9</a></li>
    			<li><a href="index.php?list=45">10</a></li>
    			<li><a href="index.php?list=10">&raquo;</a></li>
    			<li><a href="index.php?list=135">Last</a></li>
    		</ul>
    	<!-- .pageList --></div>
    Code (markup):
    Again, let CSS do the heavy lifting -- EXTERNAL to the markup -- that way across multiple pages of navigation you're not wasting bandwidth on nothing by restating the same values on every blasted line! That is the POINT of CSS after all.

    A better version would probably be able to detect if $db was a PDO object or mysqli object -- though pulling complete rows in mysqli is like pulling teeth... at least mysql_ and PDO return row sets the same way. (I imagine this is why you didn't include mysqli in your example either...)

    So... that's how I'd be going about that...
     
    deathshadow, Jul 11, 2012 IP
  5. NetStar

    NetStar Notable Member

    Messages:
    2,471
    Likes Received:
    541
    Best Answers:
    21
    Trophy Points:
    245
    #5
    You didn't try it. You can call it more than once. Over and over. As for slow double quotes..there is absolutely no noticeable difference. It's ridiculous to think that would EVER slow down a script.

    Not pointless. But if you feel so that is just a matter of opinion and preference.

    Subjected to individual preference.

    You only commented on HTML..........

    Not true at all. Tested and being used on several web sites right now. And it IS working with PDO.

    All subjective. The point of adding additional "getters" (6) is to give you access to record numbers, the limit code, total results, and page number.. that's all. All of which are optional to use.

    As for HTML markup you can change that. But it certainly is NOT invalid crap code.

    You are entitled to your opinion. But that's all it was...just your preference. Not the wrong way vs the right way but instead your way vs mine.
     
    NetStar, Jul 11, 2012 IP
  6. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #6
    So basically what you're saying is it's valid/proper to use the same ID more than once? RIGHT. Try again. Seriously, that's mind-blowing you'd not notice that or don't see a problem with it. You call it twice, you're going to have two #pagesHTML, two #pagesHTMLListing, two #pagesHTMLPageSwitches, etc, etc.. and that's NOT valid.

    Measurable at 5-10%, if you bothered understanding the difference between singles and doubles you'd know that... common sense -- doubles have to parse for more possible results.

    Well in your case you were at least adding the word "page" -- which is a HAIR better, but if you had something like

    <a href="#" title="Home">Home</a>

    That is 100% pointless and yet you see it all the blasted time in people's code. That's not subjective, that's fact. If the content says the same thing as TITLE, there is no reason to use TITLE -- it's pointless bloat. Really if you have the text "pages" followed by a bunch of numbers clearly separated as individual links, title="page 1" is pointless bloat. PERIOD. Though as I've said several thousand times, if you need to use TITLE, there's something wrong with the content -- since the point of TITLE is to add more information the text inside the tag fails to provide.


    You did notice I said NON-PDO, right? num_rows on a COUNT(*) should be returning 1 row, since there's only one result.

    Inlined presentation, possibility of generating multiple identical ID's, non-semantic markup, lack of block level separators on the choices, static width calculations, no fallback font families, clearing DIV like it's still 2001... The output is 1.6k to basically do 800 bytes or less' job. You multiply that across an entire page... What would you call that? I mean hell, I've seen WYSIWYGS make better code.

    You may want to go back and learn some HTML and CSS, specifically the POINT of each -- because to be frank, that's a ostrich with it's head in the sand attitude. Semantic markup, separation of presentation from content, leveraging caching models -- any of these ring a bell? You are one step away from just making HTML 3.2 and slapping a tranny doctype on it... you might as well go back and use the FONT tag for all the improvement your CSS has on it.

    Though it would explain how train wrecks like the average turdpress template makes it into circulation -- or the 'average' website these days blowing 100k of markup on delivering 2k of plaintext and a dozen static images.
     
    Last edited: Jul 11, 2012
    deathshadow, Jul 11, 2012 IP
  7. NetStar

    NetStar Notable Member

    Messages:
    2,471
    Likes Received:
    541
    Best Answers:
    21
    Trophy Points:
    245
    #7
    It won't break the page if you choose to display 30 page listings. Used once, which is what the majority of users WILL use is still compliant. In any case, it can be changed to css class names. It's not a big deal.

    This is a misconception from newbies. In reality there is VERY little difference in speed. It's irrelevant really as it does NOT hinder the performance or functionality of the class.

    The use of the title element has absolutely no positive or negative affect. It's a matter of preference and that is all.

    It's completely subjective. It's not BLOAT. Using a title element does NOT create bloat. Nor does it break the class or have ANYTHING to do with ANYTHING. I did not use it in an invalid way.

    It works BOTH ways. I'm currently using it. Go a head and try it the non-pdo way.

    It's irrelevant if the output is 1,600 bytes as appose to only 800 bytes. It's such a miniscule difference it's irrelevant and affects nothing. It's also just a matter of preference if you want to have fallback font families. Clearing the DIV is essential. Regardless how you do it. Again you are pointing out irrelevant petty things..


    I post a class that serves a purpose and you attempt to "break it down" with pointing out irrelevant petty crap that has nothing to do with the functionality of the code. You are completely rude and immature. I could pick apart the class you posted but I'm not a petty idiot that doesn't know how to interact with others.

    What other immature things do you have to say child?
     
    NetStar, Jul 11, 2012 IP
  8. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #8
    .. and of course, can't argue the position so instead goes personal making wild claims about age or lifestyle (when it could just be I'm a New England Yankee) -- and I'm the one who's immature.

    Though you are likely left no recourse except the insults of age (way off the mark) or circumstance (even further off) given you obviously cannot defend the work itself -- apart from dismissing anything that differs out-of-hand. Pretty much everything you said is "preference", "subjective" or "irrelevant" just shows your complete ignorance on the topic... the real gem of this new one being:

    That is the most ignorant statement I have EVER seen out of a developer. WCAG ring a bell? Much less the entire reason the fallback families even exist in the first place?!? I truly pity anyone you're making sites for if you've got that attitude. What's next, declaring fonts for screen in PX or PT on flow content? Nothing wrong with #666 text on #888 background? Same thing...

    When it serves no legitimate purpose in the code, that's called bloat last I checked. Pointless redundancies are bloat... PERIOD.

    Returns 1 on a 139 item table. The whole point of COUNT is to not return more than one row in a result set. If it is working for you, you are building a memory wasting data set... (which again defeats the point of COUNT)

    Because a 50% code reduction is irrelevant... WOW. Just... WOW. Again, apply that across an entire page... Lemme guess, what's your average CTC? 10:1?

    ... and there are better ways to do it than using decade out of date coding techniques and adding code to the markup that belongs in an external file (that can be cached across pages)... that too is called bloat.

    Though I'd love to see you rip mine apart -- ripping things apart and building them back up is how we make things BETTER. Anything else is limp wristed back-slapping hugfest nonsense best left around the drum circle.
     
    deathshadow, Jul 11, 2012 IP
  9. NetStar

    NetStar Notable Member

    Messages:
    2,471
    Likes Received:
    541
    Best Answers:
    21
    Trophy Points:
    245
    #9
    1. If you don't like the fact that I use the title element in my links - who cares. Don't use it.

    2. If you don't like the fact that my code outputs 800 bytes of HTML more than you feel is necessary - who cares. Don't use it.

    3. Both PDO and non-pdo methods work. Again, I am USING the class and it's working. Otherwise, I wouldn't be able to use it and I would fix it.

    4. If you don't like the approach I use to clear a div then again - who cares. Don't use it.


    Your existence in this thread would of made much more sense by offering suggestions rather than to waste your time by trying to pick apart little meaningless irrelevant tidbits to make yourself feel smarter... less geeky??? Or whatever you were trying to accomplish.

    Digital Point would be a lot better if we all worked with each other rather than against. Again...make suggestions rather than be ignorant and rude.
     
    NetStar, Jul 11, 2012 IP
  10. Rukbat

    Rukbat Well-Known Member

    Messages:
    2,908
    Likes Received:
    37
    Best Answers:
    51
    Trophy Points:
    125
    #10
    jqGrid makes it a lot simpler, and it has a lot more functionality.
     
    Rukbat, Jul 13, 2012 IP