Jump to:

17452 Posts in 4473 Topics by 1971 members

Archive

SilverStripe Forums » Archive » Pagination - Is it possible to use the page number rather than starting point

Our old forums are still available as a read-only archive.

Moderators: martimiz, Sean, biapar, Willr, Ingo, simon_w

Page: 1
Go to End
Author Topic: 2170 Views
  • Hammy
    Avatar
    Community Member
    49 Posts

    Pagination - Is it possible to use the page number rather than starting point Link to this post

    I've set up the pagination from the example on the site:
    http://doc.silverstripe.com/doku.php?id=private:recipes:pagination

    However I was wondering if this could be (or has been) improved a little. Instead of having the url parameter

    "?start=<num>"

    to indicate where to start the list from, is it possible to use the current page number instead (ie

    "?page=<num>"

    where page indicates the page number that you are on) and use the page number to figure out where to start the list from?

    The reason is that the url parameter "start" is a little ambiguous when you first land on it. What does start really mean? Using page instead is a little more meaning full.

    Also, if I wanted to increase or decrease the number of items (say from 15 to 10 listed items), links from external sites will show the updated list incorrectly. By using the page number instead, this will allow for less disruptions with such changes to the site for users coming from outside sources.

  • Hammy
    Avatar
    Community Member
    49 Posts

    Re: Pagination - Is it possible to use the page number rather than starting point Link to this post

    Can anyone help me with this?

    I just want to know if this has been (or can be) done? I just want to make sure I'm not wasting time when there is something already out there

  • Ingo
    Avatar
    Forum Moderator
    801 Posts

    Re: Pagination - Is it possible to use the page number rather than starting point Link to this post

    a "page" parameter can be transferred to a "start" parameter by multiplying it with the pagesize, right? so should be trivial to implement, given that you form the query in custom code (function NewsArticles() in the tutorial)

  • Hammy
    Avatar
    Community Member
    49 Posts

    Re: Pagination - Is it possible to use the page number rather than starting point Link to this post

    Hi Ingo,

    Thanks for your input. On the same topic, I've created the functionality to reference the page number rather than the starting point but have an SEO issue else where.

    When browsing down the relavent page numbers and to head back to the first page, on the list of page number links that I have at the bottom of the list, the link to page 1 (the first page of the list), instead of simply linking to domain.com/products/ it has the url domain.com/products/?page=1. I believe this is duplicating the same page unnessarily and could effect the page within search engine results.

    I've made the following updates, but have been unable to figure out how to return the page url without the parameters? (In DataObjectSet.php - the comment "// How is this done?" is where I think this functionality needs to be added, but have been thinking it could be made in the ProductHolder template - all code below).

    Any ideas?

    In Page.php, i've added:

    class Page_Controller extends ContentController {
       ...
       function ProductList(){
          $source = 'ProductPage';
          $filter = 'StartDate < NOW() AND StartDate IS NOT NULL AND (EndDate > NOW() OR EndDate IS NULL)';
          $sort= 'StartDate DESC';
          $start;
          $page; // Page Number From URL Parameter
          $num=5;
          
          if(!isset($_GET['page']) || !is_numeric($_GET['page']) || (int)$_GET['page'] < 1) {
             $start = $_GET['page'] = 0;
          } else {
             $page = $_GET['page'];
             $start = ($page - 1) * $num;
          }
          
          $latestProducts = DataObject::get($source,$filter,$sort,'',$start.','.$num);
          return $latestProducts ? $latestProducts : false;
       }
       ...
    }

    I've also had to update the DataObjectSet.php (tho ideally i need to bring this functionality out of here to avoid issues when upgrading silverstripe)

          
       // Custom Pagination
       
       protected $pageNumGetVar = "page";
       
       public function PageNums($maxPages = 0){
          $ret = new DataObjectSet();

          if($maxPages) {
             $startPage = ($this->CurrentPage() - floor($maxPages / 2)) - 1;
             $endPage = $this->CurrentPage() + floor($maxPages / 2);

             if($startPage < 0) {
                $startPage = 0;
                $endPage = $maxPages;
             }
             if($endPage > $this->TotalPages()) {
                $endPage = $this->TotalPages();
                $startPage = max(0, $endPage - $maxPages);
             }

          } else {
             $startPage = 0;
             $endPage = $this->TotalPages();
          }

          for($i=$startPage; $i < $endPage; $i++){
             if($i == 0) {
                // $link = Should be just the url without parameters. If page is equal to 1 then $link should be with parameters
                // How is this done?
                $link = HTTP::setGetVar($this->pageNumGetVar, $i + 1);
             } else {
                $link = HTTP::setGetVar($this->pageNumGetVar, $i + 1);
             }
             $thePage = new ArrayData(array(
                   "PageNum" => $i+1,
                   "Link" => $link,
                   "CurrentBool" => ($this->CurrentPage() == $i+1)?true:false,
                   )
             );
             $ret->push($thePage);
          }
          
          return $ret;
       }
       
       public function PageNextLink() {
          if($this->pageStart + $this->pageLength < $this->totalSize) {
             return HTTP::setGetVar($this->pageNumGetVar, $this->CurrentPage() + 1);
          }
       }
       
       public function PagePrevLink() {
          if($this->pageStart - $this->pageLength >= 0) {
             return HTTP::setGetVar($this->pageNumGetVar, $this->CurrentPage() - 1);
          }
       }
       ....
    }

    And the template ProductHolder.ss contains the following

       <% if ProductList.MoreThanOnePage %>
          <div class="pagination">
             <ul>
                <% if ProductList.PrevLink %>
                   <li class="prev"><a href="$ProductList.PagePrevLink">Prev</a></li>
                <% end_if %>
                
                <% control ProductList.PageNums %>
                   <% if CurrentBool %>
                      <li class="current">$PageNum</li>
                   <% else %>
                      <li><a href="$Link">$PageNum</a></li>
                   <% end_if %>
                <% end_control %>
                
                <% if ProductList.NextLink %>
                   <li class="next"><a href="$ProductList.PageNextLink">Next</a></li>
                <% end_if %>
             </ul>
             <p class="pages">Page $ProductList.CurrentPage of $ProductList.TotalPages Pages</p>
          </div>
       <% end_if %>   
    ...

  • Hammy
    Avatar
    Community Member
    49 Posts

    Re: Pagination - Is it possible to use the page number rather than starting point Link to this post

    Sorry (I always manage to copy and paste something incorrectly) - the DataObjectSet.php update is as follows:

    class DataObjectSet extends ViewableData implements IteratorAggregate {
    ...
       // Custom Pagination
       
       protected $pageNumGetVar = "page";
       
       public function PageNums($maxPages = 0){
          $ret = new DataObjectSet();

          if($maxPages) {
             $startPage = ($this->CurrentPage() - floor($maxPages / 2)) - 1;
             $endPage = $this->CurrentPage() + floor($maxPages / 2);

             if($startPage < 0) {
                $startPage = 0;
                $endPage = $maxPages;
             }
             if($endPage > $this->TotalPages()) {
                $endPage = $this->TotalPages();
                $startPage = max(0, $endPage - $maxPages);
             }

          } else {
             $startPage = 0;
             $endPage = $this->TotalPages();
          }

          for($i=$startPage; $i < $endPage; $i++){
             if($i == 0) {
             // $link = Should be just the url without parameters.
    // How is this done?
                $link = HTTP::setGetVar($this->pageNumGetVar, $i + 1);
             } else {
                $link = HTTP::setGetVar($this->pageNumGetVar, $i + 1);
             }
             $thePage = new ArrayData(array(
                   "PageNum" => $i+1,
                   "Link" => $link,
                   "CurrentBool" => ($this->CurrentPage() == $i+1)?true:false,
                   )
             );
             $ret->push($thePage);
          }
          
          return $ret;
       }
       
       public function PageNextLink() {
          if($this->pageStart + $this->pageLength < $this->totalSize) {
             return HTTP::setGetVar($this->pageNumGetVar, $this->CurrentPage() + 1);
          }
       }
       
       public function PagePrevLink() {
          if($this->pageStart - $this->pageLength >= 0) {
             return HTTP::setGetVar($this->pageNumGetVar, $this->CurrentPage() - 1);
          }
       }
       
    }

  • Ingo
    Avatar
    Forum Moderator
    801 Posts

    Re: Pagination - Is it possible to use the page number rather than starting point Link to this post

    Cool! I don't think its appropriate to merge into DataObjectSet at the current stage, because its going to be confusing with two very similiar implementations side-by-side. Perhaps we can move this functionality into a "Paginator" interface with different implementations?
    For now, I'd suggest you put your code into a DataObjectDecorator, and access the DataObjectSet methods and properties through $this->owner instead of $this. Here's something to get you started:

    http://pastie.org/315397

    You can attach the decorator to each DataObjectSet with the following code in your _config.php:

    Object::add_extension('DataObjectSet', 'PaginatedByPage');

  • Hammy
    Avatar
    Community Member
    49 Posts

    Re: Pagination - Is it possible to use the page number rather than starting point Link to this post

    Hi Ingo,

    Awesome! Was trying to figure out how to separate my custom pagination from the DataObjectSet.

    For some reason the conditional statements aren't working as expected in the methods PageNextLink and PagePrevLink, however if you remove the IF condition and use NextLink and PrevLink in the ss Templates, this works fine. From a developers perspective - is this ok? For the moment it works, so I'm happy...

    Just one issue tho, I'm still not sure how to grab just the url without the parameters for links to the first page (ie instead of domain.com/products/?page=1, use domain.com/products/ - see comment in /mysite/code/PaginatedByPage.php code below "// $link = Should be just the url without parameters." where I think this needs to be added).

    Updates are as follows:

    /mysite/_config.php

    <?php
    ...
       // Custom Pagination by page number reference
       Object::add_extension('DataObjectSet', 'PaginatedByPage');
    ...
    ?>

    /mysite/code/PaginatedByPage.php

    <?php
    class PaginatedByPage extends Extension {

       protected $pageNumGetVar = "page";
       
       public function PageNums($maxPages = 0){
          $ret = new DataObjectSet();
          if($maxPages) {
             $startPage = ($this->owner->CurrentPage() - floor($maxPages / 2)) - 1;
             $endPage = $this->owner->CurrentPage() + floor($maxPages / 2);

             if($startPage < 0) {
                $startPage = 0;
                $endPage = $maxPages;
             }
             if($endPage > $this->owner->TotalPages()) {
                $endPage = $this->owner->TotalPages();
                $startPage = max(0, $endPage - $maxPages);
             }

          } else {
             $startPage = 0;
             $endPage = $this->owner->TotalPages();
          }

          for($i=$startPage; $i < $endPage; $i++){
             if($i == 0) {
             // $link = Should be just the url without parameters.
              // How is this done? Change $link below
                $link = HTTP::setGetVar($this->pageNumGetVar, $i + 1);
             } else {
                $link = HTTP::setGetVar($this->pageNumGetVar, $i + 1);
             }
             $thePage = new ArrayData(array(
                   "PageNum" => $i+1,
                   "Link" => $link,
                   "CurrentBool" => ($this->owner->CurrentPage() == $i+1)?true:false,
                   )
             );
             $ret->push($thePage);
          }
          return $ret;
       }

       public function PageNextLink() {       
          return HTTP::setGetVar($this->pageNumGetVar, $this->owner->CurrentPage() + 1);
       }

       public function PagePrevLink() {
          return HTTP::setGetVar($this->pageNumGetVar, $this->owner->CurrentPage() - 1);
       }
    }
    ?>

    ProductHolder.ss

    ...
       <% if ProductList.MoreThanOnePage %>
          <div class="pagination">
             <ul>
                <% if ProductList.PrevLink %>
                   <li class="prev"><a href="$ProductList.PagePrevLink">Prev</a></li>
                <% end_if %>
                
                <% control ProductList.PageNums %>
                   <% if CurrentBool %>
                      <li class="current">$PageNum</li>
                   <% else %>
                      <li><a href="$Link">$PageNum</a></li>
                   <% end_if %>
                <% end_control %>
                
                <% if ProductList.NextLink %>
                   <li class="next"><a href="$ProductList.PageNextLink">Next</a></li>
                <% end_if %>
             </ul>
             <p class="pages">Page $ProductList.CurrentPage of $ProductList.TotalPages Pages</p>
          </div>
       <% end_if %>   
    ...

    2170 Views
Page: 1
Go to Top

Want to know more about the company that brought you SilverStripe? Then check out SilverStripe.com

Comments on this website? Please give feedback.