Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Magento get a product collection in an arbitrary order

Tags:

php

orm

magento

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?

like image 414
Josh Pennington Avatar asked Oct 21 '10 17:10

Josh Pennington


2 Answers

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());
        }
like image 169
Alan Storm Avatar answered Nov 15 '22 03:11

Alan Storm


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)

like image 23
clockworkgeek Avatar answered Nov 15 '22 02:11

clockworkgeek