简单说来,这个事件在Magento处理产品报库存警的集合方法里。我们的客户有超过40000封订阅和超过30000个需要将“缺货”状态改为“有货”。所以当Magento尝试从product_alert_stock表读取40000条记录到集合里的时候,由于内存限制而失败了。可能你的product_alert_stock表有超过20000记录时,产品库存报警功能就失效了。 解决方案相对简单。通过以1000为集合创建分页来遍历超过30000条记录。正如Magento在系统中所做的那样。新的功能是通过遍历所有的这些记录,循环出status=0(未处理)的记录,检查产品现在是否有货。当true=> set status=1就发送电子邮件通知客户。 那么,让我们创建我们的模块,Alwayly_ProductAlert,这将提高Magento方法。 1. Create file in app/etc/modules/ Alwayly_ProductAlert.xml with the following content:<?xml version="1.0"?> <config> <modules> <Alwayly_ProductAlert> <active>true</active> <codePool>local</codePool> </Alwayly_ProductAlert> </modules> </config> 2. Create file in app/code/local/Alwayly/ProductAlert/etc/ config.xml with the following content:<?xml version="1.0"?> <config> <modules> <Alwayly_ProductAlert> <version>1.0.0.0</version> </Alwayly_ProductAlert> </modules> <global> <models> <productalert> <rewrite> <observer>Alwayly_ProductAlert_Model_Observer</observer> </rewrite> </productalert> </models> </global> </config> 你可以看到我们重写了Mage_ProductAlert_Model_Observer类 Create file in /www/app/code/local/Alwayly/ProductAlert/Model/ Observer.php with the following content:<?php /* * ProductAlert observer */ class Alwayly_ProductAlert_Model_Observer extends Mage_ProductAlert_Model_Observer { /** * Process stock emails * * @param Mage_ProductAlert_Model_Email $email * @return Mage_ProductAlert_Model_Observer */ protected function _processStock(Mage_ProductAlert_Model_Email $email) { $email->setType('stock'); foreach ($this->_getWebsites() as $website) { /* @var $website Mage_Core_Model_Website */ if (!$website->getDefaultGroup() || !$website->getDefaultGroup()->getDefaultStore()) { continue; } if (!Mage::getStoreConfig( self::XML_PATH_STOCK_ALLOW, $website->getDefaultGroup()->getDefaultStore()->getId() )) { continue; } try { $wholeCollection = Mage::getModel('productalert/stock') ->getCollection() // ->addWebsiteFilter($website->getId()) ->addFieldToFilter('website_id', $website->getId()) ->addFieldToFilter('status', 0) ; // $wholeCollection->getSelect()->order('alert_stock_id DESC'); /* table: !product_alert_stock! alert_stock_id: 1 customer_id: 1 product_id: 1 website_id: 1 add_date: 2013-04-26 12:08:30 send_date: 2013-04-26 12:28:16 send_count: 2 status: 1 */ } catch (Exception $e) { Mage::log('error-1-collection $e=' . $e->getMessage(), false, 'product_alert_stock_error.log', true); $this->_errors[] = $e->getMessage(); return $this; } $previousCustomer = null; $email->setWebsite($website); try { $originalCollection = $wholeCollection; $count = null; $page = 1; $lPage = null; $break = false; while ($break !== true) { $collection = clone $originalCollection; $collection->setPageSize(1000); $collection->setCurPage($page); $collection->load(); if (is_null($count)) { $count = $collection->getSize(); $lPage = $collection->getLastPageNumber(); } if ($lPage == $page) { $break = true; } Mage::log('page=' . $page, false, 'check_page_count.log', true); Mage::log('collection=' . (string)$collection->getSelect(), false, 'check_page_count.log', true); $page ++; foreach ($collection as $alert) { try { if (!$previousCustomer || $previousCustomer->getId() != $alert->getCustomerId()) { $customer = Mage::getModel('customer/customer')->load($alert->getCustomerId()); if ($previousCustomer) { $email->send(); } if (!$customer) { continue; } $previousCustomer = $customer; $email->clean(); $email->setCustomer($customer); } else { $customer = $previousCustomer; } $product = Mage::getModel('catalog/product') ->setStoreId($website->getDefaultStore()->getId()) ->load($alert->getProductId()); /* @var $product Mage_Catalog_Model_Product */ if (!$product) { continue; } $product->setCustomerGroupId($customer->getGroupId()); if ($product->isSalable()) { $email->addStockProduct($product); $alert->setSendDate(Mage::getModel('core/date')->gmtDate()); $alert->setSendCount($alert->getSendCount() + 1); $alert->setStatus(1); $alert->save(); } } catch (Exception $e) { Mage::log('error-2-alert $e=' . $e->getMessage(), false, 'product_alert_stock_error.log', true); $this->_errors[] = $e->getMessage(); } } } Mage::log("\n\n", false, 'check_page_count.log', true); } catch (Exception $e) { Mage::log('error-3-steps $e=' . $e->getMessage(), false, 'product_alert_stock_error.log', true); } if ($previousCustomer) { try { $email->send(); } catch (Exception $e) { $this->_errors[] = $e->getMessage(); } } } return $this; } /** * Run process send product alerts */ public function process() { Mage::log('ProductAlert started @' . now(), false, 'product_alert_workflow.log', true); $email = Mage::getModel('productalert/email'); /* @var $email Mage_ProductAlert_Model_Email */ $this->_processPrice($email); $this->_processStock($email); $this->_sendErrorEmail(); Mage::log('ProductAlert finished @' . now(), false, 'product_alert_workflow.log', true); return $this; } } 你可以看到,我们重写了process()和 _processStock()方法。在process()方法中,我们添加了Mage::log()创建起止时间到var/log/product_alert_workflow.log。这样我们就能知道脚本是否执行完成。同样的,我们增强_processStock()方法的功能,我们增加了一些Mage:log()调用来跟踪,看所有的行为是否按期待的方式表现。 最后,如果你不想等待你的Cron被触发,你可以在Magento根目录下创建一个文件,让我们调用它。 Alwayly_cron.php<?php require_once 'app/Mage.php'; Mage::app(); try { Mage::getModel('productalert/observer')->process(); } catch (Exception $e) { Mage::log('error-0-start $e=' . $e->getMessage() . ' @' . now(), false, 'product_alert_stock_error.log', true); } 就是这些了,这个解决思路同样适用于产品价格报警。 (责任编辑:好模板) |