注 :文章中问题已在Magento EE 1.14 / CE 1.9得到验证。
最近,我发现了一件非常奇怪的问题。当为一批产品(大于1000件)分配分类时,只有最多一千件产品能够保存成功,而其他的都被忽略了。为了解决这个问题,就需要我们去深入magento的源码进行分析测试。
下面是Magento如何分配产品类别的源码:
class Mage_Adminhtml_Catalog_CategoryController extends Mage_Adminhtml_Controller_Action { public function saveAction() { . . . if (isset($data['category_products']) && !$category->getProductsReadonly()) { $products = array(); parse_str($data['category_products'], $products); $category->setPostedProducts($products); } . . . } }
$data[‘category_products’]是一个产品序列的字符串,通过parse_str生成一个关联数组将产品保存的一个数组中。但是但从这段代码,并没有看出哪里不对,再去error log里检查下,于是发现有如下的警告:
Warning: parse_str(): Input variables exceeded 1000. To increase the limit change
max_input_vars in php.ini.
如你所看到的,这个问题是由于PHP的配置参数max_input_vars引起的,因为php限制了可以接受的输入变量的数量。在PHP版本5.3.9 的说明里有介绍,大致是为了避免哈希冲突, Parse_str对参数数量进行了限制。结果数组的长度大于或者等于1000时,默认只取1000个,这就是为什么只有一个千的产品得到了保存,其余则没有。
要解决这个问题,有2个办法。一是增加max_input_vars参数的值,二是修改magento代码。
1:修改Max_input_vars的值
Max_input_vars值又可以通过两种方式来改变,修改htaccess或修改php.ini。
在magento根目录的htaccess里添加如下行,数值可以视情况改变:
php_value max_input_vars 2000
找到php.ini,找到max_input_vars = 1000,如果改行被注释,就取消注释,然后调整数值。为了使更 改生效,你可能需要重新启动服务器。
2:修改magento代码
改变max_input_vars值虽然快速且简单。但是,如果你的产品和类别每天都在飞速增长着,这种重复 操作就显得有点麻烦。为了避免这种情况,我们可以试着像下面来修改代码:
require_once 'Mage/Adminhtml/controllers/Catalog/CategoryController.php'; class Inchoo_Smile_Adminhtml_Catalog_CategoryController extends Mage_Adminhtml_Catalog_CategoryController { public function saveAction() { ... if (isset($data['category_products']) && !$category->getProductsReadonly()) { $products = array(); $exploded = explode('&', $data['category_products']); foreach ($exploded as $row) { $temp = array(); parse_str($row, $temp); list($key, $value) = each($temp); if(!empty($key)) { $products[$key] = $value; } } $category->setPostedProducts($products); } ... } }
以上方法覆盖了类控制器,但其实我们也可以使用一个更优雅的解决方案。还是在
Mage_Adminhtml_Catalog_CategoryController里,在saveAction的时候,magento会出发一个event叫 catalog_category_prepare_save,通过这个事件就可以对数据进行修改,代码如下:
class Inchoo_Smile_Model_Observer { // event: catalog_category_prepare_save public function assignCategoryProducts($observer) { $category = $observer->getCategory(); $request = $observer->getRequest(); $products = array(); $exploded = explode('&', $request->getParam('category_products')); foreach ($exploded as $row) { $temp = array(); parse_str($row, $temp); list($key, $value) = each($temp); if(!empty($key)) { $products[$key] = $value; } } $category->setPostedProducts($products); } }
以上代码可以放入任何一个你自己写的module里,然后再config里加上event即可,记着不要去修改 magento的核心代码。
来自于:jonas的magento博客