15

Is there a way to use Magento's simple ORM (Mage_Core_Model_Abstract and Mage_Core_Model_Resource_Abstract) to insert model rows with a specific primary key?

For example, if I ran the following against an empty Magento system

Mage::getModel('core/website')->setData(array (
    'website_id' => 2,
    'code' => 'foo',
    'name' => 'Main Website',
    'sort_order' => 0,
    'default_group_id' => 1,
    'is_default' => 1,
)); 

I'd expect a new entry in the core_website table. However, Magento silently does nothing here.

Digging into the resource, it looks like I'm falling afoul of this in the database resource class

#File: app/code/core/Mage/Core/Model/Resource/Db/Abstract.php
if (!is_null($object->getId()) && (!$this->_useIsObjectNew || !$object->isObjectNew())) {
    //update stuff here
}
else
{
    //insert stuff here
}

Because the model has an id (i.e. I'm inserting a specific ID), and because _useIsObjectNew is hard coded to false, my save request is always routed to the insert path.

Is there a way to force an insert with the default Magento models? (without a rewrite/class-replacement).

Yes, raw SQL is an option, but then event functionality gets lost.

2
  • Why are you trying to assign an ID to an autoincrement field? If this is a downstream dependency shouldn't you just create the record and then retrieve the autogenerated PK?
    – Ralph Tice
    Commented Mar 22, 2013 at 16:12
  • @RalphTice Yes, that would probably be the right thing to do for day to day use. Commented Mar 22, 2013 at 17:12

1 Answer 1

5

So, yeah. (edit:) The trick is to use a Mage_Core_Model_Abstract subclass which does not have the id field that the resource model expects:

$evil = Mage::getModel('core/store'); // that's a store object, baby!
$evil->setData(
    array (
        'website_id' => 99,
        'code' => 'foo',
        'name' => 'Main Website9',
        'sort_order' => 0,
        'default_group_id' => 1,
        'is_default' => 1,
    )
);

Mage::getResourceModel('core/website')->forsedSave($evil);

Mage::dispatchEvent('website_save_commit_after', [...]) is only event I see being consumed in core. It could be as simple as following with

Mage::getModel('core/website')->setData($evil->getData())->afterCommitCallback();

In any event, I need a shower.

7
  • 1
    Once you're clean — I'm not sure I follow that — there's a similar id check in forsedSave gist.github.com/astorm/5219357. Did this work for you, or was it just a theory? Commented Mar 22, 2013 at 6:19
  • Edited my answer to make it more obvious.
    – benmarks
    Commented Mar 22, 2013 at 12:11
  • ...and it did work for me.
    – benmarks
    Commented Mar 22, 2013 at 13:25
  • Ah ha, that's what I get for typing my own code instead of copying and pasting. Using this as a starting point, can you see any reason not to use a Varien_Object instead of the different model class, and then calling the resource's non depreciated save method? Commented Mar 22, 2013 at 17:06
  • And answering my own question above, it's because the generic resource's save method has Mage_Core_Model_Abstract type hinting for the data array. Commented Mar 22, 2013 at 18:37

Your Answer

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

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