Magento – Fix Recursive Event Observer When Removing Quote Items

event-observerquote

I am working on a custom module that adds two products together – a setup product and a unit product (for example a setup charge for custom graphics and then a unit charge for the number of applications of those graphics)

My problem is that when a visitor removes either the setup or the unit product, I need to remove both products.

I am using the event listener: sales_quote_remove_item

my observer method looks something like this:

public function removeCustomizationItems(Varien_Event_Observer $observer) {
    $_product_id = $observer->getQuoteItem()->getProduct()->getId();

    // returns an array of customization product pairs (setup=>id, unit=>id, min_qty=>(int))
    $_target_products = Mage::helper('hq_customization')->getTargetProducts();

    foreach ($_target_products as $_target_product) {
        if ($_product_id == $_target_product['setup'] || $_product_id == $_target_product['unit']) {
            $this->removeItems($_target_product);
        }
    }
}
public function removeItems($_target_product) {
    if (!empty($_target_product['setup'])) $_remove_ids[] = $_target_product['setup'];
    if (!empty($_target_product['unit'])) $_remove_ids[] = $_target_product['unit'];

    $cartHelper = Mage::helper('checkout/cart');
    $items = $cartHelper->getCart()->getItems();

    foreach ($items as $item) {
        $itemId = $item->getItemId();
        $prodId = $item->getProductId();

        if (in_array($prodId, $_remove_ids)) $cartHelper->getCart()->removeItem($itemId)->save();
    }
}

The problem that I am having is that each call to remove a product from the cart fires the sales_quote_remove_item event which creates an infinite loop.

Any suggestions?

Best Answer

Instead of

    if (in_array($prodId, $_remove_ids)) $cartHelper->getCart()->removeItem($itemId)->save();

you should use something like this:

    if (in_array($prodId, $_remove_ids) && !$quote->getItemById($itemId)->isDeleted())
         $cartHelper->getCart()->removeItem($itemId);

The key here is that removing an item, sets the is_deleted flag and with this you can check if an item is already flagged for deletion. Also you don't need to save each one individually as long as the cart gets saved in the end.

Related Topic