Question

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

Was it helpful?

Solution

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!

OTHER TIPS

Try calling reset on the $product object after saving to reset all public data that you've added to the object.

This is working perfect.

foreach($productIds as $id){ 

 $product = Mage::getModel('catalog/product')->load($id);
  **Mage::getSingleton('catalog/product_option')->unsetOptions();**
 try {
       if(!$product->getOptionsReadonly()) {
         $product->setProductOptions(array($option));
         $product->setCanSaveCustomOptions(true);
             $product->save();
          } 
      } catch (Exception $e) {
            Mage::log($e->getMessage());


        }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top