如何在打开完整页面caching的产品页面中包含一个dynamic块?

我们想添加一个dynamic块到产品页面。 问题是产品页面有整页caching(由于速度问题,我们无法closures)。 我们希望根据login用户的帐户在每个产品页面上显示不同的信息,并且因产品而异。

我创build了一个具有自己的caching的单独的块,但是这显示了与上一个产品页面相同的块。 我试图改变它的caching方法,所以它不会保存上一个产品页面的caching。

这是我进入产品页面的前几次,但突然开始显示一个Magento错误页面,说:“网站遇到错误,同时检索http://www.mycompany.com/productpage.html 。它可能是下来进行维护或configuration不正确。“

这是我迄今为止所做的。 我创build了app / code / local / MyCompany / MyModule / PageCache / etc / config.xml来添加MyCompany_PageCache_Model。

然后,我创build了这个文件,用于控制app / code / local / MyCompany / MyModule / PageCache / Model / Container / MyFile.php中的caching与这些function:

protected function _getCacheId() { return 'CONSTANT_CACHE' . md5($this->_placeholder->getAttribute('cache_id')); } protected function _saveCache($data, $id, $tags = array(), $lifetime = null) { return false; } protected function _renderBlock() { $blockClass = $this->_placeholder->getAttribute('block'); $template = $this->_placeholder->getAttribute('template'); $block = new $blockClass; $block->setTemplate($template); $block->setLayout(Mage::app()->getLayout()); return $block->toHtml(); } 

我还在Catalog / etc下用CONSTANT_CACHE的占位符创build了cache.xml。

上面的语法是不正确的,还是有一个更简单的方法来做到这一点?

概观

为了回答我需要先解释一下。 Magento FPC过程知道四个状态。

  1. 页面caching,没有dynamic块
  2. 页caching,dynamic块caching
  3. 页面caching,dynamic块不caching
  4. 页面不在caching中

状态1和2在没有完整的Magento应用程序被初始化的情况下被处理。 状态3和4要求应用程序被初始化并且路由被处理。 出于这个原因,如果可能的话,目的是服务于国家1和2的要求,否则你失去了FPC可能改进的很大一部分。

状态1

状态1从开发者的观点来看是无聊的,无所事事,所以让我们继续…

状态2

在状态2中,页面包含dynamic块。 目前,Magento尚未完全初始化
FPC处理器加载一个caching页面,并在其中find一个dynamic块的占位符。
通过分析占位符,处理器能够识别dynamic块的容器类,实例化它,并调用applyWithoutApp($content) 。 (方法的名称是指Magento应用程序到目前为止尚未初始化的事实)。 容器然后尝试使用方法$this->_getCacheId()返回的caching键从块caching加载dynamic块内容。
如果返回caching键并且可以装入caching项,那么容器类将使用caching块输出replace$content的占位符,并且完成FPC。
到目前为止没有产生太多的开销。

状态3

因此,状态2中的applyWithoutApp($content)无法获取并传递dynamic块内容,因此即使在FPC中find了页面的其余部分,也需要生成块内容。
为此,FPC模块将请求设置为pagecache/request/process ,并遵循常规的Magento应用程序初始化和路由。
这意味着在状态2下会产生更多的开销,即使在没有FPC的情况下仍然比普通的页面加载要好一些,因为例如URL重写被跳过了。
最后,前端控制器和标准路由器将请求委托给RequestController::processAction()方法。
该方法获取dynamic块的先前实例化的容器类,并调用applyInApp($content)
这个方法运行$this->_renderBlock()来实例化实际的块类并返回它的输出。 你已经根据你的问题实现了这个方法。 FPC现在可以用块内容replace占位符并提供页面。
有一点要注意的是,这不是一个普通的产品详细页面请求,所以如Mage::registry('current_product')不可用! 根据您的块实现,这可能会影响块级caching或dynamic块的内容生成。 我怀疑这可能是你的问题源于哪里,但我会进一步find一个可能的解决方法。

状态4

在这种状态下,FPC没有find请求页面的cachinglogging,所以Magento像往常一样生成页面,例如,产品详细信息页面输出由Mage_Catalog_ProductController::viewAction()
所有根据cache.xmlconfiguration为dynamic的块都封装在占位符标记中。
占位符标记包含参数,稍后传递给第2步和第3步的容器对象。始终设置的唯一参数是容器和块类名称。 但是几乎总是设置一个cache_id和一个template
在容器类中,可以使用$this->_placeholder->getAttribute('cache_id')来访问这些值(就像在容器的_getCacheId()方法中那样)。

即使你在这个冗长的答案的大部分上下文,这是它可能会让你感兴趣的地方。 如果需要额外的值来生成块cachingID或块输出(例如产品ID或客户ID),则可以将这些值设置为占位符的参数

为此,您需要使用string作为数组键将其设置在块getCacheKeyInfo()方法返回的数组上 。 如果使用数字数组索引,则不会将其设置为占位符上的参数。

 public function getCacheKeyInfo() { $info = parent::getCacheKeyInfo(); $info['current_product_id'] = Mage::registry('current_product')->getId(); $info['customer_id'] = Mage::getSingleton('customer/session')->getCustomerId(); return $info; } 

现在可以使用$this->_placeholder->getAttribute('current_product_id')在容器类中访问这些值。

结论

你可能不想在你的容器类中覆盖_saveCache()来返回false 。 相反,在由_getCacheId()返回的string中包含客户ID和产品ID。 这样每个客户得到他自己的caching条目。 由于applyWithoutApp()可以从caching中保存和加载dynamic块(如果一个页面被同一客户查看两次),一些开销将会减less。

_renderBlock()设置你需要的_renderBlock() ,以便块能够生成它的内容,例如

 $block->setProductId($this->_placeholder->getAttribute('current_product_id')); 

在caching信息数组中包含产品ID和客户ID的块方面将确保每个客户都获得所请求页面的正确输出,即使块被caching。

我无法确定(你没有提供块代码),但是我怀疑你使用的cachingID并不包含它需要唯一地将块的cachinglogging映射到正确的产品的所有参数。

使用这些步骤并知道如何将parameter passing给dynamic块容器,即使在创build自定义dynamic块时,也可以保留大部分的FPC性能增益。 我希望这些信息足以让你跟踪你正在描述的问题并修复它。

一般来说,如果要个性化要存储在整个页面caching中的页面,可以使用两种方法。

  1. 如果您的反向代理支持它,您可以使用ESI(Edge Side Includes)并适当地标记您的模板。 ESI允许您在生成的HTML中插入一个标记,以便在个性化内容应该去的地方,然后您的代理将在需要时从您的应用服务器的适当控制器path请求个性化内容。 如果您使用清漆 , ESI可以使用。 Magento的Lightspeed扩展具有一个名为“ 打孔”的function ,它可以做类似的事情。
  2. 如果ESI或Hole Punching不可用,则另一个选项是允许将主页面caching在整个页面caching中,并使用一些javascript来创build单独的Ajax请求并获取所需的信息。

我很欣赏Vinai的回答。 另外,我会build议Gordon Lesti的FPC延伸支持打孔。 你可以在这里得到它

有关如何使用此扩展程序打孔的说明,build议您访问此页面

我希望能帮助那些不太了解概念的人。

没有必要:

  $info['current_product_id'] = Mage::registry('current_product')->getId(); 

你可以使用这个方法:

 $this->_getProductId() 

在Enterprise_PageCache_Model_Container_Abstract中实现