Magento – Product Custom Option Duplication on Save Within Loop

custom-options

I am trying to figure out the behaviour I'm getting when saving custom product options programmatically.

I am returning a collection of products ($simples) then:

foreach ($simples as $simple)
{
    $custom_options = array($option_one, $option_two);

    $product = Mage::getModel('catalog/product')->load($simple->getId());

    $product->setProductOptions($custom_options)
            ->setCanSaveCustomOptions(true);

    $product->save();
}

$custom_options is simply an array of two option arrays:

[0] => Array
    (
        [title] => Option One
        [sku] => OPTIONONE
        [type] => field
        [price] => 0
        [is_require] => 0
        [sort_order] => 0
        [max_characters] => 100
    )
[1] => Array
    (
        [title] => Option Two
        [sku] => OPTIONTWO
        [type] => field
        [price] => 0
        [is_require] => 0
        [sort_order] => 0
        [max_characters] => 100
    )

However the iteration value appears to have some kind of effect on save(), as for each increase, each of the arrays above are added to the product that many times i.e.

Product from loop 1 has: Array[0], Array[1]
Product from loop 2 has: Array[0], Array[0], Array[1], Array[1]
Product from loop 3 has: Array[0], Array[0], Array[0], Array[1], Array[1], Array[1]

I can see that in \Mage\Catalog\Model\Resource\Product\Option.php

protected function _afterSave(Mage_Core_Model_Abstract $object)

is called multiple times on each array, I just need to understand why.

Edit: I have just created an observer and logged the calls, this is what I get:

2013-09-15T13:49:12+00:00 INFO (6): Calling save() on product: 74
2013-09-15T13:49:12+00:00 INFO (6): PRODUCT SAVE BEFORE CALLED: 74
2013-09-15T13:49:12+00:00 INFO (6): Product option _afterSave() called...
2013-09-15T13:49:12+00:00 INFO (6): Product option _afterSave() called...
2013-09-15T13:49:12+00:00 INFO (6): PRODUCT SAVE AFTER CALLED: 74
2013-09-15T13:49:13+00:00 INFO (6): SAVE SUCCESS FOR PRODUCT: 74
2013-09-15T13:49:13+00:00 INFO (6): Calling save() on product: 75
2013-09-15T13:49:13+00:00 INFO (6): PRODUCT SAVE BEFORE CALLED: 75
2013-09-15T13:49:13+00:00 INFO (6): Product option _afterSave() called...
2013-09-15T13:49:13+00:00 INFO (6): Product option _afterSave() called...
2013-09-15T13:49:13+00:00 INFO (6): Product option _afterSave() called...
2013-09-15T13:49:13+00:00 INFO (6): Product option _afterSave() called...
2013-09-15T13:49:13+00:00 INFO (6): PRODUCT SAVE AFTER CALLED: 75
2013-09-15T13:49:14+00:00 INFO (6): SAVE SUCCESS FOR PRODUCT: 75

As you can see, the products save() method is only called once, but the options are being duplicated for each loop iteration

Best Answer

OK so I finally came back to this issue and the following post helped me figure this one out: https://stackoverflow.com/questions/4006260/magento-accumulating-custom-options-in-script

As the user in the post above says, the Magento product option model was 'designed with a singleton pattern', which means for each loop I am adding the product options again, then setting these duplicated options to the following product.

So the fix is simply to call Mage::getSingleton('catalog/product_option')->unsetOptions(); before we call setProductOptions. There is no need to call load() either, the model returned in the collection is adequate.

So yeah, simple when you know how eh! I was really tearing my hair out on this one, thanks Magento!