Magento get a product collection in an arbitrary order
I have developed a custom search engine for our Magento store and I am trying to load the product collection in a very specific order (I have ranked the results according to an algorithm I designed).
I can load the product collection correctly, however it is not in the order that I would like it to be in. Here is basically how it is working now:
My database query basically comes back with a PHP array of product IDs. For this example lets say it looks like this:
$entity_ids = array(14开发者_如何学编程0452, 38601 );
Now I can transpose the 140452 and the 38601 and the product collection comes back in the same order each time. I would like the product collection to be in the same order as the ID of the entity ids.
The code I am using to create my collection is as follows:
$products = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*')
->addAttributeToFilter('entity_id', array('in' => $entity_ids))
->setPageSize($results_per_page)
->setCurPage($current_page)
->load();
Is there a way to set the sort order to be the order of the $entity_ids array?
Collections inherit from the class
Varien_Data_Collection_Db
There's a method named addOrder
on that class.
public function addOrder($field, $direction = self::SORT_ORDER_DESC)
{
return $this->_setOrder($field, $direction);
}
So, you'd think something like this should work for basic ordering
Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*')
->addOrder('entity_id');
However, it doesn't. Because of the complex joining involved in EAV Collections, there's a special method used to add an attribute to the order clause
Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection::addAttributeToSort
However again, this can only be used to add simple attributes. To create an arbitrary sort, you'll need to manipulate the Zend_Select
object directly. I'm not a big fan of this, and I'm not a big fan of using custom mysql functions to achieve things, but it appears it's the only way to do this
I tested the following code on a stock install and got the desired results. You should be able to use it to get what you want.
$ids = array(16,18,17,19);
$products = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('*')
->addAttributeToFilter('entity_id',$ids);
//shakes fist at PDO's array parameter
$ids = array_map('intval', $ids);
$products->getSelect()->order("find_in_set(e.entity_id,'".implode(',',$ids)."')");
foreach($products as $product)
{
var_dump($product->getEntityId());
var_dump($product->getSku());
}
There is no way to sort arbitrarily in SQL so you would have to sort the results in PHP afterwards. Then the bigger problem is you are using page sizing to limit the number of results being returned, some of the records you want might not be returned because of this.
The better solution is to add an attribute to products which you can then use to sort by. Products in categories already have a 'position' value which is used in this way. Then you only need to use the addOrder()
addAttributeToSort()
method that Alan suggested but with your custom attribute.
(Explanation is hurried, let me know if not clear enough)
精彩评论