Функции сортировки коллекции Magento (например, Mage_Eav_Model_Entity_Collection_Abstract::addAttributeToSort
) работают путем добавления предложения ORDER BY
в оператор выбора SQL. Однако есть моменты, когда коллекция уже загружена, и необходимо сортировать коллекцию.
Конечно, возможно использовать функцию toArray($fields)
а затем функции сортировки массива PHP (как собственные, так и пользовательские), однако это немного неуклюжие. Это также означает, что объекты в коллекции преобразуются в «немые» строки значений без магических геттеров / сеттеров, которые могут быть реализованы с помощью алгоритмов и т. Д.
Мне интересно, есть ли более элегантные / Magento-esque методы сортировки коллекции.
Благодаря,
Джонатан
Нет правильного способа сделать это. Но я думаю, что это возможно с использованием Reflection. Вы можете получить свойство $ _items объекта коллекции, отсортировать их и вернуть в коллекцию.
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; }
Вот подсказка; clear
метод коллекции отключает флаг загрузки, он позволяет вам изменять сортировку или фильтры и запускать новый запрос.
Я случайно обнаружил это при ответе на нагрузку только на настраиваемые продукты .
Другое решение, которое работает:
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; } }
Метод @Ivan Chepurnyi работал, но возвращает объект ReflectionObject, в моем случае мне нужен Varien_Data_Collection.
Вот что я сделал
$collectionItems = $collection->getItems(); usort($collectionItems, array($this, '_sortItems')); $newCollection = new Varien_Data_Collection(); foreach ($collectionItems as $item) { $newCollection->addItem($item); } var_dump($newCollection);
И в этом случае метод сортировки
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; } }
Вышеупомянутое решение будет работать нормально, но оно LOT медленнее и интенсивнее, чем добавление сортировки к самому запросу.
Если у вас большая коллекция, вы будете использовать огромный объем памяти, так как вам нужно загрузить объект (или объекты) для каждого результата и сохранить их все.
Использование коллекции Magento будет загружать только одну строку за раз из базы данных, которая будет намного более эффективной, чем вышеупомянутое решение 🙂