Skip to content

How to properly use Zend_Paginator

2009 June 4
by Richard Knop

Zend_Paginator is one of the best pagination classes you can find on the Web these days. It is flexible and works with any data collections (not just relational databases).

Unfortunately, many people use it incorrectly. The mistake they’re making is passing a complete dataset to the paginaton class which gets slower and extremely inefficient as the amount of data in the database grows.

The solution is to pass only a select object to the pagination class. I usually write a special method that returns only a select object without fetching any data:

  1. class Posts extends Zend_Db_Table_Abstract
  2. {
  3.     protected $_name = 'posts';
  4.  
  5.     public function getSelect()
  6.     {
  7.         $select = $this->select();
  8.         $select->order('id DESC');
  9.         return $select;
  10.     }
  11. }

The rest is quite straightforward. In the controller I initialize a Zend_Paginator instance, configure it (I use $_GET['p'] for a current page number) and pass it to the view. Notice the _getTable() method. It saves me lots of time because I don’t have to include and initialize models manually:

  1. class IndexController extends Zend_Controller_Action
  2. {
  3.     private $_tables = array();
  4.  
  5.     private function _getTable($table)
  6.     {
  7.         if (!isset($this->_tables[$table])) {
  8.             include APPLICATION_PATH . '/modules/default/models/' . $table . '.php';
  9.             $this->_tables[$table] = new $table();
  10.         }
  11.         return $this->_tables[$table];
  12.     }
  13.  
  14.     public function indexAction()
  15.     {
  16.         $request = $this->getRequest();
  17.         $posts = $this->_getTable('Posts');
  18.  
  19.         $paginator = Zend_Paginator::factory($posts->getSelect());
  20.         $paginator->setCurrentPageNumber($request->getParam('p'));
  21.         $paginator->setItemCountPerPage(10);
  22.  
  23.         $this->view->posts = $paginator;
  24.     }
  25. }

Then in the view I iterate through the data (in this example scenario blog posts) and print the pagination control:

  1. <?php if (count($this->posts)): ?>
  2. <?php foreach($this->posts as $post): ?>
  3. <?php // display a post content here etc ?>
  4. <?php endforeach; ?>
  5. <?php endif; ?>
  6. <?php echo $this->paginationControl($this->posts, 'Sliding',
  7.                                     'pagination.phtml'); ?>

I use this pagination template (it’s very similar to the one in the Zend Framework documentation, I use a more semantic markup though):

  1. <?php if ($this->pageCount > 1): ?>
  2. <ul class="pagination">
  3. <!– Previous page link –>
  4. <?php if (isset($this->previous)): ?>
  5. <li><a href="<?php echo $this->url(array('module' => 'default',
  6.                                         'controller' => 'index',
  7.                                         'action' => 'index',
  8.                                         'p' => $this->previous),
  9.                                   null,
  10.                                   true); ?>"><img src="/css/previous.png" alt="previous" title="previous" /></a></li>
  11. <?php else: ?>
  12. <li><img src="/css/previous.png" alt="previous" title="previous" /></li>
  13. <?php endif; ?>
  14. <!– Numbered page links –>
  15. <?php foreach ($this->pagesInRange as $page): ?>
  16. <?php if ($page != $this->current): ?>
  17. <li><a href="<?php echo $this->url(array('module' => 'default',
  18.                                         'controller' => 'index',
  19.                                         'action' => 'index',
  20.                                         'p' => $page),
  21.                                   null,
  22.                                   true); ?>"><?php echo $page; ?></a></li>
  23. <?php else: ?>
  24. <li><?php echo $page; ?> </li>
  25. <?php endif; ?>
  26. <?php endforeach; ?>
  27. <!– Next page link –>
  28. <?php if (isset($this->next)): ?>
  29. <li><a href="<?php echo $this->url(array('module' => 'default',
  30.                                         'controller' => 'index',
  31.                                         'action' => 'index',
  32.                                         'p' => $this->next),
  33.                                   null,
  34.                                   true); ?>"><img src="/css/next.png" alt="next" title="next" /></a></li>
  35. <?php else: ?>
  36. <li><img src="/css/next.png" alt="next" title="next" /></li>
  37. <?php endif; ?>
  38. </ul>
  39. <?php endif; ?>

I often have more than one pagination template so I usually create a path/to/a/module/views/scripts/pagination directory where I keep them.

No comments yet

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS