Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple calls to $model->save() in Magento over-writing data

Tags:

php

magento

I am developing a custom Magento module that needs to save a list of email addresses into a custom table. The relevant code looks like this:

foreach($this->getNewSubscriptionsForAPI() as $email){
            $requestModel->setEmail($email);
            $requestModel->setAction('subscribe');
            $requestModel->setPosted(date('Y-m-d H:i:s'));
            $requestModel->save();
        }

The getNewSubscriptionsForAPI() method is returning valid data, and the $requestModel is a valid Magento model.

When this loop runs, however, the database adaptor simple overwrites each record on top of the previous one. Ie, if I repeatedly hit 'browse' in phpMyAdmin I can see different email addresses being written to the database but always in the same row, overwriting the previous entry. The id field is correctly set up: as primary key, set to AUTO_INCREMENT, and flagged as the id field in the resource model.

What's interesting is that I can use the loop above to write successive records in the core newsletter/subscriber table with no problem.

I could, of course, simply unset() the model and get it back out of the Mage::getModel() at each cycle of the loop, but this (a) seems hugely wasteful, and (b) spoils my Dependency Injection setup for testing (where I don't want the code to be instantiating its own models, but using the ones I pass to it).

Can anyone point me in the right direction?

like image 613
MJA Avatar asked May 29 '12 10:05

MJA


4 Answers

When Magento saves a new object it automatically generates an id for the object. After you have saved the object hence an id is generated. To make magento recognize your data as a new model again, you simply need to unset the model id. I think however unsetData is more elegant as it also erases any data that might have been created for the previous object :-).

like image 121
Lucas Moeskops Avatar answered Nov 18 '22 16:11

Lucas Moeskops


Ah, it seems like I may have answered my own question. By including a call to $requestModel->unsetData(); just after the call to $requestModel->save() the loop works as intended.

unsetData is a method made available by Varien_Object, which Mage_Core_Model_Abstract inherits from.

I'm happy for someone to contribute a more elegant solution I'm happy to hear it.

like image 38
MJA Avatar answered Nov 18 '22 15:11

MJA


I don't know if this is more elegant or not but managed to solve your problem with this code. At each loop a new row will be added with the new information.

foreach($this->getNewSubscriptionsForAPI() as $email){
            $data = array('email' => $email, 'action' => 'subscribe', 
                   'posted' => date('Y-m-d H:i:s');
            $requestModel->setData($data)->save();
        }

Considering 'email', 'action' and 'posted' are your database table’s field names.

like image 2
Nilay Ates Avatar answered Nov 18 '22 14:11

Nilay Ates


This is an old thread, but for anyone coming across this, while the unsetData()advice is correct, the fact that this method calls the save() function inside a loop is bad practice and will definitely slow your site down.

You can write a function in the ResourceModel of your Model structure to allow adding multiple items inside a transaction which will be much safer as well as increase performance exponentially.

See Here and Here for some better ideas.

like image 1
Phil Schmidt Avatar answered Nov 18 '22 16:11

Phil Schmidt