我们想在产品页面添加动态块。问题是产品页面具有完整页面缓存(由于速度问题,我们无法将其关闭)。我们希望根据登录用户的帐户在每个产品页面上显示不同的信息,并且因产品而异。
我创建了一个单独的块,它有自己的缓存,但是它显示的是上一个产品页面中的相同块。我正在尝试更改它的缓存方法,因此它不会保存以前产品页面中的缓存。
我最初几次访问产品页面,然后突然开始显示一个Magento错误页面,上面写着“网站在检索http://www.mycompany.com/productpage.html时遇到错误。” 它可能已关闭以进行维护或配置不正确。“
这是我到目前为止所做的。
我创建
app/code/local/MyCompany/MyModule/PageCache/etc/config.xml
以添加 MyCompany_PageCache_Model。然后我在
app/code/local/MyCompany/MyModule/PageCache/Model/Container/MyFile.php
中创建了控制缓存的文件 有了这些功能:
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();
}
我还使用 CONSTANT_CACHE
的占位符在目录/ etc 下创建了 cache.xml 。上面的语法是否不正确,或者有更简单的方法吗?
答案 0 :(得分:122)
为了回答我需要先解释一下。 Magento FPC流程知道四种状态。
在没有初始化完整Magento应用程序的情况下处理状态1和2。状态3和4要求初始化应用程序并处理路由。出于这个原因,如果可能的话,目的是服务于州1和2的请求,否则你将失去FPC可能改进的很大一部分。
状态1从开发人员的角度来看很无聊,无所事事,所以让我们继续......
在状态2中,页面包含动态块。 目前,Magento尚未完全初始化
FPC处理器加载缓存页面并在其中找到动态块的占位符
通过分析占位符,处理器能够识别动态块的容器类,实例化它,并在其上调用applyWithoutApp($content)
。 (该方法的名称是指到目前为止Magento应用程序尚未初始化的事实)。
然后容器尝试使用方法$this->_getCacheId()
返回的缓存键从块缓存加载动态块内容。
如果返回缓存键并且可以加载缓存条目,则容器类将$content
中的占位符替换为缓存块输出并完成FPC。
到目前为止,没有产生太多的开销。
因此状态2中的applyWithoutApp($content)
无法获取并传递动态块内容,因此即使在FPC中找到了页面的其余部分,也需要生成块内容。
为此,FPC模块将请求设置为pagecache/request/process
,并遵循常规Magento应用程序初始化和路由。
这意味着在状态2下产生了更多的开销,即使它仍然比没有FPC的常规页面加载好一些,因为例如跳过URL重写。
最后,前端控制器和标准路由器将请求委托给RequestController::processAction()
方法
该方法为动态块提取先前实例化的容器类,并在其上调用applyInApp($content)
此方法运行$this->_renderBlock()
以实例化实际块类并返回其输出。您已根据自己的问题实施了此方法。 FPC现在可以用块内容替换占位符并传送页面
需要注意的一件事是,这不是常规的产品详情页面请求,例如Mage::registry('current_product')
不可用!
根据您的块实现,这可能会影响块级缓存或动态块的内容生成。我怀疑这可能是你的问题源于何处,但我会进一步解决可能的解决方法。
在这种状态下,FPC没有找到所请求页面的缓存记录,因此Magento像往常一样生成页面,例如产品详细信息页面输出由Mage_Catalog_ProductController::viewAction()
创建
根据{{1}},配置为动态的所有块都包含在占位符标记中
占位符标记包含参数,稍后将其传递给第2步和第3步的容器对象。始终设置的唯一参数是容器和块类名。但几乎总是设置cache.xml
和cache_id
在容器类中,可以使用template
访问这些值(就像在容器的_getCacheId()方法中所做的那样)。
即使你在这个冗长的答案中找到了大部分内容,这也是你可能感兴趣的地方。如果您需要其他值来生成块缓存ID或块输出(例如,产品ID或客户ID),可以将这些值设置为占位符的参数。
为此,您需要在块$this->_placeholder->getAttribute('cache_id')
方法返回的数组上设置它们,并使用字符串作为数组键。如果使用数字数组索引,则不会将其设置为占位符的参数
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()
。而是将客户ID和产品ID包含在false
返回的字符串中。这样每个客户都可以获得自己的缓存条目。由于_getCacheId()
可以从缓存中保存和加载动态块(如果同一客户查看两次页面),则会减少一些开销。
在applyWithoutApp()
中设置您需要的其他值,以便块能够在其上生成内容,例如
_renderBlock()
在块的方面,包括缓存信息数组中的产品ID和客户ID,将确保每个客户获得所请求页面的正确输出,即使缓存块也是如此。
我无法确定,(您还没有提供阻止代码),但我怀疑您使用的缓存ID并不包含唯一映射所需的所有参数将块缓存记录到正确的产品。
使用这些步骤并了解如何将参数传递给动态块容器,即使在创建自定义动态块时,也可以保留大部分FPC性能增益。我希望这些信息足以让您能够找到您正在描述的问题并进行修复。
答案 1 :(得分:5)
通常,如果您想要个性化要存储在整页缓存中的页面,可以使用两种方法。
答案 2 :(得分:1)
我非常感谢Vinai的回答。 另外,我想建议Gordon Lesti支持打孔的FPC扩展。 You can get it over here
有关如何使用此扩展程序进行打孔的说明,建议您访问this page
我希望它可以帮助那些不太熟悉这些概念的人。
答案 3 :(得分:1)
没有必要:
$info['current_product_id'] = Mage::registry('current_product')->getId();
您可以使用此方法:
$this->_getProductId()
在Enterprise_PageCache_Model_Container_Abstract
中实现