Reputation: 75
I have been created a Varien_Data_Collection from scratch:
$myCollection = new Varien_Data_Collection();
after add some items into it, $myCollection->addItem($fooItem);
, I tried to paginate it with:
$myCollection->setPageSize(3)->setCurPage(1);
but when I display the collection, it shows all items in the collection instead the first, second o N page.
$myItems = $myCollection->getItems();
foreach ($myItems as $item) {
echo $item->getData('bar');
}
Upvotes: 1
Views: 2617
Reputation: 124
class Pageable_Varien_Data_Collection extends Varien_Data_Collection
{
/**
* Load data
*
* @param bool $printQuery
* @param bool $logQuery
*
* @return Pageable_Varien_Data_Collection
*/
public function load($printQuery = false, $logQuery = false)
{
if ($this->isLoaded()) {
return $this;
}
$this->_renderLimit();
$this->_setIsLoaded();
return $this;
}
/**
* @return Pageable_Varien_Data_Collection
*/
protected function _renderLimit()
{
if ($this->_pageSize) {
$currentPage = $this->getCurPage();
$pageSize = $this->_pageSize;
$firstItem = (($currentPage - 1) * $pageSize + 1);
$lastItem = $firstItem + $pageSize;
$iterator = 1;
foreach ($this->getItems() as $key => $item) {
$pos = $iterator;
$iterator++;
if ($pos >= $firstItem && $pos <= $lastItem) {
continue;
}
$this->removeItemByKey($key);
}
}
return $this;
}
/**
* Retrieve collection all items count
*
* @return int
*/
public function getSize()
{
if (is_null($this->_totalRecords)) {
$this->_totalRecords = count($this->getItems());
}
return intval($this->_totalRecords);
}
/**
* Retrieve collection items
*
* @return array
*/
public function getItems()
{
return $this->_items;
}
}
Upvotes: 0
Reputation: 697
As explained in previous post Varien_Data_collection does not support pagination. One solution would be to extend this class and overwrite its loadData() method. Here is practical example of paginating array of stdClass objects. Can be used with any array of data
class YourNamespace_YourModule_Model_History_Collection extends Varien_Data_Collection{
//array of stdClass objects. Can be array of any objects/subarrays
protected $_history = array();
public function loadData($printQuery = false, $logQuery = false){
if ($this->isLoaded()) {
return $this;
}
$this->_totalRecords = count($this->_history);
$this->_setIsLoaded();
// paginate and add items
$from = ($this->getCurPage() - 1) * $this->getPageSize();
$to = $from + $this->getPageSize() ;
$isPaginated = $this->getPageSize() > 0;
$cnt = 0;
$sub_history = array_slice($this->_history, $from, $to-$from);
foreach ( $sub_history as $entry) {
$cnt++;
$item = new $this->_itemObjectClass();
//build here your Varien Object
$item->setDate($entry->Date);
//.......
$this->addItem($item);
if (!$item->hasId()) {
$item->setId($cnt);
}
}
return $this;
}
public function setRecords($records){
if(is_array($records)){
$this->_history = $records;
}
return;
}
}
//Your block class
class YourNamespace_YourModule_Block_History extends Mage_Core_Block_Template{
public function __construct(){
$collection_prepared = new YourNamespace_YourModule_Model_History_Collection();
//get your data here
//$records is array of stdClass objects
$collection_prepared->setRecords($records);
$this->setCollection($collection_prepared);
}
protected function _prepareLayout(){
parent::_prepareLayout();
$pager = $this->getLayout()->createBlock('page/html_pager', 'history.pager');
$pager->setAvailableLimit(array(20=>20,40=>40,80=>80,'all'=>'all'));
$pager->setCollection($this->getCollection());
$this->setChild('pager', $pager);
$this->getCollection()->load();
return $this;
}
public function getPagerHtml()
{
return $this->getChildHtml('pager');
}
}
Hope this helps!
Upvotes: 0
Reputation: 197757
The (non-abstract) base-class Varien_Data_Collection
- although it does have the setPageSize
and setCurPage
methods, those are not reflected within the aggregation of the Iterator:
class Varien_Data_Collection implements IteratorAggregate, Countable
{
...
/**
* Implementation of IteratorAggregate::getIterator()
*/
public function getIterator()
{
$this->load();
return new ArrayIterator($this->_items);
}
...
It will in any case return an ArrayIteator
that has all objects. The load
method doesn't change a thing here btw:
...
/**
* Load data
*
* @return Varien_Data_Collection
*/
public function loadData($printQuery = false, $logQuery = false)
{
return $this;
}
...
/**
* Load data
*
* @return Varien_Data_Collection
*/
public function load($printQuery = false, $logQuery = false)
{
return $this->loadData($printQuery, $logQuery);
}
...
I'd say this qualifies as a bug, as the public interface makes one assume that the magent collection object Varien_Data_Collection
provides pagination while it does not.
I have not searched for a bug-report regarding this issue. The solution is to use another iterator for pagination, for example like outlined in an answer to How to Paginate lines in a foreach loop with PHP with PHP's LimitIterator
:
/**
* Class Varien_Data_Collection_Pagination
*
* Aggregates missing Pagination on Collection on getting the Iterator
*
* @author hakre <http://hakre.wordpress.com/>
*/
class Varien_Data_Collection_Pagination implements IteratorAggregate
{
/**
* @var Varien_Data_Collection
*/
private $collection;
public function __construct(Varien_Data_Collection $collection)
{
$this->collection = $collection;
}
public function getIterator()
{
$collection = $this->collection;
if (FALSE === $size = $collection->getPageSize()) {
return $collection;
}
$page = $collection->getCurPage();
if ($page < 1) {
return $collection;
}
$offset = $size * $page - $size;
return new LimitIterator(new IteratorIterator($collection), $offset, $size);
}
}
Usage Example:
$collection = new Varien_Data_Collection();
$collectionIterator = new Varien_Data_Collection_Pagination($collection);
# [...] fill collection
# set pagination:
$collection->setPageSize(3);
$collection->setCurPage(1);
echo iterator_count($collectionIterator); # 3 (int)
Keep in mind that this is mainly an example. IMHO this should be fixed upstream within the Magento codebase, so it's perhaps worth you do some search work in the Magento Bug-Tracker.
Upvotes: 2