railpage/railpagecore

View on GitHub
lib/Pagination.php

Summary

Maintainability
B
4 hrs
Test Coverage
<?php

/**
 * Create and draw page navigation UI (Pagination)
 * @since Version 3.10.0
 * @package Railpage
 * @author Michael Greenhill
 */

namespace Railpage;

use Exception;
use InvalidArgumentException;

class Pagination {
    
    /**
     * Name of the default pagination template
     * @since Version 3.10.0
     * @const DEFAULT_TEMPLATE
     */
    
    const DEFAULT_TEMPLATE = "template.pagination";
    
    /**
     * Default left/previous navigation text
     * @since Version 3.10.0
     * @const DEFAULT_NAV_LEFT
     */
    
    const DEFAULT_NAV_LEFT = "<span class='glyphicon glyphicon-chevron-left'></span>";
    
    /**
     * Default right/more/next navigation text
     * @since Version 3.10.0
     * @const DEFAULT_NAV_RIGHT
     */
    
    const DEFAULT_NAV_RIGHT = "<span class='glyphicon glyphicon-chevron-right'></span>";
    
    /**
     * An array of configuration parameters 
     * @since Version 3.10.0
     * @var array $params
     */
    
    public $params = [];
    
    /**
     * Smarty instance
     * @since Version 3.10.0
     * @var \Railpage\Template $Smarty
     */
    
    private $Smarty;
    
    /**
     * Constructor
     * @since Version 3.10.0
     * @param string $urlFormat
     * @param int $currentPage
     * @param int $totalItems
     * @param int $itemsPerPage
     */
    
    public function __construct($urlFormat, $currentPage, $totalItems, $itemsPerPage = 25) {
        
        $this->Smarty = AppCore::GetSmarty();
        
        $this->setParam("current_page", $currentPage)
             ->setParam("url_format", $urlFormat)
             ->setParam("num_items", $totalItems)
             ->setParam("per_page", $itemsPerPage); 
        
    }
    
    /**
     * Set a configuration parameter
     * @since Version 3.10.0
     * @param string $param
     * @param mixed $value
     * @return \Railpage\Pagination
     */
     
    public function setParam($param, $value) {
        
        $this->params[$param] = $value;
        
        return $this;
        
    }
    
    /**
     * Get a configuration parameter
     * @since Version 3.10.0
     * @param string $param
     * @return mixed
     */
    
    public function getParam($param) {
        
        if (isset($this->params[$param]) && !empty($this->params[$param])) {
            return $this->params[$param]; 
        }
        
        return false;
        
    }
    
    /**
     * Set the URL format
     * @since Version 3.10.0
     * @param string $url_format
     * @return \Railpage\Pagination
     */
    
    public function setUrlFormat($format) {
        
        $this->params['url_format'] = $format;
        
        return $this;
        
    }
    
    /**
     * Validate the pagination data
     * @since Version 3.10.0
     * @return \Railpage\Pagination;
     */
    
    private function validate() {
        
        if (!$this->getParam("url_format")) {
            throw new Exception("No URL format has been set");
        }
        
        if (!$this->getParam("template")) {
            $this->setParam("template", self::DEFAULT_TEMPLATE); 
        }
        
        if (!$this->getParam("nav_left")) {
            $this->setParam("nav_left", self::DEFAULT_NAV_LEFT); 
        }
        
        if (!$this->getParam("nav_right")) {
            $this->setParam("nav_right", self::DEFAULT_NAV_RIGHT); 
        }
        
        $this->setParam("total_pages", ceil($this->getParam("num_items") / $this->getParam("per_page")));
        
        return $this;
        
    }
    
    /**
     * Add a link to the pagination
     * @since Version 3.10.0
     * @param int $increment
     * @param boolean $currentPage
     * @return \Railpage\Pagination
     */
    
    private function addLink($increment, $currentPage = null) {
        
        $links = $this->getParam("links"); 
        
        $href = sprintf($this->getParam("url_format"), $increment); 
        
        $links[$increment] = [
            "href" => $href,
            "text" => $currentPage === true ? sprintf("%s of %s", $increment, $this->getParam("total_pages")) : $increment,
            "current" => $currentPage,
            "class" => $currentPage ? "current" : ""
        ];
        
        $this->setParam("links", $links);
        
        return $this;
        
    }
    
    /**
     * Build the first few links
     * @since Version 3.10.0
     * @return \Railpage\Pagination
     */
    
    private function buildStartLinks() {
        
        for ($i = 1; $i <= 3; $i++) {
            $this->addLink($i); 
        }
        
        return $this;
        
    }
    
    /**
     * Build the last few links
     * @since Version 3.10.0
     * @return \Railpage\Pagination
     */
    
    private function buildEndLinks() {
        
        for ($i = $this->getParam("total_pages") - 2; $i <= $this->getParam("total_pages"); $i++) {
            $this->addLink($i); 
        }
        
        return $this;
        
    }
    
    /**
     * Add the current page if it's not already in the array, and mark it as current
     * @since Version 3.10.0
     * @return \Railpage\Pagination
     */
    
    private function buildCurrentPage() {
        
        $links = $this->getParam("links"); 
        $currentPage = $this->getParam("current_page"); 
        
        $past = false;
        
        foreach (array_keys($links) as $i) {
            if ($i == $currentPage) {
                $this->addLink($currentPage, true); 
                break;
            }
            
            if ($i > $currentPage) {
                $past = true;
                for ($x = $currentPage -1; $x <= $currentPage + 1; $x++) {
                    $this->addLink($x, $x == $currentPage); 
                }
                
                $links = $this->getParam("links"); 
                ksort($links); 
                $this->setParam("links", $links);
                
                break;
            }
        }
        
        return $this;
        
    }
    
    /**
     * Add dividers between page number blocks
     * @since Version 3.10.0
     * @return \Railpage\Pagination
     */
    
    private function addDividers() {
        
        $links = $this->getParam("links");
        
        end($links); 
        $last = key($links); 
        
        foreach ($links as $i => $link) {
            
            if ($i == $last) {
                continue;
            }
            
            if (!isset($links[$i + 1])) {
                $links[$i + 1] = [
                    "text" => "...",
                    "current" => false,
                    "class" => "other"
                ];
            }
            
        }
        
        ksort($links);
        
        $this->setParam("links", $links); 
        
        return $this;
        
    }
    
    /**
     * Add navigation (left, right) elements
     * @since Version 3.10.0
     * @return \Railpage\Pagniation
     */
    
    private function addNavigation() {
        
        $links = $this->getParam("links"); 
        $current = $this->getParam("current_page");
        $first = key($links); 
        
        end($links); 
        $last = key($links); 
        
        if ($current !== $first) {
            
            $links[$first - 1] = [
                "href" => sprintf($this->getParam("url_format"), $current - 1),
                "text" => $this->getParam("nav_left"),
                "current" => false,
                "class" => "navigation"
            ];
        }
        
        if ($this->getParam("current_page") !== $last) {
            $links[$last + 1] = [
                "href" => sprintf($this->getParam("url_format"), $current + 1),
                "text" => $this->getParam("nav_right"),
                "current" => false,
                "class" => "navigation"
            ];
        }
        
        ksort($links);
        
        $this->setParam("links", $links); 
        
        return $this;
        
    }
    
    /**
     * Echo the created HTML
     * @since Version 3.10.0
     * @return string
     * @todo Caching? Speed up the generation of this crap?
     */
    
    public function __toString() {
        
        return $this->buildPagination(); 
        
    }
    
    /**
     * Build the pagination
     * @since Version 3.10.0
     * @return string
     */
    
    private function buildPagination() {
        
        $this->validate();
        
        $this->buildStartLinks()
             ->buildEndLinks()
             ->buildCurrentPage()
             ->addDividers()
             ->addNavigation(); 
        
        $tpl = $this->Smarty->ResolveTemplate($this->params['template']);
        
        $caching = false;
        
        if (isset($this->Smarty->cache) && $this->Smarty->cache == true) {
            $caching = true; 
            $this->Smarty->cache = false;
            $this->Smarty->clearCache($tpl);
        }
        
        $this->Smarty->Assign("pagination", $this->getParam("links")); 
        
        $html = $this->Smarty->Fetch($tpl); 
        
        if ($caching) {
            $this->Smarty->cache = true;
        }
        
        return $html;
        
    }
    
    
}