Question

I'm back to this good old problem where using a Varien_Data_Collection in a grid does not handle sorting, paging nor filtering.

I've found some useful resources such as :

The first one is incomplete whereas the answer in the second one is too broad to help.

I know I have to use a custom collection class that extends Varien_Data_Collection I simply wanna know exactly the methods (and the details of them) I need to implement inside to be able to handle paging, sorting and filtering ?

Was it helpful?

Solution

After several tests I managed to get it right.

Here's the collection class that extends Varien_Data_Collection and that handles paging / filtering / sorting so it can be used in admin grids.

<?php

class DigitalPianism_Module_Model_Report extends Varien_Data_Collection {

    public function loadData($printQuery = false, $logQuery = false)
    {
        if ($this->isLoaded()) {
            return $this;
        }

        // We add the renders
        $this->_renderFilters()
            ->_renderOrders()
            ->_renderLimit();

        $this->_setIsLoaded();
    }

    public function addFieldToFilter($field, $condition = null)
    {
        $keyFilter = key($condition);
        $valueFilter = (string)$condition[$keyFilter];
        $this->addFilter($field, $valueFilter);
        return $this;
    }

    protected function _renderFilters()
    {
        // If elements are already filtered, return this
        if ($this->_isFiltersRendered) {
            return $this;
        }

        // Loop the collection
        foreach($this->_items AS $key => $item) {

            foreach($this->_filters AS $filter) {

                $keyFilter = $filter->getData()['field'];
                $valueFilter = $filter->getData()['value'];
                //$condFilter = $filter->getData()['type']; // not used in this example
                if (strpos($valueFilter, "%") !== false) {
                    // Delete "'%" and "%'" from the string
                    $valueFilter = substr($filter->getData()['value'], 2, -2);
                }

                // Item value
                $itemValue = $item->getData($keyFilter);

                // If it's not an array, we use the search term to compare with the value of our item
                if (!is_array($itemValue)) {
                    if (strpos(strtolower($itemValue), strtolower($valueFilter)) === FALSE) {
                        unset($this->_items[$key]);
                        // If search term not found, unset the item to not display it!
                    }
                } else {
                    // If it's an array
                    $found = false;
                    foreach ($itemValue AS $value) {
                        if (strpos(strtolower($value), strtolower($valueFilter)) !== FALSE) {
                            $found = true;
                        }
                    }
                    if (!$found) {
                        unset($this->_items[$key]); // Not founded in the array, so unset the item
                    }
                }
            }
        }

        $this->_isFiltersRendered = true;
        return $this;
    }

    protected function _renderOrders()
    {
        $keySort = key($this->_orders);
        $keyDirection = $this->_orders[$keySort];
        // We sort our items tab with a custom function AT THE BOTTOM OF THIS CODE
        usort($this->_items, $this->_build_sorter($keySort,$keyDirection));
        return $this;
    }

    protected function _renderLimit()
    {
        $this->_totalRecords = sizeof($this->_items);

        if($this->_pageSize){
            $this->_items = array_slice($this->_items, ($this->_curPage - 1) * $this->_pageSize, $this->_pageSize);
        }
        return $this;
    }

    protected function _build_sorter($key,$direction)
    {
        return function ($a, $b) use ($key,$direction) {
            if ($direction == self::SORT_ORDER_ASC)
                return strnatcmp($a[$key], $b[$key]); // Natural comparaison of string
            else
                return -1 * strnatcmp($a[$key], $b[$key]); // reverse the result if sort order desc !
        };
    }

}

Feel free to let me know if you find a bug or something missing

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top