2

I need to create a custom attribute for products, which value is updated on product save, based on other attribute's value.

So creating an observer for event catalog_product_save_before works fine when saving products manually.

Unfortunately this event doesn't fire when I loop through 100s of products in my shop with:

set_time_limit(0);
require_once 'app/Mage.php';
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

$products = Mage::getModel('catalog/product')->getCollection();
foreach($products as $product) {
    $product->save();
}

My test observer function:

public function updateProductDetails($observer) {
   Mage::log('inside the observer');
}

I need either new event that will fire on $product->save() or new method of saving all my products at once, that will fire this event catalog_product_save_before.

I would appreciate your suggestions.

  • please show you code of catalog_product_save_before event.. – Amit Bera Sep 1 '15 at 10:04
  • @Amit: I have a whole class there. Multiple attribute updates based on other attributes and product kind. I would prefer not to post it if that's ok. – Alan Sep 1 '15 at 10:25
  • 3
    You should never call ->save to update something without calling load before it. calling save from an object inside a collection may lead to loss of data. – Marius Sep 1 '15 at 11:09
  • @Marius: that's an interesting point because I think I've lost attribute settings because they were reset to default. – Alan Sep 1 '15 at 11:12
  • @Alan. instead of "may lead to loss of data", it should have been "will lead to loss of data". – Marius Sep 1 '15 at 11:15
4

As explained in the comments...
You should never call ->save to update something without calling load before it. calling save from an object inside a collection may lead to loss of data.

If you want to bulk update products you can do this. It's faster and safer.

$productIds = an array with product ids to update
$values = array('attr_code_one' => 'value 1', 'attr_code_two' => 'value 2', ....);
$storeId = 0; //store id for which you need the changes. 0 means default values.
Mage::getSingleton('catalog/product_action')->updateAttributes(
    $productIds,
    $values,
    $storeId
);
  • thanks. What if I'd like to set different attribute value for each product. Would this be the best way? foreach($pids as $pid) { $values = getValuesByPid($pid); Mage::getSingleton('catalog/product_action')->updateAttributes($pid, $values, $storeId); } – Alan Sep 1 '15 at 11:17
  • 1
    Yep...for each different values you want to update you need to call updateAttributes. but one small change. The first parameter must be an array. So instead of updateAttributes($pid, ...) use updateAttributes(array($pid), ... – Marius Sep 1 '15 at 11:19
  • Thanks Marius. I've accepted your answer because you found another issue I was not aware of(using 'save' method) and solved it with different code. Adarsh answer was also correct because it answered my question directly. – Alan Sep 2 '15 at 7:15
2

You can easily fire a new or same event as magento does from your function.

To fire event try this:

$products = Mage::getModel('catalog/product')->getCollection();
foreach($products as $product) {
    Mage::dispatchEvent('catalog_product_save_before', array('product' => $product));
    $product->save();
}

However, if you are trying to do some other stuff on product save why not have that code right with your loop? This will not need to fire any event.

I haven't tested but should work.

  • Thanks Adarsh. I got this error: 'Recoverable Error: Argument 2 passed to Mage::dispatchEvent() must be of the type array, object given.' I'm just wondering what kind of array I need to pass - I'm looking into that now but if you know feel free to share :). – Alan Sep 1 '15 at 10:01
  • Check I have updated. – Adarsh Khatri Sep 1 '15 at 10:02
  • This seems to help but I have another small issue with this code, attribute's values aren't correct. I need to debug and see where's the problem. – Alan Sep 1 '15 at 10:23
  • the product are resaved but with incorrect attribute values and my observer method doesn't run. I have place Mage::log() inside it and it didn't work. – Alan Sep 1 '15 at 10:46
  • is that loop is also called from observer? – Adarsh Khatri Sep 1 '15 at 10:49

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.