Skip to content

Digg Style Pagination

World Wide Web Server edited this page Jul 4, 2012 · 10 revisions

Category:Libraries

[h3]Digg Style Pagination Library[/h3]

The existing pagination class is sufficient, however, I wanted to produce digg-style pagination.

See here for an example of what I mean - http://www.strangerstudios.com/sandbox/pagination/diggstyle.php . A lot of the updated code has been taken from the script provided there. However, some other improvements/alterations have also been made. Basically this is a mish-mash between the CI_Pagination library and the code found at the above link.

Benefits

  • ability to let the user control how many records per page they would like to see. The url's for this are in the form of /controller/function/perpage/page. E.g. /controller/function/10/2 means show 10 records per page, and show the second page. Therefore you would be getting records 11- 20. Make sense?
  • pages are in terms of page numbers (e.g. /view/10/2 means page 2 rather than offset of 2 which is more logical to me)
  • if there are 100 pages (for example) rather than showing only a few pages either side of this in the pagination, digg-style will show a few pages either side as well as the first couple of pages and the last couple of pages. I think this increases usability.
  • i think it looks better :)

[b]I have only overwritten the existing CI_Pagination class. This is a bit lazy but if you want to do the right thing you should probably rename it and call it as a custom-made library. This is my first library and I am not a guru PHP coder so there may well be something which can be optimised further or some minor bugs. Test it thoroughly before using in anything critical.[/b]

Ok first of all, the updated /system/libraries/Pagination.php file.

[code]<?php if (!defined('BASEPATH')) exit('No direct script access allowed'); /**

// ------------------------------------------------------------------------

/**

  • Pagination Class

  • @package CodeIgniter

  • @subpackage Libraries

  • @category Pagination

  • @author Rick Ellis

  • @link http://www.codeigniter.com/user_guide/libraries/pagination.html */ class CI_Pagination {

    var $base_url = ''; // The page we are linking to var $total_rows = ''; // Total number of items (database results) var $per_page = 10; // Max number of items you want shown per page var $num_links = 2; // Number of "digit" links to show before/after the currently viewed page var $cur_page = 0; // The current page being viewed var $first_link = '‹ First'; var $next_link = '>'; var $prev_link = '<'; var $last_link = 'Last ›'; var $uri_segment = 3; var $full_tag_open = ''; var $full_tag_close = ''; var $first_tag_open = ''; var $first_tag_close = ''; var $last_tag_open = ''; var $last_tag_close = ''; var $cur_tag_open = ''; var $cur_tag_close = ''; var $next_tag_open = ''; var $next_tag_close = ''; var $prev_tag_open = ''; var $prev_tag_close = ''; var $num_tag_open = ''; var $num_tag_close = '';

    /**

    • Constructor

    • @access public

    • @param array initialization parameters */ function CI_Pagination($params = array()) { if (count($params) > 0) { $this->initialize($params);
      }

      log_message('debug', "Pagination Class Initialized"); }

    // --------------------------------------------------------------------

    /**

    • Initialize Preferences
    • @access public
    • @param array initialization parameters
    • @return void */ function initialize($params = array()) { if (count($params) > 0) { foreach ($params as $key => $val) { if (isset($this->$key)) { $this->$key = $val; } }
      } }

    // --------------------------------------------------------------------

    /**

    • Generate the pagination links

    • @access public

    • @return string */
      function create_links() { // If our item count or per-page total is zero there is no need to continue. if ($this->total_rows == 0 OR $this->per_page == 0) { return ''; }

      // Calculate the total number of pages $num_pages = ceil($this->total_rows / $this->per_page);

      // Is there only one page? Hm... nothing more to do here then. if ($num_pages == 1) { return ''; }

      // Determine the current page number.
      $CI =& get_instance();
      if ($CI->uri->segment($this->uri_segment) != 0) { $this->cur_page = $CI->uri->segment($this->uri_segment);

       // Prep the current page - no funny business!
       $this->cur_page = preg_replace("/[a-z\-]/", "", $this->cur_page);
      

      } else { $this->cur_page = 1; }

      if ( ! is_numeric($this->cur_page)) { $this->cur_page = 0; }

      // Is the page number beyond the result range? // If so we show the last page if ($this->cur_page > $num_pages) { $this->cur_page = $num_pages; }

      $uri_page_number = $this->cur_page; //$this->cur_page = floor(($this->cur_page/$this->per_page) + 1);

      // Add a trailing slash to the base URL if needed $this-&gt;base_url = preg_replace("/(.+?)/*$/", "\1/", $this->base_url);

      // And here we go... $pagination = '';

      // Render the "First" link if ($this->cur_page > 1) { $pagination .= $this->first_tag_open.''.$this->first_link.''.$this->first_tag_close; } else $pagination.= "<span class="disabled">".$this->first_link."";

      // Render the "previous" link if ($this->cur_page > 1) { $prev = $this->cur_page - 1; $pagination .= $this->prev_tag_open.''.$this->prev_link.''.$this->prev_tag_close; } else $pagination.= "<span class="disabled"><";

      if ($num_pages < 7 + ($this->num_links * 2)) //not enough pages to bother breaking it up { for ($counter = 1; $counter <= $num_pages; $counter++) { if ($counter == $this->cur_page) { $pagination .= "<span class="current">$counter"; // Current page } else { $pagination .= $this->num_tag_open.''.$counter.''.$this->num_tag_close; } } } elseif($num_pages > 5 + ($this->num_links * 2)) //enough pages to hide some { //close to beginning; only hide later pages if($this->cur_page < 1 + ($this->num_links * 2)) { for ($counter = 1; $counter < 4 + ($this->num_links * 2); $counter++) { if ($counter == $this->cur_page) { $pagination .= "<span class="current">$counter"; // Current page } else { $pagination .= $this->num_tag_open.''.$counter.''.$this->num_tag_close; } }

           $pagination.= "...";
           
           $num_pages_minus = $num_pages-1;
           $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$num_pages_minus.'">'.$num_pages_minus.'</a>'.$this->num_tag_close;
           $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$num_pages.'">'.$num_pages.'</a>'.$this->num_tag_close;    
       }
       //in middle; hide some front and some back
       elseif($num_pages - ($this->num_links * 2) > $this->cur_page && $this->cur_page > ($this->num_links * 2))
       {
           $one=1;
           $two=2;
      
           $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$one.'">'.$one.'</a>'.$this->num_tag_close;
           $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$two.'">'.$two.'</a>'.$this->num_tag_close;
           
           $pagination.= "...";
           
           for ($counter = $this->cur_page - $this->num_links; $counter <= $this->cur_page + $this->num_links; $counter++)
           {
               if ($counter == $this->cur_page)
               {
                   $pagination.= "<span class=\"current\">$counter</span>";
               }
               else
               {
                   $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$counter.'">'.$counter.'</a>'.$this->num_tag_close;
               }
           }
           $pagination.= "...";
      
           $num_pages_minus = $num_pages-1;
           $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$num_pages_minus.'">'.$num_pages_minus.'</a>'.$this->num_tag_close;
           $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$num_pages.'">'.$num_pages.'</a>'.$this->num_tag_close;    
       }
       //close to end; only hide early pages
       else
       {
           $one=1;
           $two=2;
      
           $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$one.'">'.$one.'</a>'.$this->num_tag_close;
           $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$two.'">'.$two.'</a>'.$this->num_tag_close;
           
           $pagination.= "...";
           
           for ($counter = $num_pages - (2 + ($this->num_links * 2)); $counter <= $num_pages; $counter++)
           {
               if ($counter == $this->cur_page)
               {
                   $pagination.= "<span class=\"current\">$counter</span>";
               }
               else
               {
                   $pagination .= $this->num_tag_open.'<a href="'.$this->base_url.$counter.'">'.$counter.'</a>'.$this->num_tag_close;
               }
           }
       }
      

      }

      // Render the "next" link if ($this->cur_page < $counter - 1) { $next = $this->cur_page + 1; $pagination .= $this->next_tag_open.''.$this->next_link.''.$this->next_tag_close; } else $pagination.= "<span class="disabled">>";

      // Render the "Last" link if ($this->cur_page < $counter - 1) { $pagination .= $this->last_tag_open.''.$this->last_link.''.$this->last_tag_close; } else $pagination.= "<span class="disabled">".$this->last_link."";

      // Kill double slashes. Note: Sometimes we can end up with a double slash // in the penultimate link so we'll kill all double slashes. $pagination = preg_replace("#([^:])//+#", "\1/", $pagination);

      // Add the wrapper HTML if exists $pagination = $this->full_tag_open.$pagination.$this->full_tag_close;

      return $pagination;
      } } // END Pagination Class ?>[/code]

Secondly, a new pagination plugin to keep our controller files a bit cleaner So, make a new file here /system/plugins/pagination_pi.php

[code]<?php

/**

  • Initalises pagination config settings and returns the create_links string.

  • @param unknown_type $cur_page_seg

  • @param unknown_type $total_rows

  • @param unknown_type $per_page_val

  • @param unknown_type $per_page_seg

  • @param unknown_type $pbase_url

  • @return string */ function init_paginate ($cur_page_seg, $total_rows, $per_page_val, $per_page_seg, $pbase_url) {
    $obj =& get_instance();

    //load relevant libraries $obj->load->library('pagination');

    //pagination setup echo $per_page_val; $pbase_url = $pbase_url."/".$per_page_val; $config['base_url'] = $pbase_url; $config['total_rows'] = $total_rows; $config['per_page'] = $per_page_val; $config['uri_segment'] = $cur_page_seg;

    //pagination initialization $obj->pagination->initialize($config);

    return $obj->pagination->create_links(); // end paging }

/**

  • Works out how many records should be shown per page. The value will either be taken from

  • 1. The uri segment
    
    1. The default value set in the controller; or
    1. A default upper/lower range if people try to do tricky things in the uri segment (e.g. negative
  • values).
    
  • @param unknown_type $per_page_val

  • @param unknown_type $per_page_seg

  • @return unknown */ function get_per_page($per_page_val, $per_page_seg) {
    $per_page = validate_per_page($per_page_val, $per_page_seg);

    return $per_page; }

/**

  • Validates the per page val and returns the value. Will check for out of bounds and non-numerical values

  • @param unknown_type $per_page_val

  • @param unknown_type $per_page_seg

  • @return unknown */ function validate_per_page($per_page_val, $per_page_seg) { $obj =& get_instance();

    //use per page if set from the uri, otherwise use default value set in controller $per_page = $obj->uri->segment($per_page_seg, $per_page_val);

    //security check - ensure value is numeric if (is_numeric($per_page)) : $per_page=$per_page; else: $per_page = $per_page_val; endif;

    //limit the per page value - prevents someone from doing a query of 1000 rows etc if ($per_page > 100) : $per_page = 100; endif;

    //limit the per page value from negative numbers if ($per_page < 1) : $per_page = 10; endif;

    return $per_page; }

/**

  • Will work out what offset should be used for a given sql query for a given pag

  • @param unknown_type $cur_page_seg

  • @param unknown_type $per_page_val

  • @return unknown */ function get_offset($cur_page_seg, $per_page_val) { $obj =& get_instance();

    //determine offset - per_page_val has already been validated $page = 1; if ($obj->uri->segment($cur_page_seg, 0)) : $page = $obj->uri->segment($cur_page_seg, 0); endif; if ( $page == 1): $offset = 0; else : $offset = ($page - 1) * $per_page_val; endif;

    return $offset; } ?>[/code]

Thirdly, our controller file. To use the pagination, add this to the controller.

[code] $this->load->model('My_Model', 'sql', TRUE);

    //********************SET UP PAGINATION VALUES****************************
    //set up per_page_value, per_page_seg, cur_page_seg and $data['pbase_url']
    //************************************************************************
    $this->load->plugin('pagination'); 
    
    $per_page_value = 5;  //default - unless overridden later
    $per_page_seg = 5;    //the uri segment for the per page value
    $cur_page_seg = 6;      //the url segment for the current page value (generally +1 of per page seg)
    
    $per_page = get_per_page($per_page_value, $per_page_seg); 
    $offset = get_offset($cur_page_seg, $per_page); 
    
    //generate the query
    $data['query'] = $this->sql->get_records($offset, $per_page);
    
    //find out the total amount of records
    $total_rows = count($this->sql->get_records(NULL, NULL));
    
    $data['pbase_url'] = base_url().'path/to/controller/';
    init_paginate($cur_page_seg, $total_rows, $per_page, $per_page_seg, $data['pbase_url']); 
            
    $this->load->view('path/to/controller', $data);

[/code]

Fourthly, an example function from out model file.

[code] function get_records($offset, $limit) { //add where clause processing here if required

    $this->db->select('*');    
    //$this->db->having($having);
    
            if ($offset != NULL)
        $this->db->offset($offset);
    if ($limit != NULL)
        $this->db->limit($limit);
    
    if ($limit == NULL && $offset == NULL)
    {
        $count = $this->db->get('my_table');
        return $count->result_array();
    }
    else
        return $this->db->get('my_table');
}

[/code]

Fifthly, our view file. Wherever you want the pagination to be, add this:

[code]

<?php echo $this->pagination->create_links();?>
<!-- this is the number of records part - an example only -->
10 | 20
[/code]

Sixthly, and also lastly, here is an example css file

[code] div.pagination { padding: 3px; margin: 3px; }

div.pagination a { padding: 2px 5px 2px 5px; margin: 2px; border: 1px solid #AAAADD; text-decoration: none; /* no underline */ color: #000099; }

div.pagination a:hover, div.pagination a:active { border: 1px solid #000099; color: #000; }

div.pagination span.current { padding: 2px 5px 2px 5px; margin: 2px; border: 1px solid #000099; font-weight: bold; background-color: #993300; color: #FFF; } div.pagination span.disabled { padding: 2px 5px 2px 5px; margin: 2px; border: 1px solid #EEE; color: #DDD; } [/code]

Hope it helps someone out there!

Clone this wiki locally