tags:

views:

85

answers:

2

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(140452, 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?

Thanks

Josh Pennington

+3  A: 

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);           

        $products->getSelect()->order("find_in_set(e.entity_id,'".implode(',',$ids)."')");
        foreach($products as $product)
        {
            var_dump($product->getEntityId());
            var_dump($product->getSku());
        }
Alan Storm
I may have read the question wrong, but I think he wants to order on the array he currently has in PHP (which doesn't necessarily correlate to any column in the DB). This should give him sorting by any column, but he'd have to get the data back into the database.
Joseph Mastey
Ah, yeah, I misread the question. SO burnout, I think.
Alan Storm
Updated question with more correct answer.
Alan Storm
Although longer to implement your find_in_set solution does have the nice advantage of using the array of entity IDs directly.
clockworkgeek
This worked amazingly well. Thank you so much!
Josh Pennington
+1  A: 

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)

clockworkgeek
A couple of things. 1. It looks like addOrder doesn't work on EAV collections, you need to addAttributeToSort 2. You can usually achieve arbitrary sorts in SQL using whatever that implementation's "find_in_set" function is. Using position is probably a smart idea though, if it applies.
Alan Storm
Thanks for the correction.
clockworkgeek