Zend Framework 2 : Zend\Paginator : Paginate Your Data
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'; ?>"><< first </a> <a class="Previous" href="<?= $url.'/'.$this->previous.$parameterGet; ?>">< prev </a> <?php else: ?> <b><i><< first </i></b> <b><i>< prev </i></b> <?php endif; ?> <?php foreach ($this->pagesInRange as $page): ?> <?php if ($page != $this->current): ?> <a class="nopage" href="<?= $url.'/'.$page.$parameterGet; ?>"> <?= $page; ?> </a> <?php else: ?> <span class="nopage"> <?= $page; ?> </span> </b> <?php endif; ?> <?php endforeach; ?> <?php if (isset($this->next)): ?> <a class="next" href="<?= $url.'/'.$this->next.$parameterGet; ?>"> next ></a> <a class="next" href="<?= $url.'/'.$this->pageCount.$parameterGet; ?>"> last >></a> <?php else: ?> <b><i> next > </i></b> <b><i> last >> </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 !
[…] ZendPaginator : Paginate Your Data […]
Hi!
What is the value of the variable $ page in your controller? example print_r ($page); die;
try it by yourself :p
can you post git link for this tutorial
ok, this is the link : https://github.com/samsonasik/SanSamplePagination
thanks
You’re welcome 🙂
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
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?
try :
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.
clone my repo : https://github.com/samsonasik/SanSamplePagination
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.
you should check your php version, it need >= php 5.3.3
I have Php 5.3.4. I don’t understand what’s wrong
It’s weird, read your apache error log.
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.
No problem, you’re welcome ;),
Thanks! Helped me out! 😉
you’re welcome 😉
Thanks!
but I want to know if I can use paginator in plusieure module without duplication
No. you are not duplicate it. all zf module config are merged.
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.
all module config are merged, just define it in one module, and you can use it everywhere.
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
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’
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.
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
I have written about pagination DbTableGateway adapter here : https://samsonasik.wordpress.com/2013/05/06/zend-framework-2-paginator-using-tablegateway-object/ , ArrayAdapter is just an option.
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
it’s not about doctrine issue, it’s about your route issue, check your route if consist page segment like /:page 🙂
the page will change in the address bar but record will not change in 2nd and 3rd pages
it means you don’t get the value of “page” of route, print_r debug and dump the param
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’,
)
);
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
you better learn from the docs : https://zf2.readthedocs.org/en/latest/tutorials/tutorial.pagination.html
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.
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
error solved 🙂
Hey bro, how do you fixed the read-only error?
Thank you very much! You’re saving my life! Your tutorials are very good written!
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!
read the post carefully! you need to register Requesthelper via factories :
please read my service manager cheat sheet for better understanding : https://samsonasik.wordpress.com/2013/01/02/zend-framework-2-cheat-sheet-service-manager/
error solved, thank you very much!!!!
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
the $this->pageCount is automatically catchable on pager.phtml, it used by paginationControl that passes data.
I need to set total_items, how can I get this? Because I want to use the paginator for webservice.
there is some method on Paginator class :
Thanks for this wonderfull tutorial 🙂 By the way Is possible in ZF2 to paginate verticaly I mean twitter pagination!!!
yes, just modify your view part of paginator by yourself. use ajax to load other “page”
Can you please explain by example ?
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
that’s a query param, no need to define at route. just call
plz can you done an example for pagination with ajax (without refresh the whole page)
https://github.com/samsonasik/SanAlbumPaginationWithAjax
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
Thanks, you help me very much.
you’re welcome 😉
Thank you samsonasik