如何在打开全页缓存的产品页面中包含动态块? [英] How do I include a dynamic block in the product page with full page caching turned on?

查看:22
本文介绍了如何在打开全页缓存的产品页面中包含动态块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们想向产品页面添加一个动态块.问题是产品页面有整页缓存(由于速度问题,我们无法关闭它).我们希望根据登录用户的帐户在每个产品页面上显示不同的信息,并且因产品而异.

We would like to add a dynamic block to the product page. The problem is that the product page has full page caching (and we cannot turn that off due to speed issues). We want to display different information on each product page based on the logged in user's account, and it varies from product to product.

我创建了一个单独的块,它有自己的缓存,但这显示了与上一个产品页面相同的块.我正在尝试更改它的缓存方法,以便它不会保存上一个产品页面的缓存.

I created a separate block that has its own caching, but this displays the same block from the previous product page. I'm trying to alter it's caching method so it doesn't save the cache from the previous product page.

前几次我转到产品页面时它可以工作,但突然开始显示 Magento 错误页面,上面写着该网站在检索 http://www.mycompany.com/productpage.html.
它可能因维护而停机或配置不正确."

It works the first few times I go to the product pages, but then suddenly starts displaying a Magento error page that says, "The website encountered an error while retrieving http://www.mycompany.com/productpage.html.
It may be down for maintenance or configured incorrectly."

这是我到目前为止所做的.

Here is what I've done so far.

我创建了 app/code/local/MyCompany/MyModule/PageCache/etc/config.xml 来添加 MyCompany_PageCache_Model.

然后我在app/code/local/MyCompany/MyModule/PageCache/Model/Container/MyFile.php
中创建了控制缓存的文件具有这些功能:

Then I created the file that controls caching in app/code/local/MyCompany/MyModule/PageCache/Model/Container/MyFile.php
with these functions:

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 下创建了 cache.xml,其中包含 CONSTANT_CACHE 的占位符.

I also created cache.xml under Catalog/etc with my placeholder for CONSTANT_CACHE.

上面的语法是否不正确,或者有更简单的方法吗?

Is the syntax above incorrect, or is there an easier way to do this?

推荐答案

概述

为了回答我需要先解释一下.Magento FPC 进程知道四种状态.

Overview

In order to answer I need to explain a little first. The Magento FPC process knows four states.

  1. 缓存中的页面,没有动态块
  2. 缓存中的页面,缓存动态块
  3. 缓存中的页面,未缓存动态块
  4. 页面不在缓存中

状态 1 和 2 的处理没有初始化完整的 Magento 应用程序.状态 3 和 4 要求初始化应用程序并处理路由.出于这个原因,如果可能的话,力求满足来自状态 1 和 2 的请求,否则您将失去 FPC 可能改进的很大一部分.

State 1 and 2 are processed without the full Magento application being initialized. State 3 and 4 require the application to be initialized and routing to be processed. For that reason, aim to serve requests from state 1 and 2 if possible, otherwise you are losing a big part of the possible improvements of the FPC.

从开发人员的角度来看,状态 1 很无聊,无事可做,所以让我们继续......

State 1 is boring from a developer point of view, nothing to do, so lets move on to...

在状态 2 中,页面包含动态块.目前,Magento 尚未完全初始化.
FPC 处理器加载一个缓存页面并在其中找到一个动态块的占位符.
通过分析占位符,处理器能够识别动态块的容器类,将其实例化,并对其调用 applyWithoutApp($content).(该方法的名称是指到目前为止 Magento 应用程序尚未初始化的事实).然后容器尝试从块缓存中加载动态块内容,使用方法 $this->_getCacheId() 返回的缓存键.
如果返回缓存键并且可以加载缓存条目,则容器类会将 $content 中的占位符替换为缓存的块输出并完成 FPC.
到目前为止,还没有产生多少开销.

In state 2 a page contains dynamic blocks. Right now, Magento has not been fully initialized.
The FPC processor loads a cached page and finds a placeholder for a dynamic block in it.
By analyzing the placeholder, the processor is able to identify the container class for the dynamic block, instantiates it, and calls applyWithoutApp($content) on it. (The name of the method refers to the fact that the Magento application hasn't been initialized so far). The container then tries to load the dynamic block contents from the block cache, using the cache key returned by the method $this->_getCacheId().
If a cache key is returned and a cache entry could be loaded, the container class replaces the placeholder in the $content with the cached block output and the FPC is done.
So far not much overhead has been produced.

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

So applyWithoutApp($content) in state 2 was unable to fetch and deliver the dynamic block content, so the block content needs to be generated, even though the rest of the page has been found in the FPC.
For this purpose the FPC module sets the request to pagecache/request/process, and the regular Magento application initialization and routing is followed.
This means a lot more overhead is produced then with state 2, even though it still is a bit better then a regular page load without the FPC, because e.g. the URL rewriting is skipped.
Finally the front controller and standard router delegate the request to the RequestController::processAction()method.
The method fetches the previously instantiated container class for the dynamic block, and calls applyInApp($content) on it.
This method runs $this->_renderBlock() to instantiate the real block class and return it's output. You already implemented this method according to your question. The FPC can now replace the placeholder with the block content and deliver the page.
One thing to be aware of is that this is not a regular product detail page request, so e.g. Mage::registry('current_product') is not available! Depending on your block implementation, this might influence the block level caching or content generation of the dynamic block. I suspect this might be where your problem stems from, but I'll get to a possible workaround a bit further down.

在这种状态下,FPC 没有找到请求页面的缓存记录,所以 Magento 像往常一样生成页面,例如产品详细信息页面输出由 Mage_Catalog_ProductController::viewAction() 创建.
根据 cache.xml,所有配置为动态的块都包含在占位符标记中.
占位符标签包含参数,稍后将这些参数传递给第 2 步和第 3 步的容器对象.唯一始终设置的参数是容器和块类名称.但几乎总是同时设置 cache_idtemplate.
在容器类中,可以使用 $this->_placeholder->getAttribute('cache_id') 访问这些值(就像您在容器的 _getCacheId() 方法中所做的那样).

In this state the FPC didn't find a cache record for the requested page, so Magento generates the page as usual, e.g. the product detail page output is created by the Mage_Catalog_ProductController::viewAction().
All blocks that are configured to be dynamic, according to the cache.xml, are wrapped in placeholder tags.
The placeholder tags contain arguments, that are later passed to the container object for step 2 and 3. The only arguments that always are set are the container and the block class names. But almost always a cache_id and a template are set as well.
In the container class, these values can be accessed using $this->_placeholder->getAttribute('cache_id') (like you did in the _getCacheId() method of your container).

即使您掩盖了这个冗长答案的大部分内容,这也是您可能会感兴趣的地方.如果您需要其他值来生成块缓存 ID 或块输出(例如产品 ID 或客户 ID),您可以将它们设置为占位符的参数.

Even if you where glossing over most of this lengthy answer, this is where it might get interesting for you. If you need additional values to generate the blocks cache id or the block output, (e.g. the product id or the customer id), you can set these as arguments to the placeholder.

为此,您需要将它们设置在块 getCacheKeyInfo() 方法返回的数组上,并使用 字符串作为数组键.如果您使用数字数组索引,它们将不会被设置为占位符的参数.

To do so you need to set them on the array returned by the block getCacheKeyInfo() method with a string as an array key. If you use a numeric array index they will not be set as arguments on the placeholder.

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') 访问这些值.

These values are now accessible in the container class using $this->_placeholder->getAttribute('current_product_id').

您可能不想覆盖容器类中的 _saveCache() 以返回 false.相反,在 _getCacheId() 返回的字符串中包含客户 ID 和产品 ID.这样每个客户都会获得自己的缓存条目.由于 applyWithoutApp() 可以从缓存中保存和加载动态块(如果同一客户查看了页面两次),因此会减少一些开销.

You probably don't want to override _saveCache() in your container class to return false. Instead, include the customer id and product id in the string returned by _getCacheId(). That way each customer get's his own cache entry. Some overhead will be reduced because applyWithoutApp() can save and load the dynamic block from the cache (if a page is viewed twice by the same customer).

_renderBlock() 中设置您需要的附加值,以便块能够在其上生成其内容,例如

In _renderBlock() set the additional values you need in order for the block to be able to generate it's contents on it, e.g.

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

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

On the block side of things, including the product id and the customer id in the cache info array will ensure that each customer get's the correct output for the requested page, even when the block is cached.

我不能确定,(您还没有提供块代码),但我怀疑您使用的缓存 ID 不包含将块的缓存记录唯一映射到所需的所有参数正确的产品.

I can't know for sure, (you haven't provided the block code), but I suspect the cache id you are using doesn't contain all the arguments it needs to uniquely map the cache record for the block to the right product.

使用这些步骤并了解如何将参数传递给动态块容器,可以保留大部分 FPC 性能增益,即使在创建自定义动态块时也是如此.我希望这些信息足以让您找到所描述的问题并解决它.

Using the steps and knowing how to pass arguments to a dynamic block container it is possible to retain most of the FPC performance gain, even when creating custom dynamic blocks. I hope this information is enough for you to be able to track down the problem you are describing and fix it.

这篇关于如何在打开全页缓存的产品页面中包含动态块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆