Magento 1 – Save Collection Without Foreach Loop

collection;magento-1.9php-5.4save

I am currently going through and optimizing our codebase for our custom modules. I am using PHP Codesniffer along with the Magento Coding Standard rules to scan our code.

In many of our files I see a warning like

Model LSD method save() detected in loop

Here is an example of a function containing that error

public function resetmasstatusAction()
 {
    $invoicesIds = $this->getRequest()->getPost('invoice_ids');
    if (!empty($invoicesIds)) {
        $invoices = Mage::getResourceModel('sales/order_invoice_collection')
            ->addAttributeToSelect('*')
            ->addAttributeToFilter('entity_id', array('in' => $invoicesIds))
            ->load();
        foreach ($invoices as $invoice) :
            $invoice->setMas_status('NEW')
                ->setMas_updated_at(date('Y-m-d H:i:s'))
                ->save();
        endforeach;
    }
    $this->_redirect('*/sales_invoice/index');
}

How would I go about doing the save operation for all items in a collection such as this one, without having the save() function in the foreach loop to improve performance?

Best Answer

After doing some research into this, I discovered that the best way to do this is like the following.

Please note that the walk iterator is essentially the same thing as a foreach loop, however the goal in my original question was how to not run a SQL query over and over again in a foreach loop.

By running the save() function on the entire $invoices object, we essentially run a large SQL query to save all of the rows at once rather than running a bunch of small queries.

public function resetmasstatusAction()
 {
    $invoicesIds = $this->getRequest()->getPost('invoice_ids');
    if (!empty($invoicesIds)) {
        $invoices = Mage::getResourceModel('sales/order_invoice_collection')
            ->addAttributeToSelect('*')
            ->addAttributeToFilter('entity_id', array('in' => $invoicesIds))
            ->load();
        //The below will allow you to save the updated collection
        //Without running multiple SQL queries in the foreach loop.
        $invoices->walk('setMas_status', array('NEW');
        $invoices->walk('setMas_updated_at', array(date('Y-m-d H:i:s'));           
        $invoices->save();
    }
    $this->_redirect('*/sales_invoice/index');
}
Related Topic