在magento 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的核心代码。
|