Magento 对未定义对象的 count() 分层导航调用

Magento Layered navigation call to count() on undefined object

我在分层导航块中遇到了一个问题,我认为这可能是一个错误。

在块 Mage_Catalog_Block_Navigation 中,方法 _renderCategoryMenuItemHtml:

    // get all children
    // If Flat Data enabled then use it but only on frontend
    $flatHelper = Mage::helper('catalog/category_flat');
    if ($flatHelper->isAvailable() && $flatHelper->isBuilt(true) && !Mage::app()->getStore()->isAdmin()) {
        $children = (array)$category->getChildrenNodes();
        $childrenCount = count($children);
    } else {
        $children = $category->getChildren();
        $childrenCount = $children->count();
    }

我启用了平面类别索引,并且在计划时(每分钟)重建索引。 Magento 版本是 1.14.0.1,有时我会收到一条错误消息:

Call to a member function count() on a non-object

基于 if 子句,我假设当有人在重建索引 (isAvailable) 时访问页面时会发生这种情况。

问题是 else 块中的代码似乎甚至在理论上都不起作用,因为 $category->getChildren() returns 一个字符串。我在这里错过了什么吗?这是一个错误还是我在某处配置错误。

您可以通过打开缓存(所有 cms/catalog/category/404 页面都是在企业版中缓存的完整页面)并在重建索引完成后定期刷新缓存来避免这种情况。考虑增加重建索引之间的间隔。

如果使用内置设置进行调整不起作用,您可以随时进行调试:

Create a log file and make it writable

touch mage-root/var/log/counts.log
chmod 755 mage-root/var/log/counts.log

Replace the child calls with:

// get all children
// If Flat Data enabled then use it but only on frontend
$flatHelper = Mage::helper('catalog/category_flat');
Mage::log( 'Flat data enabled: '  . $flatHelper, null, 'counts.log', FALSE );
if ($flatHelper->isAvailable() && $flatHelper->isBuilt(true) && !Mage::app()->getStore()->isAdmin()) {
    $children = (array)$category->getChildrenNodes();
    Mage::log( 'Children in if: '  . $children, null, 'counts.log', FALSE );
    $childrenCount = count($children);
} else {
    $children = $category->getChildren();
    Mage::log( 'Children in else: '  . $children, null, 'counts.log', FALSE );
    $childrenCount = $children->count();
}

最后,您可以通过将原版 class 复制到以下位置来覆盖它:

app\code\local\Mage\Catalog\Block\Navigation.php

然后在违规语句上方添加 if( !empty( $children ) ) 并长期使用此 'patch'。

进一步查看后,它看起来像是一个错误。问题是竞争条件:

  • Mage_Catalog_Model_Category::_construct 决定使用什么,EAV 或 Flat 资源
  • 然后 Mage_Catalog_Helper_Category::getStoreCategories returns 基于此的不同集合。
  • Mage_Catalog_Block_Navigation::_renderCategoryMenuItemHtml 中,$category 对象是 Mage_Catalog_Model_CategoryVarien_Data_Tree_Node 基于之前使用 Flat 或 EAV 的决定。
  • Mage_Catalog_Block_Navigation::_renderCategoryMenuItemHtml 再次检查是否将对象视为 Flat 或 EAV,并根据此调用不同的方法。

因此,在使用 Flat 资源初始化类别的情况下,类别索引过程在最后一个方法之后但之前的某个时间被锁定,Magento 将处理 $category 作为错误类型的对象。

我的解决方案是另外检查 else 部分中的 $category 类型。

} else {
        if( $category instanceof Varien_Data_Tree_Node )
        {
            $children = $category->getChildren();
        } else
        {
            $children = $category->getChildrenCategories();
        }
    }

我有点害怕的是一个问题,因为我在锁定时访问类别索引。