繁体   English   中英

Magento:如果窗口小部件参数发生变化,则从块/整页缓存中刷新窗口小部件

[英]Magento: Flush widget from block / fullpage cache if widget parameters change

我们在商店的起始页面上有一个小部件。

该商店使用FPC和块缓存。

如果管理员更改后端的窗口小部件设置,我们如何更新窗口小部件内容?

是否可以在CacheKey中使用Widget的配置数据?

或者我们是否必须将缓存寿命设置得非常小?

编辑:我自己的答案使用缓存生命周期。 仅在编辑窗口小部件实例时从FPC明确清理缓存块的方法是什么?

EE整页缓存和窗口小部件实例缓存

(没有重写,无限制的缓存生命周期)

概观

第一步是创建前端窗口小部件,但提供整页缓存可以使用的一些附加信息。
第二步是在窗口小部件的整页缓存中处理打孔。
第三步是如果在管理区域中更改了此窗口小部件,则仅自动清除窗口小部件缓存。

第一步:创建小部件

首先,为您的模块创建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));
        }
    }

由于这个小gem,我们不必重写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;
    }
}

当我们现在通过管理界面添加窗口小部件例如, unique_id参数widget.xml的将被添加到布局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条目存在,就不会刷新占位符参数。
使用缓存将窗口小部件参数传递给块可避免重写窗口小部件实例模型并在动态呈现块时加载窗口小部件实例。

您可以实现方法getCacheKeyInfo并使用一些特定于块的值来生成唯一的哈希。

在Magento EE中,您可以在块Enterprise_Banner_Block_Widget_Banner看到它

我认为唯一的可能性是通过cache_lifetime参数执行此操作。 因此,我们将此设置为大约30秒,每30秒根据当前配置刷新窗口小部件。

当参数发生变化时,我没有找到立即从缓存中删除项目的解决方案。

这就是我做的:

  1. 首先,窗口小部件块需要知道窗口小部件实例的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; } 
  2. 在我的widget块中,我将cachelifetime设置得非常小,以避免双重缓存:编辑:不需要,因为FPC禁用了块缓存

     public function getCacheLifetime() { return 1; } 
  3. 在缓存信息中包含当前模板和窗口小部件实例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(), ); } 
  4. 现在我们必须为这个小部件创建一个自己的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(); } } 
  5. 我们必须为此占位符添加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> 
  6. 最后,小部件必须在后端保存一次,以便生成新的布局xml。

尝试下一步方法:

  1. 覆盖模块中的Enterprise_PageCache_Model_Validator
  2. Mage_Widget_Block_Interface添加到Mage_Widget_Block_Interfaceprotected $_dataChangeDependency数组。

  3. 以下一种方式重写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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM