3

The problem

I have added a custom attribute to the sales_flat_order table like:

/* @var $installer Mage_Sales_Model_Mysql4_Setup */
$installer = new Mage_Sales_Model_Mysql4_Setup('setup');

$installer->addAttribute(
    Mage_Sales_Model_Order::ENTITY,
    'new_attribute_code',
    array(
        'type' => 'varchar',
        'visible' => true,
    )
);

I would like to programmatically do a bulk update of orders to set a new value for this attribute against many orders. This value will be scripted to update based on the result of another system, it's not a "one off" or solved by having a default value.

I hoped Magento would have a similar kind of interface as it does for products which allows for bulk updates like

Mage::getSingleton('catalog/product_action')->updateAttributes(
    $productIdsArray,
    array('description' => 'New desc'),
    Mage_Core_Model_App::ADMIN_STORE_ID
);

However, I can find no such interface. Does anyone know an efficient and safe way to bulk update orders?

Research

Product bulk update

The product bulk update seems to boil down to Mage_Catalog_Model_Resource_Abstract::_saveAttributeValue. This won't help me for Mage_Sales entities. I could however use it as inspiration for a direct sql level access. However this is something I would hope Magento handles.

Order bulk cancel

I know that you can mark many orders as "cancelled" through the mass action in the magento admin panel. However under the hood it is in fact doing

public function massCancelAction()
{
    $orderIds = $this->getRequest()->getPost('order_ids', array());

    foreach ($orderIds as $orderId) {
        $order = Mage::getModel('sales/order')->load($orderId);
        if ($order->canCancel()) {
            $order->cancel()
                ->save();
        }
    }

That is pretty grim. It's not even loading all the orders in a collection before trying to cancel. It's calling load within a for loop. Ew.

Does anyone know of anything clever I can be doing here?

Responses

@Raphael thanks for your answer. Popping this in my entities' resource model seemed to work okay.

private function getOrderTable()
{
    return $this->getTable('sales/order');
}

public function updateOrders(array $orderIds, $value)
{
    if (empty($orderIds) || !is_string($value)) {
        return $this;
    }

    $adapter = $this->_getWriteAdapter();
    try {
        $adapter->beginTransaction();

        $data  = array(
            'new_attribute_code' => $value,
        );

        $condition = $this->_getWriteAdapter()->quoteInto($this->getIdFieldName() . ' IN(?)', $orderIds);
        $this->_getWriteAdapter()->update($this->getOrderTable(), $data, $condition);

        $adapter->commit();
    } catch (Exception $e) {
        $adapter->rollBack();
        throw $e;
    }

    return $this;
}

1 Answer 1

4

I faced the problem a while ago with quote attributes.

The solution I came up with was implementing a saveAttribute method on the resource class which accepts an array of attributes to update:

public function saveAttribute($model, $attributes)
{
    try {
        $adapter = $this->_getWriteAdapter();
        $adapter->beginTransaction();
        $condition = $this->_getWriteAdapter()->quoteInto($this->getIdFieldName() . '=?', $model->getId());
        $data      = array();
        foreach ($attributes as $attribute) {
            $value = $model->getData($attribute);
            if (isset($value)) {
                $data[$attribute] = $value;
            }
        }
        if (!empty($data)) {
            $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition);
        }
        $adapter->commit();
    } catch (Exception $e) {
        $adapter->rollBack();
        throw $e;
    }
    return $this;
}

Thus in my collection loop I was able to do:

foreach ($orders as $order)
{
    $order->setMyAttribute($value);
    $order->getResource()->saveAttribute($order,array('my_attribute'));
}

I never actually pushed my research further to find out if Magento had something close to this to handle bulk attributes update differently.

1
  • 1
    Thanks, your answer was a helpful starting point! See my updated question :) Apr 8, 2016 at 14:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.