简体   繁体   中英

Magento product collection pagination with custom sort

I'm overriding Mage_Catalog_Block_Product_List 's _getProductCollection by adding:

foreach ($this->_productCollection as $product) {
     $product->setDistance(Mage::helper('myhelper')->getDistance($product));
}

Now I want the collection to be sorted by distance, I tried the following:

 $this->_productCollection = Mage::helper('myhelper')->sortProductByDist($this->_productCollection);

The helper for sorting is like following (stolen from SO):

public function sortProductByDist($products) {

      $sortedCollection = Mage::getSingleton('catalog/layer')
         ->getProductCollection()->addFieldToFilter('entity_id', 0);

      $sortedCollection = $sortedCollection->clear();
      $collectionItems = $products->getItems();
      usort($collectionItems, array($this,'_sortItems'));

      foreach ($collectionItems as $item) {
          $sortedCollection->addItem($item);              
      }
      return $sortedCollection;
}

protected function _sortItems($a, $b) {
        $order = 'asc';
        $al = strtolower($a->getDistance());
        $bl = strtolower($b->getDistance());

        if ($al == $bl) {
            return 0;
        }

        if ($order == 'asc') {
            return ($al < $bl) ? -1 : 1;
        } else {
            return ($al > $bl) ? -1 : 1;
        }
}

The problem is the product collection is no longer paginated when this additional sort is applied.

Anyone knows how to fix this?

You are not doing it the right way, and there are no easy solutions. You need to use the database to do the sorting.

The _productCollection is not an array, it's an object that has references, the query at this point can still be updated, the pagination will be handled by the query to the database.

if you do a

Mage::log((string) $this->_productCollection->getSelect()); 

you will see the query in the logs

What you do is to load the products of the current page, add the distance on all products of the page, and create a new collection where you force your items in. So that collection's data is not coming from the database and only contains the elements of the current page.

Sorting using php is a bad idea, because if you have a lot of products it means you need to load them all from the database. That will be slow.

The solution

Calculate distance in the database directly by modifying the query.

You can edit the select query and do the distance calculation in the database

$this->_productCollection
    ->getSelect()
        ->columns("main.distance as distance")

Now you can add a sort on the product collection

$this->_productCollection->setOrder('distance');

The complicated part will be to write the equivalent of your getDistance method in mysql. In my example I assumed distance was in the database already.

Don't hesitate to print the query at various steps to understand what is going on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM