【问题标题】:Magento: serialization error on caching CollectionMagento:缓存集合上的序列化错误
【发布时间】:2015-07-02 15:40:29
【问题描述】:

我编写了一个扩展,其中一个基本抽象类包含一个将提取产品集合的函数:

$cache = Mage::app()->getCache();
        if(!$cache->load('itserv_feed_collection')) {
            $_productCollection = Mage::getModel('catalog/product')->getCollection();
            $_productCollection->addAttributeToSelect('*');                        
            $_productCollection->addAttributeToSelect('stock_status');        
            $_productCollection->addAttributeToSelect(Mage::getStoreConfig('feed_options/mappa_attributi/produttore'));
            $_productCollection->addAttributeToSelect(Mage::getStoreConfig('feed_options/mappa_attributi/ean'));
            $_productCollection->addAttributeToSelect(Mage::getStoreConfig('feed_options/mappa_attributi/mpn'));      
            $_productCollection->addAttributeToFilter('type_id', Mage_Catalog_Model_Product_Type::TYPE_SIMPLE);                                                                       
            $cache->save(serialize($_productCollection), "itserv_feed_collection", array("itserv_feed_collection"), 120);                
        }
        else {                
            $_productCollection = unserialize($cache->load('itserv_feed_collection'));
        }
        return $_productCollection;

从这个类扩展的每个子类都将使用同一个运行时堆栈中的同一个集合。我想将此集合保存在缓存中(正如您在查看代码时看到的那样),因此由于子类将第二次使用它,因此脚本不需要再次加载它。

问题是不可能使用缓存,因为缓存需要一个序列化的集合,在这种情况下,我不能这样做,因为集合包含无法序列化的 Mage_Core_Model_Config_Element(它会触发著名的错误“序列化'Mage_Core_Model_Config_Element' 是不允许的”)。

我尝试了不同的解决方案,甚至使用 json_encode/json_decode 代替 serialize/unserialize,但我无法解决问题。

你有什么解决办法吗?谢谢!

【问题讨论】:

  • 您能否根据收藏中的其他信息再次正确设置 Mage_Core_Model_Config_Element ?如果是这样,每次反序列化对象时都会调用魔术方法__wakup,这样就可以解决问题?
  • 首先,感谢您的评论。 “...再次正确设置 Mage_Core_Model_Config_Element...”是什么意思?
  • 我的意思是:Mage_Core_Model_Config_Element 的目的是什么?是否需要它?难道您不能从中获取标识符,以便您可以通过__wakeup 正确重新加载它吗?

标签: magento caching serialization magento-1.9


【解决方案1】:

这可能有点晚了,但希望将来能让某人走上正轨。

正如您所注意到的,您无法序列化集合,但您可以将返回的项目作为数组获取并缓存它们。这是第 1 步。

然后,根据您使用集合的方式(例如在产品列表上)和调用 count(),Magento 将尝试再次加载集合,导致错误,因为 IsLoaded 标志将为 false,但是您会有物品。

要解决这个问题,您需要在将项目添加到集合后设置标志。为此,您应该重写产品资源集合(以访问此标志)。所以在代码方面:

代码基于您要使用产品列表页面上的集合的假设,不支持排序/过滤等,因为只有项目被缓存。

第 1 步: 添加对产品列表和产品资源集合的重写:

<config>
    <global>
        <blocks>
            <projectName>
                <class>CompanyName_ProjectName_Block</class>
            </projectName>
            <catalog>
                <rewrite>
                    <product_list>CompanyName_ProjectName_Block_Catalog_Product_List</product_list>
                </rewrite>
            </catalog>
        </blocks>
        <models>
            <projectName>
                <class>CompanyName_ProjectName_Model</class>
            </projectName>
            <catalog_resource>
                <rewrite>
                    <product_collection>CompanyName_ProjectName_Model_Resource_Product_Collection</product_collection>
                </rewrite>
            </catalog_resource>
        </models>
    </global>
<config>

第 2 步:创建资源类

<?php
class CompanyName_ProjectName_Model_Resource_Product_Collection extends Mage_Catalog_Model_Resource_Product_Collection
{
    public function setIsLoaded($flag)
    {
        $this->_setIsLoaded($flag);
    }
}

第 3 步:创建执行实际缓存加载的产品列表类

<?php
class CompanyName_ProjectName_Block_Catalog_Product_List extends Mage_Catalog_Block_Product_List
{   
    public function getCachedLoadedProductCollection()
    {
        $cache = Mage::app()->getCache();
        $cacheKey = 'category_products_' .  Mage::app()->getStore()->getId() . '_' . $this->getCategoryId() . '_' . date('d-m-Y');
        $cachedProductCollection = $cache->load($cacheKey);

        if (!$cachedProductCollection) {
            $loadedProductCollection = parent::getLoadedProductCollection();
            $cachedProductCollection = serialize($loadedProductCollection->exportToArray());
            $cache->save($cachedProductCollection, $cacheKey, array('ProjectName'), 3600);
        } else {
            $loadedProductCollection = Mage::getModel('catalog/product')->getResourceCollection();
            $loadedProductCollection->setIsLoaded(true);
            $cachedProductCollectionArray = unserialize($cachedProductCollection);   
            $loadedProductCollection->importFromArray($cachedProductCollectionArray);
        }

        return $loadedProductCollection;
    }
}

代码可以更紧凑一些,但这样更容易理解。这旨在代替 getLoadedProductCollection 被调用,以便于例如在一页中从多个类别中获取产品。希望对您有所帮助!

【讨论】:

    【解决方案2】:

    Magento 有其内置的集合缓存,但请记住,集合缓存不缓存集合对象,它缓存基于执行的 sql 从数据库加载的数据。

    在你的情况下,你可以试试下面的代码:

            $_productCollection = Mage::getModel('catalog/product')->getCollection();
            $_productCollection->addAttributeToSelect('*');                        
            $_productCollection->addAttributeToSelect('stock_status');        
            $_productCollection->addAttributeToSelect(Mage::getStoreConfig('feed_options/mappa_attributi/produttore'));
            $_productCollection->addAttributeToSelect(Mage::getStoreConfig('feed_options/mappa_attributi/ean'));
            $_productCollection->addAttributeToSelect(Mage::getStoreConfig('feed_options/mappa_attributi/mpn'));      
            $_productCollection->addAttributeToFilter('type_id', Mage_Catalog_Model_Product_Type::TYPE_SIMPLE);                                                                       
    
           if (Mage::app()->useCache('collections')) {
                $_productCollection->initCache(
                   Mage::app()->getCache(),
                   "defineuniquevalue",
                   array("COLLECTION_DATA")
             );
         }
     return $_productCollection;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多