14

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.

  • 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 Mar 22 '13 at 16:12
  • @RalphTice Yes, that would probably be the right thing to do for day to day use. – Alan Storm Mar 22 '13 at 17:12
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.

  • 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? – Alan Storm Mar 22 '13 at 6:19
  • Edited my answer to make it more obvious. – benmarks Mar 22 '13 at 12:11
  • ...and it did work for me. – benmarks Mar 22 '13 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? – Alan Storm Mar 22 '13 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. – Alan Storm Mar 22 '13 at 18:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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