Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Zend\Paginator : Paginate Your Data

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on July 23, 2012

Zend Framework has a component named Zend\Paginator. It can paginate items into pages, paginate arbitrary data, not just relational databases, and fetch only the results that need to be displayed.


For example, i have a array data like this :

$dataItems =  array(
                 0 => array('id'=>1, 'name'=>'samsonasik'),
                 1 => array('id'=>2, 'name'=>'abdul malik ikhsan'),
                 2 => array('id'=>3, 'name'=>'superman'),
         );

And route :

'Test' => array(
    'type'    => 'Segment',
    'options' => array(
        // Change this to something specific to your module
        'route'    => '/[:lang]/test[/:page]',
        'defaults' => array(
            '__NAMESPACE__' => 'Test\Controller',
            'controller'    => 'Test',
            'action'        => 'index',
         ),
      ),
      //........
),

and we will access as http://localhost/zf2app/public/en/test/1 or http://localhost/zf2app/public/en/test/2.
First step, we create a Requesthelper view helper for handling GET parameter if passed by url.

namespace Test\View\Helper;
use Zend\View\Helper\AbstractHelper;

class Requesthelper extends AbstractHelper
{
    protected $request;
    
    //get Request
    public function setRequest($request)
    {
        $this->request = $request;    
    }
    
    public function getRequest()
    {
        return $this->request;    
    }
    
    public function __invoke()
    {
        return $this->getRequest()->getServer()->get('QUERY_STRING');     
    }
}

And then, register it and pass Request object :

'Requesthelper' => function($sm){
   $helper = new View\Helper\Requesthelper;
   $request = $sm->getServiceLocator()->get('Request');
   $helper->setRequest($request);
   return $helper;
}

Next, create a file, for example named pager.phtml:
and write the following of codes into pager.pthml :

<?php
$url = $this->url('Test', array('lang'=>$this->lang));
//handle parameter get 🙂
$parameterGet = $this->Requesthelper();
if ($parameterGet != ""){
  $parameterGet = "?".$parameterGet;
}
?>

<?php if ($this->pageCount): ?>
<div class="paginationControl">
    <p>
	    <!--<div style="float:left">-->
      <!-- Previous page link -->
      <?php if (isset($this->previous)): ?>
     <a class="first" href="<?= $url.'/1'; ?>">&lt;&lt; first&nbsp;&nbsp;</a>
     <a class="Previous" href="<?= $url.'/'.$this->previous.$parameterGet; ?>">&lt; prev&nbsp;&nbsp;</a>      
      <?php else: ?>
      <b><i>&lt;&lt; first&nbsp;&nbsp;</i></b>
      <b><i>&lt; prev&nbsp;&nbsp;</i></b>      
      <?php endif; ?>
      <?php foreach ($this->pagesInRange as $page): ?>
      <?php if ($page != $this->current): ?>
        <a class="nopage" href="<?= $url.'/'.$page.$parameterGet; ?>">
      <?= $page; ?>
      </a>&nbsp;
      <?php else: ?>
            <span class="nopage">
      <?= $page; ?>
    </span>
      </b>&nbsp;
      <?php endif; ?>
      <?php endforeach; ?>
      <?php if (isset($this->next)): ?>
      <a class="next" href="<?= $url.'/'.$this->next.$parameterGet; ?>">&nbsp;next &gt;</a>
      <a class="next" href="<?= $url.'/'.$this->pageCount.$parameterGet; ?>">&nbsp;last &gt;&gt;</a>
      <?php else: ?>      	
	   <b><i>&nbsp;next &gt;&nbsp;</i></b>
	   <b><i>&nbsp;last &gt;&gt;&nbsp;</i></b>
      <?php endif; ?>
    </p>
</div>
<?php endif; ?>

Preparation done, so we can set the fake data to test it in the controller and pass the data to the component :

$matches = $this->getEvent()->getRouteMatch();
$page      = $matches->getParam('page', 1);

$dataItems =    array(
      0 => array('id'=>1, 'name'=>'samsonasik'),
      1 => array('id'=>2, 'name'=>'abdul malik ikhsan'),
      2 => array('id'=>3, 'name'=>'superman'),
  );
$paginator = new \Zend\Paginator\Paginator(new
                    \Zend\Paginator\Adapter\ArrayAdapter($dataItems)
              );

$paginator->setCurrentPageNumber($page);
$paginator->setItemCountPerPage(2);

return new ViewModel(array(
   'test' => $paginator,
   'lang' => $matches->getParam('lang','en')
));

So, in View, we can call :

<?php foreach($test as $key=>$row) : ?>
    <?php echo $row['id']; ?> : <?php echo $row['name']; ?> <br />
<?php endforeach; ?>

<?= ( count($test) > 0 ) ? $this->paginationControl($test, 'Sliding', 'pager.phtml', array('lang'=>$lang)) : ""; ?>


[UPDATE]
How about Paginate data from database ?
First, buffer() the resultSet object :

..................
    public function fetchAll()
    {
        $resultSet = $this->select(function (Select $select){
            $select->columns(array('id', 'name'));
            $select->order(array('id asc'));  
        });
        
        $resultSet->buffer();
        $resultSet->next();
         
        return $resultSet; 
     }
...................

And use Iterator adapter :

        $iteratorAdapter = new \Zend\Paginator\Adapter\Iterator($this->getSampleTable()->fetchAll());
        $paginator = new \Zend\Paginator\Paginator($iteratorAdapter);

DONE !

60 Responses

Subscribe to comments with RSS.

  1. […] ZendPaginator : Paginate Your Data […]

  2. user said, on October 26, 2012 at 4:23 pm

    Hi!
    What is the value of the variable $ page in your controller? example print_r ($page); die;

  3. loktheprince said, on December 5, 2012 at 6:48 pm

    can you post git link for this tutorial

  4. Edgar Martinez said, on December 28, 2012 at 12:44 am

    would fetchAll() not return all the records in the DB or would it set a limit and a offset? how would we set up pagination without having to return all the records in the Database

    • samsonasik said, on December 28, 2012 at 3:52 am
              $resultSet = $this->select(function (Select $select){
                  $select->columns(array('id', 'name'));
                  $select->limit(5);
                  $select->order(array('id asc'));  
              });
      
      • alban said, on April 22, 2013 at 7:41 pm

        this is not still clear to me, you are just limiting the results here, so how would the paginator understand the total number of results?

      • samsonasik said, on April 23, 2013 at 12:03 am

        try :

        $paginator->getCurrentItemCount();
        $paginator->getTotalItemCount();
        
  5. Fabien said, on February 28, 2013 at 1:09 am

    I followed this tutorial from A to Z but can’t make the Requesthelper working. I got this error : “Catchable fatal error: Instantiation of ‘Closure’ is not allowed” any idea why? Thank you samsonasik for your blog it’s very helpfull.

    • samsonasik said, on February 28, 2013 at 2:15 am

      clone my repo : https://github.com/samsonasik/SanSamplePagination

      • Fabien said, on February 28, 2013 at 12:23 pm

        Thank you for your answer. I tried to use the repo but I got the same error. This error coming from the line 4 of pager.phtml when pager call Requesthelper :

        $parameterGet = $this->Requesthelper();

        I’m using Zf 2.1.3.

      • samsonasik said, on March 1, 2013 at 5:31 am

        you should check your php version, it need >= php 5.3.3

      • Fabien said, on March 1, 2013 at 12:45 pm

        I have Php 5.3.4. I don’t understand what’s wrong

      • samsonasik said, on March 1, 2013 at 1:36 pm

        It’s weird, read your apache error log.

      • Fabien said, on March 2, 2013 at 3:03 pm

        I finally found what’s wrong. I was inclunding the helper twice. Now working fine. Thank you very much for your help you can delete my previous message.

  6. samsonasik said, on March 2, 2013 at 5:02 pm

    No problem, you’re welcome ;),

  7. tinef said, on March 7, 2013 at 4:26 am

    Thanks! Helped me out! 😉

  8. zakaria said, on April 8, 2013 at 9:43 pm

    Thanks!
    but I want to know if I can use paginator in plusieure module without duplication

    • samsonasik said, on April 8, 2013 at 11:57 pm

      No. you are not duplicate it. all zf module config are merged.

  9. msilva66 said, on April 22, 2013 at 3:38 am

    Nice code… But… Is there a way of doing your code to work on everywhere I want?
    Like… I want to put it on a lib called Commons so I can use the paginator on every module I need it.
    I am almost getting it, but got stucked.

    • samsonasik said, on April 22, 2013 at 10:51 am

      all module config are merged, just define it in one module, and you can use it everywhere.

  10. Juniawan Adalah Pan Ganesh said, on May 13, 2013 at 6:05 am

    Boss, Thanks sebelumnya sudah berbagi tutorial yang berguna ini. Dilihat dari code diatas, berarti kita meload semua data dulu ($this->getSampleTable()->fetchAll())?
    Kalau iya, ini kan akan sangat mengganggu performance kalau berhubungan dengan data yang besar. Apa harus saya membuat custom paginator(menggunakan db), atau ada cara lain menggunakan Paginator agar paginator ini tidak mengganggu masalah performance, yang mungkin(pasti) ada yang saya tidak ketahui?

    Saya lagi mempelajari Zend\Paginator\Paginator

    Thanks sebelumnya,

    Salam
    Juniawan

    • samsonasik said, on May 13, 2013 at 6:09 am

      Zend Framework punya banyak adapter : DbSelect, DbTableGateway, Iterator, ArrayAdapter, dan Null. tinggal pilih aja. Latest artikel saya bahas ini. Bisa jg baca dokumentasinya ZF2 http://zf2.readthedocs.org baca di bagian ‘Using Zend\Paginator in your album module’

      • Juniawan Adalah Pan Ganesh said, on May 14, 2013 at 5:50 am

        bagaimana dengan performance-nya kalau menggunakan db adapter? karena dari contoh-nya kan memanggil semua data? meskipun yang ditampilkan sesuai limit yang ditentukan ke Paginator. mohon pencerahannya Pak. Trims.

  11. Manish Kutaula said, on May 29, 2013 at 5:51 pm

    This tutorial for DB paginating is wrong .. in case of data from database one have to use DbSelect Adapter or DbTableGateway Adapter. other wise the whole purpose of pagination will fail

  12. Bharath said, on September 27, 2013 at 6:30 pm

    i got an output but the fetch all record but not shows in the second page… i’ll got error as 404 error. i’ll use ZF2 with Doctrine2

    • samsonasik said, on September 27, 2013 at 8:30 pm

      it’s not about doctrine issue, it’s about your route issue, check your route if consist page segment like /:page 🙂

      • Bharath said, on September 28, 2013 at 12:27 pm

        the page will change in the address bar but record will not change in 2nd and 3rd pages

      • samsonasik said, on September 28, 2013 at 2:55 pm

        it means you don’t get the value of “page” of route, print_r debug and dump the param

  13. Bharath said, on September 28, 2013 at 11:54 am

    This is my module.config

    ‘city’ => array(
    ‘type’ => ‘segment’,
    ‘options’ => array(
    ‘route’ => ‘/city[/:action][/:id2][/page/:page]’, //Its My URL Bharath
    ‘constraints’ => array(
    ‘action’ => ‘(?!\bpage\b)[a-zA-Z][a-zA-Z0-9_-]*’,
    ‘id’ => ‘[a-zA-Z0-9_-]*’,
    ‘page’ => ‘[0-9]+’,
    ),
    ‘defaults’ => array(
    ‘controller’ => ‘access/city’,
    ‘action’ => ‘index’,
    //’page’ => 1
    ),
    ),

    ‘may_terminate’ => true,
    ‘child_routes’ => array(
    ‘list’ => array(
    ‘type’ => ‘Segment’,
    ‘options’ => array(
    ‘route’ => ‘/[:page]’,
    ‘constraints’ => array(
    ‘controller’ => ‘access/city’,
    ‘action’ => ‘list’,
    ),
    ‘defaults’ => array(
    ),
    ),
    ),
    ),
    //
    //
    ‘pager’ => array(
    ‘type’ => ‘Segment’,
    ‘options’ => array(
    ‘route’ => ‘/pager[/:page]’,
    ‘defaults’ => array(
    ‘controller’ => ‘access/city’,
    ‘action’ => ‘pager’,
    ),
    ),
    ),
    ),

    This is my View Script in index.phtml

    echo $this->paginationControl(

    $this->paginator,

    ‘sliding’,

    ‘access\city\paginator.phtml’,

    array(

    ‘route’ => ‘city’,
    )
    );

  14. Bharath said, on September 28, 2013 at 5:00 pm

    i have 35 record in the db. in 1st page shows fetched records but in 2nd page i got an error in the route. i got error is:

    The requested controller was unable to dispatch the request.

    Controller:
    Access/city

    My module config and index files in previous question

  15. Bharath said, on October 2, 2013 at 5:28 pm

    i’m using paginator to search the records from the table. i’ll using selectable() function to executes paginator.but i’ll search some record use of search box the selected record is not retived from table all datas are show like paginator view.

  16. DurgeshGoel said, on October 8, 2013 at 9:41 pm

    Hi,

    Pls help to implement join query in below code

    $dbSelect = $this->getInboxTable()
    ->getSql()
    ->select()
    ->columns(array(‘id’, ‘msg_to_id’, ‘msg_from_id’, ‘stared’))
    ->where(array(‘msg_to_id’ => $user_id,))
    ->order(array(‘id asc’));

    $iteratorAdapter = new \Zend\Paginator\Adapter\DbSelect($dbSelect,$this->getInboxTable()->getAdapter())
    $paginator = new \Zend\Paginator\Paginator($iteratorAdapter);

    Something like

    $dbSelect = $this->getInboxTable()
    ->getSql()
    ->select()
    ->from(array(‘inb’ => ‘inbox_msg’),array(‘id’, ‘msg_to_id’, ‘msg_from_id’, ‘stared’))
    ->join(array(‘u’ => ‘user’),’inb.msg_to_id = u.id’ ,array(‘id’,’name’ ) )
    ->where(array(‘msg_to_id’ => $user_id,))
    ->order(array(‘inb.id asc’));

    error : Since this object was created with a table and/or schema in the constructor, it is read only

    ThAnK u iN AdvaNce

  17. fjmiguel said, on October 14, 2013 at 6:10 pm

    Thank you very much! You’re saving my life! Your tutorials are very good written!

  18. Thinh said, on November 28, 2013 at 11:12 pm

    I have an error:
    Warning: Missing argument 1 for Tut\View\Helper\Requesthelper::setRequest(), called in …/Module.php on line 47 and defined in …\View\Helper\Requesthelper.php on line 12

    Notice: Undefined variable: request in …\View\Helper\Requesthelper.php on line 14

    Fatal error: Call to a member function getServer() on a non-object in …\View\Helper\Requesthelper.php on line 24

    please help me!

    • samsonasik said, on November 30, 2013 at 2:09 am

      read the post carefully! you need to register Requesthelper via factories :

      class Module
      {
          /* another common function here */
          
          // REGISTER VIEW HELPER via factories
          public function getViewHelperConfig()
          {
              return array(
                  'factories' => array(
                      'Requesthelper' => function($sm){
                              $helper = new View\Helper\Requesthelper;
                              $request = $sm->getServiceLocator()->get('Request');
                              $helper->setRequest($request);
                              
                              return $helper;
                     }
                  ),
              );
          }
      }
      

      please read my service manager cheat sheet for better understanding : https://samsonasik.wordpress.com/2013/01/02/zend-framework-2-cheat-sheet-service-manager/

      • Thinh said, on December 2, 2013 at 11:23 pm

        error solved, thank you very much!!!!

  19. Vimal raj said, on December 23, 2013 at 1:05 am

    In view file $this->pageCount has no value ,so the pagination control doesn’t works for me, in which file u had assigned the value for pageCount

    • samsonasik said, on December 25, 2013 at 1:36 am

      the $this->pageCount is automatically catchable on pager.phtml, it used by paginationControl that passes data.

  20. Thanh said, on January 6, 2014 at 4:42 pm

    I need to set total_items, how can I get this? Because I want to use the paginator for webservice.

    • samsonasik said, on January 6, 2014 at 8:19 pm

      there is some method on Paginator class :

      Paginator::getItemCountPerPage();
      Paginator::getTotalItemCount();
      
  21. oskar said, on January 9, 2014 at 5:41 am

    Thanks for this wonderfull tutorial 🙂 By the way Is possible in ZF2 to paginate verticaly I mean twitter pagination!!!

    • samsonasik said, on January 9, 2014 at 5:45 am

      yes, just modify your view part of paginator by yourself. use ajax to load other “page”

      • oskar said, on January 9, 2014 at 6:13 am

        Can you please explain by example ?

  22. Io Yer said, on March 3, 2014 at 12:07 pm

    Hi,
    is there a way to pass arrays in ZF2 routes? How is the proper way if I need to get something like: /?a[]=1&a[]=2&a[]=5…. etc

    • samsonasik said, on March 3, 2014 at 6:53 pm

      that’s a query param, no need to define at route. just call

      print_r(
         $this->params()->fromQuery('a')
      );
      
  23. ista said, on May 28, 2014 at 6:21 pm

    plz can you done an example for pagination with ajax (without refresh the whole page)

  24. c0nstruct0r said, on July 19, 2014 at 10:58 pm

    How can I test it with PHPUnit? It returns “Argument 1 passed to Zend\Paginator\Adapter\Iterator::__construct() must implement interface Iterator, array given”. Here is example https://github.com/c0nstruct0r/Zend-Framework-2-tutorial-PHPUnit

  25. Alfredo said, on August 4, 2014 at 7:36 pm

    Thanks, you help me very much.

  26. Lennon Cécere said, on January 25, 2023 at 9:45 pm

    Thank you samsonasik


Leave a reply to samsonasik Cancel reply