Question

I'm using the event catalog_product_save_after to trigger some action after a product has altered/saved. This event does not work when a massaction is used to change the product as this is done without calling save().

  • Is there another event that can be used to monitor product changes?
  • Is there a recommended way to get all product changes?
Was it helpful?

Solution

You can do this job via standard event/observers:

<global>
     <events>
        <catalog_product_save_before>
            <observers>
                <some_module_detect_product_changes>
                    <type>singleton</type>
                    <class>some_module/observer</class>
                    <method>detectProductChanges</method>
                </some_module_detect_product_changes>
            </observers>
        </catalog_product_save_before>
        <catalog_product_attribute_update_before>
            <observers>
                <some_module_detect_product_attribute_changes>
                    <type>singleton</type>
                    <class>some_module/observer</class>
                    <method>detectProductAttributeChanges</method>
                </some_module_detect_product_attribute_changes>
            </observers>
        </catalog_product_attribute_update_before>
</global>

And Observer.php:

class Some_Module_Model_Observer{
    public function detectProductAttributeChanges($observer)
    {
        $attributesData = $observer->getEvent()->getAttributesData();
        $productIds     = $observer->getEvent()->getProductIds();

        $user  = Mage::getSingleton('admin/session')->getUser();
        foreach ($productIds as $id) {
            $change             = Mage::getModel('some_module/changes');
            $change->product_id = $id;
            $change->new_values = print_r($attributesData, true);
            $change->user_id    = ($user) ? $user->getId() : NULL;
            $change->created    = now();
            $change->save();
        }
        return $this;
    }

    public function detectProductChanges($observer)
    {
        /**
         * @var $product Mage_Catalog_Model_Product
         * @var $user    Mage_Admin_Model_User
         */
        $product = $observer->getEvent()->getProduct();
        if ($product->hasDataChanges()) {

            try {
                $user       = Mage::getSingleton('admin/session')->getUser();
                $attributes = $this->getAttributes();
                $new        = array();
                $org        = array();
                $changes    = array();
                foreach ($attributes as $attribute) {
                    if (!is_array($product->getData($attribute))) {
                        $new[$attribute] = ($product->getData($attribute)) ? $product->getData($attribute) : null;
                        if (!is_array($product->getOrigData($attribute))) {
                            $org[$attribute] = ($product->getOrigData($attribute)) ? $product->getOrigData($attribute) : null;
                            if (($new[$attribute] != $org[$attribute])) {
                                $changes[$attribute] = array('new'=> $new[$attribute],
                                                             'old'=> $org[$attribute]);
                            }
                        }
                    }
                }

                $stokAttributes = array(
                    'qty',
                    'manage_stock',
                    'is_in_stock',
                    'min_qty',
                    'min_sale_qty',
                    'max_sale_qty',
                );
                if ($product->getStockItem()) {
                    foreach ($stokAttributes as $attribute=> $value) {
                        $new[$attribute] = ($product->getStockItem()->getData($attribute)) ? $product->getStockItem()->getData($attribute) : null;
                        $org[$attribute] = ($product->getStockItem()->getOrigData($attribute)) ? $product->getStockItem()->getOrigData($attribute) : null;
                        if ($new[$attribute] != $org[$attribute]) {
                            $changes[$attribute] = array('new'=> $new[$attribute],
                                                         'old'=> $org[$attribute]);
                        }
                    }
                }


                $newValues = array_intersect_key($new, $changes);
                if (count($newValues)) {
                    $oldValues = array_intersect_key($org, $changes);

                    $change             = Mage::getModel('some_module/changes');
                    $change->product_id = $product->entity_id;
                    $change->sku        = $product->sku;
                    $change->name       = $product->name;
                    $change->new_values = print_r($newValues, true);
                    $change->old_values = print_r($oldValues, true);
                    $change->user_id    = ($user) ? $user->getId() : NULL;
                    $change->created    = now();
                    $change->save();
                }
            } catch (Exception $e) {
                Mage::log($e->getTraceAsString(), null, 'product_changes_fault.log');
            }
        }
        return $this;
    }

}

Here is I used Changes model to save every changes to DB. And you may create admin grid to view tracked changes on dashboard.

OTHER TIPS

By observing catalog_product_attribute_update_before brought up by mageUz you can store the affected entity_ids referenced by the event as product_ids:

By Zend_Debug::dumping an $observer->getEvent()->getData() where I handled catalog_product_attribute_update_before I got:

array(4) {
  ["attributes_data"] => &array(1) {
    ["status"] => int(1)
  }
  ["product_ids"] => &array(2) {
    [0] => string(6) "159340"
    [1] => string(6) "159339"
  }
  ["store_id"] => &int(0)
  ["name"] => string(39) "catalog_product_attribute_update_before"
}

You could, for example, store those entity_ids in the Magento session singleton.

Then observe end_process_event_catalog_product_mass_action, which is one of Magento's dynamically built events. Handling that will tell you when product changes are complete allowing you to get the updated product state. Since it contains no data itself you'll need those entity_ids you just stored.

I already commented appropriate logic for your situation. But to get understand you I give further code:

class Some_Module_Model_Sync{
public function catalogSynchronizeChangedProducts()
{
    /**
     * suppose you have hash_code attribute for catalog products which is store
     * hash code of synchronizeable attribute values.
     */
    $collection = Mage::getResourceModel('catalog/product_collection');
    foreach ($collection as $product) {
        $hash = md5($product->getName() . $product->getPrice() . $product->getSomeValueYouWantToSyncronize());
        if ($product->getHashCode() != $hash) {
            //if you understand this stuff, product has some changes, because of
            //new hash code not equal to hash code when last synchronized time;
            //you should synchronize this product

            /*after synchronization */
            $product->setHashCode($hash)->save();
        }
    }
}
}

And your cron uses this logic to synchronization your products.

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