sort Magento collection AFTER load
Solution 1
Another solution which works:
class Aligent_Navigation_Block_Dropdown extends Mage_Catalog_Block_Product_List {
public function getProductsByShortDesc(){
$data = $this->getLoadedProductCollection()->getItems(); //an array of objects
usort($data,array('Aligent_Navigation_Block_Dropdown','sortByShortDesc'));
return $data;
}
public static function sortByShortDesc($a, $b)
{
if($a->getShortDescription() == $b->getShortDescription()){ return 0 ; }
return ($a->getShortDescription() < $b->getShortDescription()) ? -1 : 1;
}
}
Solution 2
There is no proper way of doing it. But I think it is possible with using of Reflection. You can retrieve $_items property of collection object, sort them and set it back to the collection.
function sortCollection(Varien_Data_Collection $collection, callable $sorter) {
$collectionReflection = new ReflectionObject($collection);
$itemsPropertyReflection = $collectionReflection->getProperty('_items');
$itemsPropertyReflection->setAccessible(true); // Make it accessible
$collectionItems = $itemsPropertyReflection->getValue($collection);
usort($collectionItems, $sorter);
$itemsPropertyReflection->setValue($collection, $collectionItems);
$itemsPropertyReflection->setAccessible(false); // Return restriction back
return $collection;
}
Solution 3
Here's a tip; A collection's clear
method unsets it's loaded flag, it allows you to change the sort or filters and run the new query.
I accidentally discovered it when answering load only configurable products.
Solution 4
The method of @Ivan Chepurnyi worked but returns a ReflectionObject object, in my case I needed a Varien_Data_Collection.
Here is what I did instead
$collectionItems = $collection->getItems();
usort($collectionItems, array($this, '_sortItems'));
$newCollection = new Varien_Data_Collection();
foreach ($collectionItems as $item) {
$newCollection->addItem($item);
}
var_dump($newCollection);
And in case here is the sorting method
public function _sortItems($a, $b)
{
$columnId = "your_column_that_you_need_to_sort";
$dir = "desc";
$al = strtolower($a->getData($columnId));
$bl = strtolower($b->getData($columnId));
if ($al == $bl) {
return 0;
}
if ($dir == 'asc') {
return ($al < $bl) ? -1 : 1;
} else {
return ($al > $bl) ? -1 : 1;
}
}
Jonathan Day
Lover of patterns, hater of hacks, aficionado of elegant solutions. Navigating the Magento maze since 2008. twitter: http://twitter.com/#!/aligent
Updated on June 12, 2022Comments
-
Jonathan Day almost 2 years
The Magento collection sorting functions (e.g.
Mage_Eav_Model_Entity_Collection_Abstract::addAttributeToSort
) work by adding anORDER BY
clause to the SQL select statement. However, there are times when a collection has already been loaded and it is necessary to sort the collection.It is certainly possible to use the
toArray($fields)
function and then PHP array sorting functions (either native or user-defined), however this is a little clumsy. It also means that the objects in the collection are converted to "dumb" rows of values without magic getters/setters which can/are be implemented with algorithms, etc.I'm wondering if there are more elegant/Magento-esque methods of sorting the collection.
Thanks,
Jonathan -
OSdave almost 13 yearsI confirm it's possible Ivan, my partner just use your snippet succesfully. The only thing is that instead of
$collection->getProperty('_items');
he had to use$collectionReflection->getProperty('_items');
, a small typo I guess. One another thing I think worth telling, is that, as we're talking about Magento, and thus Classes,$yourSortingCallback
has to be an array of 2 elements, first one being the name of the class where the method is defined, and 2nd one is the name of the method, ie:usort($collectionItems, array('The_Class', 'The_Method'));
. Anyway, we're both very thankfull -
Ivan Chepurnyi almost 13 years@OSdave, yeah there was a type. $yourSortingCallback call back can be even anonymous function.
-
benz001 almost 13 yearsand of course it means you can also addAttributeToSelect() as well, which was just what I was struggling with, thanks :-)
-
Kasper Sanguesa-Franz over 7 yearsOnly problem with this solution is if you got multiple pages then this would sort only the items on this page