我们商店的起始页面上有一个小部件。
该商店使用FPC和块缓存。
如果管理员更改了后端的窗口小部件设置,我们如何更新窗口小部件内容?
是否可以在CacheKey中使用Widget的配置数据?
或者我们必须将缓存寿命设置得非常小吗?
编辑:我自己的答案使用缓存生存期。 只有在编辑窗口小部件实例时才能从FPC中明确清理缓存块的方法是什么?
答案 0 :(得分:13)
第一步是创建前端窗口小部件,但提供整页缓存可以使用的其他信息。
第二步是在窗口小部件的整页缓存中处理打孔
第三步是仅在此小部件中自动清除小部件缓存(如果在管理区域中更改了该小部件)。
首先,为您的模块创建 etc / widget.xml 文件:
<widgets>
<netzarbeiter_test type="netzarbeiter_test/widget_test">
<name>FPC Holepunch Cache Test</name>
<description>Dummy test widget</description>
<parameters>
<!-- This is the important parameter here: -->
<unique_id>
<required>1</required>
</unique_id>
<example_text>
<visible>1</visible>
<label>Example Text Parameter</label>
<type>text</type>
</example_text>
</parameters>
</netzarbeiter_test>
</widgets>
注意参数<unique_id>
。我们不提供输入类型或值,它将通过Mage_Widget_Block_Adminhtml_Widget_Options::_addField()
方法自动填充生成的值:
// Excerpt from Mage_Widget_Block_Adminhtml_Widget_Options::_addField()
if ($values = $this->getWidgetValues()) {
$data['value'] = (isset($values[$fieldName]) ? $values[$fieldName] : '');
}
else {
$data['value'] = $parameter->getValue();
//prepare unique id value
if ($fieldName == 'unique_id' && $data['value'] == '') {
$data['value'] = md5(microtime(1));
}
}
由于这个小宝石,我们不必须重写Mage_Widget_Model_Widget_Instance
类,将widget ID注入生成的布局xml。
接下来,创建窗口小部件类本身。这只是实现Mage_Widget_Block_Interface
接口的常规块实例,除了在unique_id
方法中使用cacheKeyInfo
。
class Netzarbeiter_Test_Block_Widget_Test
extends Mage_Core_Block_Abstract
implements Mage_Widget_Block_Interface
{
public function getCacheKeyInfo()
{
$info = parent::getCacheKeyInfo();
if ($id = $this->getData('unique_id')) {
// Because the array key is a string, it will be added to the FPC placeholder
// parameters. That is how the FPC container can access it (see below).
$info['unique_id'] = (string) $id;
}
return $info;
}
protected function _toHtml()
{
// The FPC was completely cleared (or not created yet),
// recreate the widget parameter cache
if (! $this->getFullPageCacheEnvironment() && $this->getUniqueId()) {
$id = Netzarbeiter_Test_Model_Fpc_Container_Widget_Test::CACHE_PREFIX . $this->getUniqueId() . '_params';
Enterprise_PageCache_Model_Cache::getCacheInstance()->save(serialize($this->getData()), $id);
}
// Just some dummy output to display the text parameter and the render time
$time = now();
$textParam = $this->escapeHtml($this->getExampleText());
return <<<EOF
<p><b>Render Time:</b> {$time}<br/>
<b>Example Text:</b> {$textParam}<br/></p>
EOF;
}
}
当我们现在通过管理界面添加一个小部件实例时, widget.xml 中指定的unique_id
参数将被添加到布局xml中(为了可读性而添加了格式:
SELECT layout_update_id, handle, xml FROM core_layout_update;
+------------------+--------------------------+----------------------------------------------------------------------------------------------------+
| layout_update_id | handle | xml |
+------------------+--------------------------+----------------------------------------------------------------------------------------------------+
| 17 | catalog_category_layered | <reference name="left">
| | | <block type="netzarbeiter_test/widget_test" name="2a3b55e13549e176709fc6c67a4a7bd8">
| | | <action method="setData">
| | | <name>unique_id</name>
| | | <value>7fa2574145ef204fb6d179cfc604ac76</value>
| | | </action>
| | | <action method="setData">
| | | <name>example_text</name>
| | | <value>This is a String!</value>
| | | </action>
| | | </block>
| | | </reference>
+------------------+--------------------------+----------------------------------------------------------------------------------------------------+
这意味着,只要通过布局xml渲染创建块实例,就会在块对象上知道unique_id
参数。
添加 etc / cache.xml 文件:
<config>
<placeholders>
<cms_block_widget>
<block>netzarbeiter_test/widget_test</block>
<placeholder>WIDGET_FPC_TEST</placeholder>
<container>Netzarbeiter_Test_Model_Fpc_Container_Widget_Test</container>
</cms_block_widget>
</placeholders>
</config>
接下来,创建容器类:
class Netzarbeiter_Test_Model_Fpc_Container_Widget_Test
extends Enterprise_PageCache_Model_Container_Abstract
{
const CACHE_PREFIX = 'TEST_WIDGET_';
protected function _getCacheId()
{
return self::CACHE_PREFIX . $this->_placeholder->getAttribute('unique_id');
}
protected function _renderBlock()
{
$block = $this->_getPlaceHolderBlock();
// Set any parameters from the placeholder on the block as needed.
// See observer below where the current parameters are cached.
$id = $this->_getCacheId() . '_params';
if ($parameters = Enterprise_PageCache_Model_Cache::getCacheInstance()->load($id)) {
$block->addData(unserialize($parameters));
// Set environment information on block (used in _toHtml,
// the params cache is recreated when not set)
$block->setFullPageCacheEnvironment(true);
}
Mage::dispatchEvent('render_block', array('block' => $block, 'placeholder' => $this->_placeholder));
return $block->toHtml();
}
}
这就是使我们的小部件成为完全缓存页面中的动态块所需的一切。但到目前为止,widget块无限期地缓存。我们仍然需要处理缓存刷新。
将事件观察器用于自动*_save_commit_after
事件,所有Magento模型都提供特定于窗口小部件实例的事件。每次在管理界面中保存窗口小部件实例时都会触发它。
<adminhtml>
<events>
<widget_widget_instance_save_commit_after>
<observers>
<netzarbeiter_test>
<model>netzarbeiter_test/observer</model>
<method>widgetWidgetInstanceSaveCommitAfter</method>
</netzarbeiter_test>
</observers>
</widget_widget_instance_save_commit_after>
</events>
</adminhtml>
最后一块拼图是观察者方法:
public function widgetWidgetInstanceSaveCommitAfter(Varien_Event_Observer $observer)
{
/** @var $widget Mage_Widget_Model_Widget_Instance */
$widget = $observer->getEvent()->getObject();
$parameters = $widget->getWidgetParameters();
$uniqueId = isset($parameters['unique_id']) ? $parameters['unique_id'] : '';
if (strlen($uniqueId)) {
$id = Netzarbeiter_Test_Model_Fpc_Container_Widget_Test::CACHE_PREFIX . $uniqueId;
Enterprise_PageCache_Model_Cache::getCacheInstance()->remove($id);
$id = Netzarbeiter_Test_Model_Fpc_Container_Widget_Test::CACHE_PREFIX . $uniqueId . '_params';
Enterprise_PageCache_Model_Cache::getCacheInstance()->save(serialize($parameters), $id);
}
}
现在,即使使用激活的整页缓存,每次保存前端的实例也会自动更新。在所有其他时间,动态块将从缓存中获取。
编辑:在代码中添加了缓存的小部件参数示例,因为正如Alex在下面的注释中指出的那样,只要FPC条目存在,就不会刷新占位符参数。
使用缓存将窗口小部件参数传递给块可以避免重写窗口小部件实例模型,并在动态呈现块时加载窗口小部件实例。
答案 1 :(得分:0)
您可以实现方法getCacheKeyInfo
并使用一些特定于块的值来生成唯一的哈希值。
在Magento EE中你可以看到这个,即在Enterprise_Banner_Block_Widget_Banner
区块
答案 2 :(得分:0)
我认为唯一的可能性是通过cache_lifetime参数执行此操作。 因此,我们将此设置为大约30秒,每30秒根据当前配置刷新窗口小部件。
当参数发生变化时,我没有找到立即从缓存中删除项目的解决方案。
这就是我所做的:
首先,窗口小部件块需要知道窗口小部件实例的ID。为了做到这一点,我不得不在我的一个模块中重写Mage_Widget_Model_Widget_Instance :: generateLayoutUpdateXml:
public function generateLayoutUpdateXml($blockReference, $templatePath = '')
{
$xml = parent::generateLayoutUpdateXml($blockReference, $templatePath);
$injectXml = '<action method="setData"><name>widget_instance_id</name><value>' .
$this->getId() . '</value></action>';
$xml = str_replace('</block>', $injectXml . '</block>', $xml);
return $xml;
}
在我的widget块中,我将cachelifetime设置得非常小以避免双重缓存:编辑:不需要,因为FPC禁用了块缓存
public function getCacheLifetime()
{
return 1;
}
在缓存信息中包含当前模板和小部件实例ID 。我发现那些带有字符串键的数组条目被映射到FPC占位符中的属性:
public function getCacheKeyInfo()
{
$instanceId = $this->getWidgetInstanceId();
return array(
'MYBOX',
Mage::app()->getStore()->getId(),
(int)Mage::app()->getStore()->isCurrentlySecure(),
Mage::getDesign()->getPackageName(),
Mage::getDesign()->getTheme('template'),
'widget_instance_id' => $instanceId,
'template' => $this->getTemplate(),
);
}
现在我们必须为这个小部件创建一个自己的FPC占位符。此占位符加载窗口小部件实例的当前配置并呈现窗口小部件
class MyCompany_PageCache_Model_Container_WidgetInstance
extends Enterprise_PageCache_Model_Container_Abstract
{
protected function _renderBlock()
{
$instanceId = $this->_placeholder->getAttribute('widget_instance_id');
$widgetInstance = Mage::getModel('widget/widget_instance')->load($instanceId);
if($widgetInstance->getId()) {
Mage::logException( new Exception('Widget Instance '.$instanceId.' not found') );
}
$data = $widgetInstance->getWidgetParameters();
$block = $this->_placeholder->getAttribute('block');
$name = $this->_placeholder->getAttribute('name');
$template = $this->_placeholder->getAttribute('template');
$block = new $block;
$block->setTemplate($template);
if ($name !== null) {
$block->setNameInLayout($name);
}
$block->setLayout(Mage::app()->getLayout());
$block->setData($data);
return $block->toHtml();
}
}
我们必须为此占位符添加cache.xml配置:
<mycompany_mybox>
<block>mycompany_mybox/widget</block>
<placeholder>MYCOMPANY_MYBOX_WIDGET</placeholder>
<container>MyCompany_PageCache_Model_Container_WidgetInstance</container>
<cache_lifetime>30</cache_lifetime>
</mycompany_mybox>
最后,小部件必须在后端保存一次,以便生成新的布局xml。
答案 3 :(得分:0)
尝试下一步方法:
Enterprise_PageCache_Model_Validator
。将Mage_Widget_Block_Interface
添加到此课程的protected $_dataChangeDependency
数组中。
以下一种方式重写protected function _getObjectClasses($object)
:
/**
* Get list of all classes related with object instance
*
* @param $object
* @return array
*/
protected function _getObjectClasses($object)
{
$classes = array();
if (is_object($object)) {
$classes[] = get_class($object);
$classes = array_merge($classes, class_implements($object), class_parents ($object));
}
return $classes;
}