{ Hello Magento 2 }

解决 Magento 2 应用问题,更注重深度挖掘。(ง •̀_•́)ง

0%

magento 1 fpc 动态内容

magento 1 企业版的一些页面使用了 fpc ,如果我们调用一个产生随机字符串的方法,那么在 fpc 开着的情况下,我们每次会得到相同的字符串,而不是随机的字符串。那么我们怎样才能每次都得到随机的字符串呢? 我们以 Magento 1.14.1.0 为例,创建一个模块 VendorName_TestModule 做实验。 File: app\etc\modules\VendorName_TestModule.xml

1
2
3
4
5
6
7
8
9
<?xml version="1.0"?>
<config>
<modules>
<VendorName_TestModule>
<active>true</active>
<codePool>local</codePool>
</VendorName_TestModule>
</modules>
</config>

File: app\code\local\VendorName\TestModule\etc\config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0"?>
<config>
<modules>
<VendorName_TestModule>
<version>0.1.0</version>
</VendorName_TestModule>
</modules>
<global>
<blocks>
<testmodule>
<class>VendorName_TestModule_Block</class>
</testmodule>
</blocks>
<helpers>
<testmodule>
<class>VendorName_TestModule_Helper</class>
</testmodule>
</helpers>
</global>
<frontend>
<layout>
<updates>
<testmodule>
<file>testmodule.xml</file>
</testmodule>
</updates>
</layout>
</frontend>
</config>

File:app\design\frontend\rwd\default\layout\testmodule.xml

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<layout version="0.1.0">
<default>
<reference name="content">
<block type="testmodule/fpctest" name="fpctest" template="testmodule/fpctest.phtml" after="-"/>
</reference>
</default>
</layout>

File: app\code\local\VendorName\TestModule\Block\Fpctest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class VendorName_TestModule_Block_Fpctest extends Mage_Core_Block_Template
{
protected function _construct()
{
$this->setTemplate('testmodule/fpctest.phtml');
}

public function getRandString($length = 4)
{
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$str = '';
for ($i = 0; $i < $length; ++$i) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
}

File: app\design\frontend\rwd\default\template\testmodule\fpctest.phtml

1
2
3
4
This is from block
<br/>
<?php echo $this->getRandString() ?>
<br/>

缓存原因,每次刷新页面得到的都是相同字符串。

每次刷新获得随机字符串

File: app\code\local\VendorName\TestModule\etc\cache.xml

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0"?>
<config>
<placeholders>
<testmodule>
<block>testmodule/fpctest</block>
<placeholder>TESTMODULE_CACHE</placeholder>
<container>VendorName_TestModule_Model_Container_Fpctest</container>
<cache_life>5</cache_life>
</testmodule>
</placeholders>
</config>

File: app\code\local\VendorName\TestModule\Model\Container\Fpctest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
class VendorName_TestModule_Model_Container_Fpctest extends Enterprise_PageCache_Model_Container_Abstract{

protected function _renderBlock()
{
$block = $this->_getPlaceHolderBlock();
return $block->toHtml();
}

protected function _getCacheId()
{
return 'TESTMODULE_CACHE' . md5($this->_placeholder->getAttribute('cache_id')).'_'.$this->_getIdentifier();
}

protected function _getIdentifier()
{
return $this->_getCookieValue(Enterprise_PageCache_Model_Cookie::COOKIE_CUSTOMER, '');
}

public function applyWithoutApp(&$content)
{
// by default will attempt to load block from cache.
return false; // always dynamic
}
}

记得刷新缓存 fpc 页面有 4 种状态

  1. Page in cache, no dynamic blocks
  2. Page in cache, dynamic blocks cached
  3. Page in cache, dynamic blocks not cached
  4. Page not in cache

当我们刷新缓存后,再请求页面,我们的页面处于状态 4 ,执行过程就是正常的过程。但是 magento 会根据 cache.xml ,用 <!--{MY_PLACEHOLDER_NAME_hash}-->rendered block content<!--/{MY_PLACEHOLDER_NAME_hash}--> 替代 block 的内容缓存起来, block 也被缓存起来。在最终页面发送之前,再把上面的 placeholder 替换成缓存的 block 内容。缓存的 block 内容会有过期时间。 所以我们第二次刷新的时候,页面处于状态 2 ,那么这个时候会请求 container 的 applyWithoutApp($content)。按照道理应该返回 block 的内容(如果 block 没有过期的话)。但是我们返回的是 false ,这时候就是状态 3 了,请求转向 pagecache/request/process 最后来到了 container 的 applyWithApp() ,而 applyWithApp() 则会调用 $this->_renderBlock()。所以我们得到了随机的字符串。 下面讨论下过期时间 File: app\code\local\VendorName\TestModule\Model\Container\Fpctest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
class VendorName_TestModule_Model_Container_Fpctest extends Enterprise_PageCache_Model_Container_Abstract{

protected function _renderBlock()
{
$block = $this->_getPlaceHolderBlock();
return $block->toHtml();
}

protected function _getCacheId()
{
return 'TESTMODULE_CACHE' . md5($this->_placeholder->getAttribute('cache_id')).'_'.$this->_getIdentifier();
}

protected function _getIdentifier()
{
return $this->_getCookieValue(Enterprise_PageCache_Model_Cookie::COOKIE_CUSTOMER, '');
}

protected function _saveCache($data, $id, $tags = array(), $lifetime = 5)
{
parent::_saveCache($data, $id, $tags, $lifetime);
}

}

刷新缓存,我们会发现随机字符串在 5 s 内保持一样,5 s 后由于缓存过期,拿到新的值。如果 $lifetime = 0 那么就会一直过期。

充分利用缓存, placeholder 带参

在 fpc 上打孔,不能直接使用 Mage::registry() 和 Mage::app()->getFrontController()->getAction()->getFullActionName() 这种,因为在状态 3 的时候,页面是转向 pagecache/request/process ,它并不是一个通常的请求。如果你这么用了,那么就会发现,结果很怪异,访问 A 页面正常,访问下 B 页面也正常,再回到 A 页面,哎~ ,怎么把 B 的结果带过来了。。 下面我们让 block 缓存起来,通过 placeholder 带参来解决上面提到的问题。 File: app\code\local\VendorName\TestModule\Block\Fpctest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
class VendorName_TestModule_Block_Fpctest extends Mage_Core_Block_Template
{
// !important
public function getCacheKeyInfo() {
$info = parent::getCacheKeyInfo();
$info['page_type'] = $this->getPagetype();
return $info;
}

protected function _construct()
{
$this->setTemplate('testmodule/fpctest.phtml');
}

public function getRandString($length = 4)
{
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$str = '';
for ($i = 0; $i < $length; ++$i) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}

public function getPagetype()
{
if ($this->hasData('page_type')) {
return $this->getData('page_type');
} else {
return Mage::app()->getFrontController()->getAction()->getFullActionName();
}
}
}

File: app\code\local\VendorName\TestModule\Model\Container\Fpctest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
class VendorName_TestModule_Model_Container_Fpctest extends Enterprise_PageCache_Model_Container_Abstract{

protected function _renderBlock()
{
$block = $this->_getPlaceHolderBlock();
$pageType = $this->_placeholder->getAttribute('page_type');
$block->setPageType($pageType);
return $block->toHtml();
}

protected function _getCacheId()
{
return 'TESTMODULE_CACHE' . md5($this->_placeholder->getAttribute('cache_id')).'_'.$this->_getIdentifier();
}

protected function _getIdentifier()
{
return $this->_getCookieValue(Enterprise_PageCache_Model_Cookie::COOKIE_CUSTOMER, '');
}

protected function _saveCache($data, $id, $tags = array(), $lifetime = 5)
{
parent::_saveCache($data, $id, $tags, $lifetime);
}
}

File: app\design\frontend\rwd\default\template\testmodule\fpctest.phtml

1
2
3
4
5
This is from block
<br/>
<?php echo $this->getRandString() ?>
<br/>
<?php echo $this->getPagetype();?>

参考链接

How do I include a dynamic block in the product page with full page caching turned on? Overcoming Magento’s full-page cache through hole punching what do cache.xml in etc folder of any module?