Pagination Helper

By Andy Dawson (AD7six)
The pagination helper, for instruction on use see: http://bakery.cakephp.org/articles/view/65

Helper Class:

Download code <?php 
/**
 * Pagination Helper, responsible for managing the LINKS required for pagination.
 * ALL parameters are specified in the component.
 */
class PaginationHelper extends Helper 
{
/**
 * Options to be passed to ajax links if used
 *
 * @var array
 * @access public
 */
    
var $ajaxLinkOptions = array();
/**
 * Placeholder for the link style - defined in/by the component
 *
 * @var boolean
 * @access private
 */
    
var $style 'html';
/**
 * Placeholder for the parameter style - defined in/by the component
 *
 * @var boolean
 * @access private
 */
    
var $paramStyle 'get';
/**
 * Placeholder for the pagination details
 *
 * @var array
 * @access private
 */
    
var $_pageDetails = Array();
/**
 * Helpers
 *
 * @var array
 * @access private
 */
    
var $helpers = Array("Html","Ajax");

/**
 * Sets the default pagination options. Fails if the value $paging is not set
 *
 * @param array $paging an array detailing the page options
 * @return boolean
 */
    
function setPaging($paging)
    {
        if (empty(
$paging)) {return false;}
        
$this->_pageDetails $paging;
        
$this->_pageDetails['previousPage'] = ($paging['page']>1) ? $this->_pageDetails['page']-'';
        
$this->_pageDetails['nextPage'] = ($paging['page'] < $this->_pageDetails['pageCount']) ? $this->_pageDetails['page']+'';

        
$this->url $this->_pageDetails['url'];
        
        
$getParams $this->params['url'];
        unset(
$getParams['url']);
        
$this->getParams $getParams;
        
        
$this->showLimits $this->_pageDetails['showLimits'];
        
$this->style = isset($this->_pageDetails['style'])?$this->_pageDetails['style']:$this->style;
        
        if ((
$this->_pageDetails['maxPages'] % 2)==0// need odd number of page links
        
{
            
$this->_pageDetails['maxPages'] = $this->_pageDetails['maxPages']-1;
        }
        
        
$this->maxPages $this->_pageDetails['maxPages'];
        
$this->pageSpan = ($this->_pageDetails['maxPages']-1)/2;
        
           return 
true;
    }
    
/**
* Displays the list of pages for the given parameters.
*
* @param string text to display before limits
* @param string display a separate between limits
* @param boolean whether to escape the title or not
* @return unknown the html string for modifying the number of results per page
**/
    
function resultsPerPage($t="Results per page: "$separator=" ",$escapeTitle=true)
    {
        if (empty(
$this->_pageDetails)) { return false; }
        
$pageDetails $this->_pageDetails;
        if ( !empty(
$pageDetails['pageCount']) )
        {
            if(
is_array($pageDetails['resultsPerPage']))
            {
                
$OriginalValue $pageDetails['show'];
                
$t .= $separator;
                foreach(
$pageDetails['resultsPerPage'] as $value)
                {
                    if(
$OriginalValue == $value)
                    {
                        
$t .= '<em>'.$value.'</em>'.$separator;
                    }
                    else
                    {
                        
$pageDetails['show'] = $value;
                        
$t .= $this->_generateLink($value,1,$escapeTitle,$pageDetails).$separator;
                    }
                }
            }
            return 
$t;
        }
        return 
false;
    }

/**
* Generate a select box for options for results per page
*
* @param string prefix text
* @return unknown the html string for the select box for modifying the number of results per page
**/
    
function resultsPerPageSelect($t="Results per page: ")
    {
        if (empty(
$this->_pageDetails)) { return false; }
        if ( !empty(
$this->_pageDetails['pageCount']) )
        {
            
$Options = Array();
            if(
is_array($this->_pageDetails['resultsPerPage']))
            {
                foreach(
$this->_pageDetails['resultsPerPage'] as $value)
                {
                    
$Options[$value] = $value;
                }
            }
            return 
$t.$this->Html->selectTag("pagination/show"$Options$this->_pageDetails['show'], NULLNULL,FALSE);
        }
        return 
false;
    }

/**
* Displays info of the current result set
*
* @param string prefix text
* @param string
* @param string
* @return unknown the html string for the current result set.
**/
    
function result($t="Results: ",$of=" of ",$inbetween="-")
    {
        if (empty(
$this->_pageDetails)) { return false; }
        if ( !empty(
$this->_pageDetails['pageCount']) )
        {
            if(
$this->_pageDetails['pageCount'] > 1)
            {
                
$start_row = (($this->_pageDetails['page']-1)*$this->_pageDetails['show'])+1;
                
$end_row min ((($this->_pageDetails['page'])*$this->_pageDetails['show']),($this->_pageDetails['total']));
                
$t $t.$start_row.$inbetween.$end_row.$of.$this->_pageDetails['total'];
            }
            else
            {
                
$t .= $this->_pageDetails['total'];
            }
            return 
$t;
        }
        return 
false;
    }
/**
* Returns a list of page numbers separated by $separator
*
* @param string $separator - defaults to null
* @param boolean
* @param string $spacerLower - If there are more results than space for the links, the text inbetween
* @param string $spacerUpper - If there are more results than space for the links, the text inbetween
* @return string html for the list of page numbers
**/
    
function pageNumbers($separator=null,$escapeTitle=true,$spacerLower="...",$spacerUpper="...")
    {
        if (empty(
$this->_pageDetails) || $this->_pageDetails['pageCount'] == 1) { return "<em>1</em>"; }
        
$total $this->_pageDetails['pageCount'];
        
$max $this->maxPages;
        
$span $this->pageSpan;
        if (
$total<$max)
        {
            
$upperLimit min($total,($span*2+1));
            
$lowerLimit 1;
        }
        elseif (
$this->_pageDetails['page']<($span+1))
        {
            
$lowerLimit 1;
            
$upperLimit min($total,($span*2+1));
        }
        elseif (
$this->_pageDetails['page']>($total-$span))
        {
            
$upperLimit $total;
            
$lowerLimit max(1,$total-$span*2);
        }
        else
        {
            
$upperLimit min ($total,$this->_pageDetails['page']+$span);
            
$lowerLimit max (1,($this->_pageDetails['page']-$span));
        }
        
        
$t = array();
        if ((
$lowerLimit<>1)AND($this->showLimits))
        {
            
$lowerLimit $lowerLimit+1;
            
$t[] = $this->_generateLink(1,1,$escapeTitle);
            if (
$spacerLower)
            {
                
$t[] = $spacerLower;
            }
        }
        if ((
$upperLimit<>$total)AND($this->showLimits))
        {
            
$dottedUpperLimit true;
        }
        else
        {
            
$dottedUpperLimit false;
        }
        if ((
$upperLimit<>$total)AND($this->showLimits))
        {
            
$upperLimit $upperLimit-1;
        }
        for (
$i $lowerLimit$i <= $upperLimit$i++)
        {
             if(
$i == $this->_pageDetails['page'])
             {
                
$text '<em>'.$i.'</em>';
             }
             else
             {
                
$text $this->_generateLink($i,$i,$escapeTitle);
             }
             
$t[] = $text;
        }
        if (
$dottedUpperLimit)
        {
            if (
$spacerUpper)
            {
                
$t[] = $spacerUpper;
            }
            
$t[] = $this->_generateLink($this->_pageDetails['pageCount'],$this->_pageDetails['pageCount'],$escapeTitle);
        }
        
$t implode($separator$t);
        return 
$t;
    }
    
/**
* Displays a link to the previous page, where the page doesn't exist then
* display the $text
*
* @param string $text - text display: defaults to next
* @return string html for link/text for previous item
**/
    
function prevPage($text='prev',$escapeTitle=true)
    {
        if (empty(
$this->_pageDetails)) { return false; }
        if ( !empty(
$this->_pageDetails['previousPage']) )
        {
            return 
$this->_generateLink($text,$this->_pageDetails['previousPage'],$escapeTitle);
        }
        return 
$text;
    }
    
/**
* Displays a link to the next page, where the page doesn't exist then
* display the $text
*
* @param string $text - text to display: defaults to next
* @return string html for link/text for next item
**/
    
function nextPage($text='next',$escapeTitle=true)
    {
        if (empty(
$this->_pageDetails)) { return false; }
        if (!empty(
$this->_pageDetails['nextPage']))
        {
            return 
$this->_generateLink($text,$this->_pageDetails['nextPage'],$escapeTitle);
        }
        return 
$text;
    }

/**
* Displays a link to the first page
* display the $text
*
* @param string $text - text to display: defaults to next
* @return string html for link/text for next item
**/
    
function firstPage($text='first',$escapeTitle=true)
    {
        if (empty(
$this->_pageDetails)) { return false; }
        if (
$this->_pageDetails['page']<>1)
        {
            return 
$this->_generateLink($text,1,$escapeTitle);
        }
        else
        {
            return 
false;
        }
    }

/**
* Displays a link to the last page
* display the $text
*
* @param string $text - text to display: defaults to next
* @return string html for link/text for next item
**/
    
function lastPage($text='last',$escapeTitle=true)
    {
        if (empty(
$this->_pageDetails)) { return false; }
        if (
$this->_pageDetails['page']<>$this->_pageDetails['pageCount'])
        {
            return 
$this->_generateLink($text,$this->_pageDetails['pageCount'],$escapeTitle);
        }
        else
        {
            return 
false;
        }
    }


/**
* Generate link to sort the results by the given value
*
* @param string field to sort by
* @param string title for link defaults to $value
* @param string model to sort by - uses the default model class if absent
* @param boolean escape title
* @param string text to append to links to indicate sorted ASC
* @param string text to append to links to indicate sorted DESC
* @return string html for link to modify sort order
**/
    
function sortBy ($value$title=NULL$Model=NULL,$escapeTitle=true,$upText=" ^",$downText=" v"
    {
        if (empty(
$this->_pageDetails)) { return false; }
        
$title $title?$title:ucfirst($value);
        
$value strtolower($value);
        
$Model $Model?$Model:$this->_pageDetails['Defaults']['sortByClass'];

        
$OriginalSort $this->_pageDetails['sortBy'];
        
$OriginalModel $this->_pageDetails['sortByClass'];
        
$OriginalDirection $this->_pageDetails['direction'];

        if ((
$value==$OriginalSort)&&($Model==$OriginalModel)) 
        {
            if (
up($OriginalDirection)=="DESC"
            {
                
$this->_pageDetails['direction'] = "ASC";
                
$title .= $upText;
            } 
            else 
            {
                
$this->_pageDetails['direction'] = "DESC";
                
$title .= $downText;
            }
        }
        else
        {
            if (
$Model
            {
                
$this->_pageDetails['sortByClass'] = $Model;
                
//echo "page details model class set to ".$this->_pageDetails['sortByClass']."<br>";
            
}
            else
            {
                
$this->_pageDetails['sortByClass'] = NULL;
            }
            
$this->_pageDetails['sortBy'] = $value;
        }
        
$link $this->_generateLink ($title,1,$escapeTitle);
        
$this->_pageDetails['sortBy'] = $OriginalSort;
        
$this->_pageDetails['sortByClass'] = $OriginalModel;
        
$this->_pageDetails['direction'] = $OriginalDirection;
        return 
$link;
    }

/**
* Generate a select box for options to sort results
*
* @param array array of text strings, formatted as "Field::Direction::Class".
* @param string prefix text
* @param string text to append to links to indicate sorted ASC
* @param string text to append to links to indicate sorted DESC
* @return unknown the html string for the select box for selecting sort order
**/
    
function sortBySelect($sortFields$t="Sort By: ",$upText=" ^",$downText=" v")
    {
        if (empty(
$this->_pageDetails)) { return false; }
        if ( !empty(
$this->_pageDetails['pageCount']) )
        {
            
$OriginalValue $this->_pageDetails['sortBy']."::".$this->_pageDetails['direction']."::".$this->_pageDetails['sortByClass'];
            if(
is_array($sortFields))
            {
                foreach(
$sortFields as $value)
                {
                    
$Vals = Array();
                    
$Vals explode("::",$value);
                    if (isset(
$Vals[2]))
                    {
                        
$DisplayVal $Vals[2]." ";
                    }
                    else
                    {
                        
$DisplayVal "";
                    }
                    
$DisplayVal .= $Vals[0];
                    if (
up($Vals[1])=="ASC")
                    {
                        
$DisplayVal .= $downText;
                    }
                    else
                    {
                        
$DisplayVal .= $upText;                        
                    }
                    
$Options[$value] = $DisplayVal;
                }
                return 
$t.$this->Html->selectTag("pagination/sortByComposite"$Options$OriginalValueNULLNULL,FALSE);
            }
        }
        return 
false;
    }
    
/**
* Internal method to generate links based upon passed parameters.
*
* @param string title for link
* @param string page the page number
* @param boolean escape title
* @param string the div to be updated by AJAX updates
* @return string html for link
**/
    
function _generateLink ($title,$page=NULL,$escapeTitle,$pageDetails NULL
    {
        
$pageDetails $pageDetails?$pageDetails:$this->_pageDetails;
        
$url $this->_generateUrl($page,$pageDetails);
        
$AjaxDivUpdate $pageDetails['ajaxDivUpdate'];
        if (
$this->style=="ajax")
        {
            
$options am($this->ajaxLinkOptions,
                            array(
                                
"update" => $pageDetails['ajaxDivUpdate']
                                )
                            );
            if (isset(
$pageDetails['ajaxFormId']))
            {
                
$id 'link' intval(rand());
                
$return $this->Html->link(
                                
$title,
                                
$url,
                                array(
'id' => $id'onclick'=>" return false;"),
                                
NULL,
                                
$escapeTitle
                                    
);
                
$options['with'] = "Form.serialize('{$this->_pageDetails['ajaxFormId']}')";
                
$options['url'] = $url;
                
$return .= $this->Ajax->Javascript->event("'$id'""click"$this->Ajax->remoteFunction($options));
                return 
$return;
            }
            else
            {
                return 
$this->Ajax->link(
                                
$title,
                                
$url,
                                
$options,
                                
NULL,
                                
NULL,
                                
$escapeTitle
                                    
);
            }
        }
        else
        {
            return 
$this->Html->link(
                            
$title,
                            
$url,
                            
NULL,
                            
NULL,
                            
$escapeTitle
                                
);
        }
    }

    function 
_generateUrl ($page=NULL,$pageDetails=NULL
    {
        
$pageDetails $pageDetails?$pageDetails:$this->_pageDetails;
        
$getParams $this->getParams// Import any other pre-existing get parameters
        
if ($this->_pageDetails['paramStyle']=="pretty")
        {
            
$pageParams=$pageDetails['importParams'];
        }
        
$pageParams['show'] = $pageDetails['show'];
        
$pageParams['sortBy'] = $pageDetails['sortBy'];
        
$pageParams['direction'] = $pageDetails['direction'];
        
$pageParams['page'] = $page?$page:$pageDetails['page'];
        if (isset(
$pageDetails['sortByClass']))
        {
            
$pageParams['sortByClass'] = $pageDetails['sortByClass'];
        }
        
$getString = Array();
        
$prettyString = Array();
        if (
$pageDetails['paramStyle']=="get")
        {
            
$getParams am($getParams,$pageParams);
        }
        else
        {
            foreach(
$pageParams as $key => $value)
            {
                if (isset(
$pageDetails['Defaults'][$key]))
                {
                    if (
up($pageDetails['Defaults'][$key])<>up($value))
                    {
                        
$prettyString[] = "$key{$pageDetails['paramSeperator']}$value";
                    }
                }
                else
                {
                    
$prettyString[] = "$key{$pageDetails['paramSeperator']}$value";
                }            
            }
        }
        foreach(
$getParams as $key => $value)
        {
            if (
$pageDetails['paramStyle']=="get")
            {
                if (isset(
$pageDetails['Defaults'][$key]))
                {
                    if (
up($pageDetails['Defaults'][$key])<>up($value))
                    {
                        
$getString[] = "$key=$value";
                    }
                }
                else
                {
                    
$getString[] = "$key=$value";
                }
            }
            else
            {
                
$getString[] = "$key=$value";
            }            
        }
        
$url $this->url;
        if (
$prettyString)
        {
            
$prettyString implode ("/"$prettyString);
            
$url .= $prettyString;
        }
        if (
$getString)
        {
            
$getString implode ("&"$getString);
            
$url .= "?".$getString;
        }
        return 
$url;
    }
}
?>