Version Notes
N/A
Download this release
Release Info
Developer | Jonathan Selander |
Extension | Made_Cache |
Version | 1.4.0 |
Comparing to | |
See all releases |
Code changes from version 1.1.2 to 1.4.0
- app/code/community/Made/Cache/Block/Catalog/Product/List.php +8 -1
- app/code/community/Made/Cache/Block/Messages.php +19 -0
- app/code/community/Made/Cache/Block/Profiler.php +45 -0
- app/code/community/Made/Cache/Block/Varnish/Footer.php +32 -0
- app/code/community/Made/Cache/Helper/Data.php +75 -0
- app/code/community/Made/Cache/Helper/Varnish.php +251 -0
- app/code/community/Made/Cache/Model/Layout.php +48 -11
- app/code/community/Made/Cache/Model/Observer.php +72 -40
- app/code/community/Made/Cache/Model/Observer/Abstract.php +2 -0
- app/code/community/Made/Cache/Model/Observer/Catalog.php +25 -15
- app/code/community/Made/Cache/Model/Observer/Checkout.php +3 -7
- app/code/community/Made/Cache/Model/Observer/Cms.php +6 -10
- app/code/community/Made/Cache/Model/Profiler.php +65 -0
- app/code/community/Made/Cache/Model/VarnishObserver.php +304 -0
- app/code/community/Made/Cache/controllers/VarnishController.php +43 -0
- app/code/community/Made/Cache/etc/config.xml +139 -10
- app/code/community/Made/Cache/etc/magento.vcl +118 -184
- app/code/community/Made/Cache/etc/system.xml +99 -0
- app/design/frontend/base/default/layout/madecache.xml +47 -8
- package.xml +4 -4
app/code/community/Made/Cache/Block/Catalog/Product/List.php
CHANGED
@@ -18,6 +18,11 @@ class Made_Cache_Block_Catalog_Product_List extends Mage_Catalog_Block_Product_L
|
|
18 |
*/
|
19 |
public function getProductHtml($product)
|
20 |
{
|
|
|
|
|
|
|
|
|
|
|
21 |
$name = 'prod_list_prod_' . $product->getId();
|
22 |
$block = $this->getLayout()->createBlock('cache/catalog_product_list_product')
|
23 |
->setName($name)
|
@@ -25,6 +30,8 @@ class Made_Cache_Block_Catalog_Product_List extends Mage_Catalog_Block_Product_L
|
|
25 |
->setTemplate('catalog/product/list/product.phtml')
|
26 |
->setProduct($product);
|
27 |
|
28 |
-
|
|
|
|
|
29 |
}
|
30 |
}
|
18 |
*/
|
19 |
public function getProductHtml($product)
|
20 |
{
|
21 |
+
// Prevent crash within catalog_product_view
|
22 |
+
if (($viewedProduct = Mage::registry('product')) !== null) {
|
23 |
+
Mage::unregister('product');
|
24 |
+
}
|
25 |
+
|
26 |
$name = 'prod_list_prod_' . $product->getId();
|
27 |
$block = $this->getLayout()->createBlock('cache/catalog_product_list_product')
|
28 |
->setName($name)
|
30 |
->setTemplate('catalog/product/list/product.phtml')
|
31 |
->setProduct($product);
|
32 |
|
33 |
+
$html = $block->toHtml();
|
34 |
+
Mage::register('product', $viewedProduct);
|
35 |
+
return $html;
|
36 |
}
|
37 |
}
|
app/code/community/Made/Cache/Block/Messages.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* When varnish is in front we use ESI and a custom messages getter action
|
4 |
+
*
|
5 |
+
* @author jonathan@madepeople.se
|
6 |
+
*/
|
7 |
+
class Made_Cache_Block_Messages extends Mage_Core_Block_Messages
|
8 |
+
{
|
9 |
+
protected function _toHtml()
|
10 |
+
{
|
11 |
+
if (Mage::helper('cache/varnish')->shouldUse()
|
12 |
+
&& !$this->getBypassVarnish()) {
|
13 |
+
return Mage::helper('cache/varnish')
|
14 |
+
->getEsiTag('madecache/varnish/messages');
|
15 |
+
}
|
16 |
+
|
17 |
+
return parent::_toHtml();
|
18 |
+
}
|
19 |
+
}
|
app/code/community/Made/Cache/Block/Profiler.php
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Block that displays a simple block rendering profiler
|
4 |
+
*
|
5 |
+
* @package Made_Cache
|
6 |
+
* @author info@madepeople.se
|
7 |
+
* @copyright Copyright (c) 2012 Made People AB. (http://www.madepeople.se/)
|
8 |
+
*/
|
9 |
+
class Made_Cache_Block_Profiler extends Mage_Core_Block_Abstract
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* Render basic HTML
|
13 |
+
*
|
14 |
+
* @return string
|
15 |
+
*/
|
16 |
+
protected function _toHtml()
|
17 |
+
{
|
18 |
+
$profilerData = Made_Cache_Model_Profiler::getProfilerData();
|
19 |
+
if (empty($profilerData)) {
|
20 |
+
return;
|
21 |
+
}
|
22 |
+
|
23 |
+
$totalTime = 0;
|
24 |
+
|
25 |
+
$html = '<table>';
|
26 |
+
$html .= '<thead><tr><th>Block</th><th>Time (ms)</th></tr></thead>';
|
27 |
+
$html .= '<tbody>';
|
28 |
+
|
29 |
+
foreach ($profilerData as $blockName => $time) {
|
30 |
+
$html .= '<tr>'
|
31 |
+
. '<td>' . $blockName . '</td>'
|
32 |
+
. '<td>' . intval($time*1000) . '</td>'
|
33 |
+
. '</tr>';
|
34 |
+
|
35 |
+
$totalTime += $time;
|
36 |
+
}
|
37 |
+
|
38 |
+
$html .= '<tr><th>Total time spent rendering uncached blocks:</th>'
|
39 |
+
. '<th>' . intval($totalTime*1000) . '</th></tr>';
|
40 |
+
$html .= '</tbody>';
|
41 |
+
$html .= '</table>';
|
42 |
+
|
43 |
+
return $html;
|
44 |
+
}
|
45 |
+
}
|
app/code/community/Made/Cache/Block/Varnish/Footer.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Block that echoes a resource whose purpose is to maintain the cookie for the
|
4 |
+
* client. This is needed in order to make sure that the cookie the browser
|
5 |
+
* sends actually corresponds to a session within Magento.
|
6 |
+
*
|
7 |
+
* @package Made_Cache
|
8 |
+
* @author info@madepeople.se
|
9 |
+
* @copyright Copyright (c) 2012 Made People AB. (http://www.madepeople.se/)
|
10 |
+
*/
|
11 |
+
class Made_Cache_Block_Varnish_Footer extends Mage_Core_Block_Abstract
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* Generate the script resource AJAX request. This could be a good place
|
15 |
+
* to fetch placeholders (such as recently viewed) in a general way,
|
16 |
+
* by adding product id data from a cookie to a placeholder element ID,
|
17 |
+
* for instance
|
18 |
+
*
|
19 |
+
* @return string
|
20 |
+
*/
|
21 |
+
protected function _toHtml()
|
22 |
+
{
|
23 |
+
$scriptUrl = Mage::getUrl('madecache/varnish/cookie');
|
24 |
+
|
25 |
+
$html = <<<EOF
|
26 |
+
<script type="text/javascript">
|
27 |
+
new Ajax.Request('$scriptUrl');
|
28 |
+
</script>
|
29 |
+
EOF;
|
30 |
+
return $html;
|
31 |
+
}
|
32 |
+
}
|
app/code/community/Made/Cache/Helper/Data.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Contains globally used helper functions
|
4 |
+
*
|
5 |
+
* @package Made_Cache
|
6 |
+
* @author info@madepeople.se
|
7 |
+
* @copyright Copyright (c) 2012 Made People AB. (http://www.madepeople.se/)
|
8 |
+
*/
|
9 |
+
class Made_Cache_Helper_Data extends Mage_Core_Helper_Abstract
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* Flattens array
|
13 |
+
*
|
14 |
+
* @param type $array
|
15 |
+
* @return string
|
16 |
+
*/
|
17 |
+
protected function _flattenArray($array)
|
18 |
+
{
|
19 |
+
$result = array();
|
20 |
+
foreach ($array as $key => $value) {
|
21 |
+
if (is_array($value)) {
|
22 |
+
$result = array_merge($result, $this->_flattenArray($value));
|
23 |
+
}
|
24 |
+
else {
|
25 |
+
$result[$key] = $value;
|
26 |
+
}
|
27 |
+
}
|
28 |
+
return $result;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Returns string usable as a cache key part, and takes different
|
33 |
+
* datatypes into concern
|
34 |
+
*
|
35 |
+
* @param mixed $value
|
36 |
+
* @return string
|
37 |
+
*/
|
38 |
+
public function paramValueToCacheKey($value)
|
39 |
+
{
|
40 |
+
if (is_array($value)) {
|
41 |
+
$value = implode('_', $this->_flattenArray($value));
|
42 |
+
} else if (is_object($value)) {
|
43 |
+
$newValue = '';
|
44 |
+
foreach ($value->getData() as $dataKey => $dataValue) {
|
45 |
+
$newValue = $dataKey . $dataValue;
|
46 |
+
}
|
47 |
+
$value = $newValue;
|
48 |
+
}
|
49 |
+
|
50 |
+
return $value;
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Used to determine if the current response has notification messages,
|
55 |
+
* because if it does, neither the block cache or varnish should keep it.
|
56 |
+
*
|
57 |
+
* @return boolean
|
58 |
+
*/
|
59 |
+
public function responseHasMessages()
|
60 |
+
{
|
61 |
+
$layout = Mage::app()->getFrontController()->getAction()
|
62 |
+
->getLayout();
|
63 |
+
|
64 |
+
foreach (array('global_messages', 'messages') as $blockName) {
|
65 |
+
if (($messagesBlock = $layout->getBlock($blockName)) !== false) {
|
66 |
+
if ($messagesBlock->getMessageCollection()->count()) {
|
67 |
+
return true;
|
68 |
+
}
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
return (bool)Mage::getModel('core/message_collection')
|
73 |
+
->count();
|
74 |
+
}
|
75 |
+
}
|
app/code/community/Made/Cache/Helper/Varnish.php
ADDED
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Contains functions related to Varnish
|
4 |
+
*
|
5 |
+
* Methods from https://www.varnish-software.com/static/book/Cache_invalidation.html
|
6 |
+
* are used in order to create a dynamic cache invalidation approach
|
7 |
+
*
|
8 |
+
* @package Made_Cache
|
9 |
+
* @author info@madepeople.se
|
10 |
+
* @copyright Copyright (c) 2012 Made People AB. (http://www.madepeople.se/)
|
11 |
+
*/
|
12 |
+
class Made_Cache_Helper_Varnish extends Mage_Core_Helper_Abstract
|
13 |
+
{
|
14 |
+
/**
|
15 |
+
* Determine if varnish is in front of Magento
|
16 |
+
*
|
17 |
+
* @return boolean
|
18 |
+
*/
|
19 |
+
public function isInFront()
|
20 |
+
{
|
21 |
+
return !!Mage::app()->getFrontController()
|
22 |
+
->getRequest()
|
23 |
+
->getHeader('X-Varnish');
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Determine if Varnish functions should be used
|
28 |
+
*
|
29 |
+
* @return boolean
|
30 |
+
*/
|
31 |
+
public function shouldUse()
|
32 |
+
{
|
33 |
+
return Mage::app()->useCache('varnish')
|
34 |
+
&& $this->isInFront();
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Returns an array of defined Varnish servers
|
39 |
+
* @return type
|
40 |
+
*/
|
41 |
+
public function getServers()
|
42 |
+
{
|
43 |
+
$serversConfig = explode('\n', Mage::getStoreConfig('cache/varnish/servers'));
|
44 |
+
$servers = array();
|
45 |
+
|
46 |
+
foreach ($serversConfig as $server) {
|
47 |
+
$server = trim($server);
|
48 |
+
|
49 |
+
// Skip new lines
|
50 |
+
if (empty($server)) {
|
51 |
+
continue;
|
52 |
+
}
|
53 |
+
|
54 |
+
$servers[] = $server;
|
55 |
+
}
|
56 |
+
|
57 |
+
return $servers;
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Flush varnish cache by banning all content
|
62 |
+
*/
|
63 |
+
public function flush()
|
64 |
+
{
|
65 |
+
return $this->_callVarnish('', 'FLUSH');
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Purge specific object in varnish cache
|
70 |
+
*
|
71 |
+
* @param string|array $urls
|
72 |
+
*/
|
73 |
+
public function purge($urls)
|
74 |
+
{
|
75 |
+
return $this->_callVarnish($urls, 'PURGE');
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Refresh specific content in varnish, might be more costly than PURGE
|
80 |
+
* because backend is called, but also doesn't invalidate cache if the
|
81 |
+
* backend is acting up
|
82 |
+
*
|
83 |
+
* @param string|array $urls
|
84 |
+
*/
|
85 |
+
public function refresh($urls)
|
86 |
+
{
|
87 |
+
return $this->_callVarnish($urls, 'REFRESH');
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Send a message to all defined Varnish servers
|
92 |
+
*
|
93 |
+
* Uses code from magneto-varnish.
|
94 |
+
*
|
95 |
+
* @see https://github.com/madalinoprea/magneto-varnish/blob/master/code/Varnish/Helper/Data.php#L48
|
96 |
+
* @param string|array $urls
|
97 |
+
* @param string $type
|
98 |
+
* @param array $headers
|
99 |
+
*/
|
100 |
+
protected function _callVarnish($urls, $type = 'PURGE', $headers = array())
|
101 |
+
{
|
102 |
+
$urls = (array)$urls;
|
103 |
+
$servers = $this->getServers();
|
104 |
+
|
105 |
+
// Init curl handler
|
106 |
+
$curlHandlers = array(); // keep references for clean up
|
107 |
+
$mh = curl_multi_init();
|
108 |
+
|
109 |
+
foreach ($servers as $varnishServer) {
|
110 |
+
foreach ($urls as $url) {
|
111 |
+
$varnishUrl = "http://" . $varnishServer . $url;
|
112 |
+
|
113 |
+
$ch = curl_init();
|
114 |
+
curl_setopt($ch, CURLOPT_URL, $varnishUrl);
|
115 |
+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type);
|
116 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
117 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
118 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
119 |
+
|
120 |
+
if (!empty($headers)) {
|
121 |
+
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
122 |
+
}
|
123 |
+
|
124 |
+
curl_multi_add_handle($mh, $ch);
|
125 |
+
$curlHandlers[] = $ch;
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
$active = null;
|
130 |
+
do {
|
131 |
+
curl_multi_exec($mh, $active);
|
132 |
+
} while ($active);
|
133 |
+
|
134 |
+
// Error handling and clean up
|
135 |
+
$errors = array();
|
136 |
+
foreach ($curlHandlers as $ch) {
|
137 |
+
$info = curl_getinfo($ch);
|
138 |
+
|
139 |
+
if (curl_errno($ch)) {
|
140 |
+
$errors[] = "Cannot purge url {$info['url']} due to error" . curl_error($ch);
|
141 |
+
} else if ($info['http_code'] != 200 && $info['http_code'] != 404) {
|
142 |
+
$errors[] = "Cannot purge url {$info['url']}, http code: {$info['http_code']}";
|
143 |
+
}
|
144 |
+
|
145 |
+
curl_multi_remove_handle($mh, $ch);
|
146 |
+
curl_close($ch);
|
147 |
+
}
|
148 |
+
curl_multi_close($mh);
|
149 |
+
|
150 |
+
return $errors;
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Retreive an ESI tag for the specified URL
|
155 |
+
*
|
156 |
+
* @param string $url
|
157 |
+
*/
|
158 |
+
public function getEsiTag($url)
|
159 |
+
{
|
160 |
+
$url = preg_replace('#^/#', '', $url);
|
161 |
+
return '<esi:include src="' . Mage::getUrl($url) . '"/>';
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Return a hash of the block layout XML in the current configuration,
|
166 |
+
* this is used to identify a unique rendering of the block as we cache
|
167 |
+
* all ESI requests
|
168 |
+
*
|
169 |
+
* @param Mage_Core_Block_Abstract $block
|
170 |
+
*/
|
171 |
+
public function getLayoutHash(Mage_Core_Block_Abstract $block)
|
172 |
+
{
|
173 |
+
$xml = $block->getLayout()->getNode();
|
174 |
+
$doc = new DOMDocument;
|
175 |
+
$doc->loadXML($xml->asXML());
|
176 |
+
$xpath = new DOMXpath($doc);
|
177 |
+
$nodeList = $xpath->query("//block[@name='".$block->getNameInLayout()."']");
|
178 |
+
return sha1($doc->saveXML($nodeList->item(0)));
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Helper function that purges the user session cache for cached ESI
|
183 |
+
* blocks
|
184 |
+
*/
|
185 |
+
public function purgeUserCache()
|
186 |
+
{
|
187 |
+
$sessionId = Mage::getSingleton('core/session')->getSessionId();
|
188 |
+
if (!empty($sessionId)) {
|
189 |
+
$this->_callVarnish('/', 'BAN', array('X-Ban-String: req.url ~ madecache/varnish/(esi|messages) && req.http.X-Session-UUID == ' . $sessionId));
|
190 |
+
}
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Retrieve the TTL for the current request
|
195 |
+
*
|
196 |
+
* @param type $request
|
197 |
+
*/
|
198 |
+
public function getRequestTtl($request)
|
199 |
+
{
|
200 |
+
if ($request->isPost()) {
|
201 |
+
// Never cache POST
|
202 |
+
return null;
|
203 |
+
}
|
204 |
+
|
205 |
+
$noCacheRoutes = Mage::getStoreConfig('cache/varnish/nocache_routes');
|
206 |
+
|
207 |
+
if ($this->_matchRoutesAgainstRequest($noCacheRoutes, $request)
|
208 |
+
|| $this->_matchRoutesAgainstRequest('madecache/varnish/cookie', $request)) {
|
209 |
+
return null;
|
210 |
+
}
|
211 |
+
|
212 |
+
// Messages should only be cached if they are empty
|
213 |
+
if ($this->_matchRoutesAgainstRequest('madecache/varnish/messages', $request)
|
214 |
+
&& Mage::helper('cache')->responseHasMessages()) {
|
215 |
+
return null;
|
216 |
+
}
|
217 |
+
|
218 |
+
return Mage::getStoreConfig('cache/varnish/ttl');
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Match routes against the current request for cache exclusion
|
223 |
+
*
|
224 |
+
* @param array|string $routes
|
225 |
+
* @param object $request
|
226 |
+
* @return boolean
|
227 |
+
*/
|
228 |
+
protected function _matchRoutesAgainstRequest($routes, $request)
|
229 |
+
{
|
230 |
+
if (!is_array($routes)) {
|
231 |
+
$routes = explode("\n", $routes);
|
232 |
+
}
|
233 |
+
|
234 |
+
foreach ($routes as $key => $handle) {
|
235 |
+
if (($handle = trim($handle)) === '') {
|
236 |
+
continue;
|
237 |
+
}
|
238 |
+
$routes[$key] = $handle;
|
239 |
+
}
|
240 |
+
|
241 |
+
if (in_array($request->getModuleName(), $routes)
|
242 |
+
|| in_array($request->getModuleName() . '/' . $request->getControllerName(), $routes)
|
243 |
+
|| in_array($request->getModuleName() . '/' . $request->getControllerName() . '/' . $request->getActionName(), $routes))
|
244 |
+
{
|
245 |
+
return true;
|
246 |
+
}
|
247 |
+
|
248 |
+
return false;
|
249 |
+
}
|
250 |
+
|
251 |
+
}
|
app/code/community/Made/Cache/Model/Layout.php
CHANGED
@@ -29,7 +29,7 @@ class Made_Cache_Model_Layout extends Mage_Core_Model_Layout
|
|
29 |
* @var int
|
30 |
*/
|
31 |
const DEFAULT_CACHE_LIFETIME = 9999999999;
|
32 |
-
|
33 |
/**
|
34 |
* Take cache/noache/ESI tags into concern for block rendering
|
35 |
*
|
@@ -39,6 +39,30 @@ class Made_Cache_Model_Layout extends Mage_Core_Model_Layout
|
|
39 |
{
|
40 |
parent::generateXml();
|
41 |
$xml = $this->getNode();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
|
43 |
// Find blocks to cache
|
44 |
$cacheList = $xml->xpath("//cache/*");
|
@@ -72,7 +96,19 @@ class Made_Cache_Model_Layout extends Mage_Core_Model_Layout
|
|
72 |
$this->_esiBlocks[$blockName] = array();
|
73 |
}
|
74 |
}
|
75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
return $this;
|
77 |
}
|
78 |
|
@@ -108,16 +144,17 @@ class Made_Cache_Model_Layout extends Mage_Core_Model_Layout
|
|
108 |
} else {
|
109 |
$paramKeys = array();
|
110 |
foreach (Mage::app()->getRequest()->getParams() as $key => $value) {
|
111 |
-
if (is_array($value)) {
|
112 |
-
$value = implode('_', $value);
|
113 |
-
} elseif (is_object($value)) {
|
114 |
-
$newValue = '';
|
115 |
-
foreach ($value->getData() as $dataKey => $dataValue) {
|
116 |
-
$newValue = $dataKey . $dataValue;
|
117 |
-
}
|
118 |
-
$value = $newValue;
|
119 |
-
}
|
120 |
|
|
|
121 |
$paramKeys[] = $key . $value;
|
122 |
}
|
123 |
|
29 |
* @var int
|
30 |
*/
|
31 |
const DEFAULT_CACHE_LIFETIME = 9999999999;
|
32 |
+
|
33 |
/**
|
34 |
* Take cache/noache/ESI tags into concern for block rendering
|
35 |
*
|
39 |
{
|
40 |
parent::generateXml();
|
41 |
$xml = $this->getNode();
|
42 |
+
$doc = new DOMDocument;
|
43 |
+
$doc->loadXML($xml->asXML());
|
44 |
+
$xpath = new DOMXpath($doc);
|
45 |
+
|
46 |
+
// Aggregate references into one layout tree
|
47 |
+
$references = $xpath->query("//reference");
|
48 |
+
foreach ($references as $node) {
|
49 |
+
$blockName = $node->getAttribute('name');
|
50 |
+
$nodeList = $xpath->query("//block[@name='".$blockName."']");
|
51 |
+
if ($nodeList->length) {
|
52 |
+
$blockNode = $nodeList->item(0);
|
53 |
+
if ($node->hasChildNodes()) {
|
54 |
+
$childNodes = $xpath->query('*', $node);
|
55 |
+
foreach ($childNodes as $child) {
|
56 |
+
if ($child->nodeType == XML_ELEMENT_NODE) {
|
57 |
+
$blockNode->appendChild($child);
|
58 |
+
}
|
59 |
+
}
|
60 |
+
}
|
61 |
+
}
|
62 |
+
$node->parentNode->removeChild($node);
|
63 |
+
}
|
64 |
+
$xml = new Mage_Core_Model_Layout_Element($doc->saveXML());
|
65 |
+
$this->setXml($xml);
|
66 |
|
67 |
// Find blocks to cache
|
68 |
$cacheList = $xml->xpath("//cache/*");
|
96 |
$this->_esiBlocks[$blockName] = array();
|
97 |
}
|
98 |
}
|
99 |
+
|
100 |
+
// Find eventual noesi tags
|
101 |
+
$noEsiList = $xml->xpath("//noesi/*");
|
102 |
+
if (count($noEsiList)) {
|
103 |
+
foreach ($noEsiList as $node) {
|
104 |
+
$blockName = trim((string)$node);
|
105 |
+
// Names are unique, an array could hold future settings
|
106 |
+
if (isset($this->_esiBlocks[$blockName])) {
|
107 |
+
unset($this->_esiBlocks[$blockName]);
|
108 |
+
}
|
109 |
+
}
|
110 |
+
}
|
111 |
+
|
112 |
return $this;
|
113 |
}
|
114 |
|
144 |
} else {
|
145 |
$paramKeys = array();
|
146 |
foreach (Mage::app()->getRequest()->getParams() as $key => $value) {
|
147 |
+
// if (is_array($value)) {
|
148 |
+
// $value = implode('_', $value);
|
149 |
+
// } elseif (is_object($value)) {
|
150 |
+
// $newValue = '';
|
151 |
+
// foreach ($value->getData() as $dataKey => $dataValue) {
|
152 |
+
// $newValue = $dataKey . $dataValue;
|
153 |
+
// }
|
154 |
+
// $value = $newValue;
|
155 |
+
// }
|
156 |
|
157 |
+
$value = Mage::helper('cache')->paramValueToCacheKey($value);
|
158 |
$paramKeys[] = $key . $value;
|
159 |
}
|
160 |
|
app/code/community/Made/Cache/Model/Observer.php
CHANGED
@@ -8,10 +8,12 @@
|
|
8 |
*/
|
9 |
class Made_Cache_Model_Observer
|
10 |
{
|
|
|
|
|
11 |
/**
|
12 |
* Observer that injects cache values into specific blocks, we want
|
13 |
* to do it like this instead of block rewrites to prevent other
|
14 |
-
* third-party modules
|
15 |
*
|
16 |
* @param Varien_Event_Observer $observer
|
17 |
*/
|
@@ -22,12 +24,21 @@ class Made_Cache_Model_Observer
|
|
22 |
// null lifetime means don't use cache
|
23 |
return;
|
24 |
}
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
switch (true) {
|
27 |
case $block instanceof Mage_Catalog_Block_Product_View:
|
28 |
Mage::getSingleton('cache/observer_catalog')
|
29 |
->applyProductView($block);
|
30 |
break;
|
|
|
|
|
|
|
|
|
31 |
case $block instanceof Mage_Catalog_Block_Product_List:
|
32 |
Mage::getSingleton('cache/observer_catalog')
|
33 |
->applyProductList($block);
|
@@ -46,6 +57,10 @@ class Made_Cache_Model_Observer
|
|
46 |
->applyCartSidebar($block);
|
47 |
break;
|
48 |
}
|
|
|
|
|
|
|
|
|
49 |
}
|
50 |
|
51 |
/**
|
@@ -63,42 +78,6 @@ class Made_Cache_Model_Observer
|
|
63 |
}
|
64 |
}
|
65 |
|
66 |
-
/**
|
67 |
-
* ESI tags for Varnish, needs the block to have the attribute esi === 1
|
68 |
-
* as well as Varnish configured with for instance Phoenix_VarnishCache
|
69 |
-
*
|
70 |
-
* @param Varien_Event_Observer $observer
|
71 |
-
*/
|
72 |
-
public function addEsiTag(Varien_Event_Observer $observer)
|
73 |
-
{
|
74 |
-
$block = $observer->getEvent()->getBlock();
|
75 |
-
|
76 |
-
// Only return an ESI tag if varnish is in front
|
77 |
-
if (!$block->getRequest()->getHeader('X-Varnish')) {
|
78 |
-
return;
|
79 |
-
}
|
80 |
-
|
81 |
-
if ($block->getData('esi')) {
|
82 |
-
$layoutHandles = $block->getLayout()->getUpdate()
|
83 |
-
->getHandles();
|
84 |
-
|
85 |
-
$esiPath = 'madecache/varnish/esi'
|
86 |
-
. '/block/' . base64_encode($block->getNameInLayout())
|
87 |
-
. '/layout/' . base64_encode(join(',', $layoutHandles))
|
88 |
-
;
|
89 |
-
|
90 |
-
if (($product = Mage::registry('product')) !== null) {
|
91 |
-
$esiPath .= '/misc/' . base64_encode(serialize(array(
|
92 |
-
'product' => $product->getId()
|
93 |
-
)));
|
94 |
-
}
|
95 |
-
|
96 |
-
$html = '<esi:include src="' . Mage::getUrl($esiPath) . '"/>';
|
97 |
-
$transport = $observer->getEvent()->getTransport();
|
98 |
-
$transport->setHtml($html);
|
99 |
-
}
|
100 |
-
}
|
101 |
-
|
102 |
/**
|
103 |
* CatalogRule invalidates cache on product save, so this must be cleaned
|
104 |
*
|
@@ -123,7 +102,7 @@ class Made_Cache_Model_Observer
|
|
123 |
*/
|
124 |
public function clearQuoteCache(Varien_Event_Observer $observer)
|
125 |
{
|
126 |
-
// Only
|
127 |
$object = $observer->getEvent()->getQuote();
|
128 |
Mage::app()->cleanCache(array('SALES_QUOTE_' . $object->getId()));
|
129 |
}
|
@@ -132,7 +111,7 @@ class Made_Cache_Model_Observer
|
|
132 |
* Unset the uenc param for redirection of blocks that have cached links.
|
133 |
* If we don't do this, links redirects to where user X came from when
|
134 |
* the block was cached. This also means that cached return links for
|
135 |
-
* ESI blocks return a visitor to the ESI
|
136 |
*
|
137 |
* @param Varien_Event_Observer $observer
|
138 |
*/
|
@@ -144,7 +123,60 @@ class Made_Cache_Model_Observer
|
|
144 |
// To this day, the only used encoding type is PARAM_NAME_URL_ENCODED
|
145 |
$key = Mage_Core_Controller_Varien_Action::PARAM_NAME_URL_ENCODED;
|
146 |
if (($param = $request->getParam($key)) !== null) {
|
147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
148 |
}
|
149 |
}
|
150 |
}
|
8 |
*/
|
9 |
class Made_Cache_Model_Observer
|
10 |
{
|
11 |
+
protected $_shouldProfile = null;
|
12 |
+
|
13 |
/**
|
14 |
* Observer that injects cache values into specific blocks, we want
|
15 |
* to do it like this instead of block rewrites to prevent other
|
16 |
+
* third-party modules from breaking
|
17 |
*
|
18 |
* @param Varien_Event_Observer $observer
|
19 |
*/
|
24 |
// null lifetime means don't use cache
|
25 |
return;
|
26 |
}
|
27 |
+
|
28 |
+
// Allow developers to manipulate block cache data
|
29 |
+
Mage::dispatchEvent('made_cache_setup_block_before', array(
|
30 |
+
'block' => $block
|
31 |
+
));
|
32 |
|
33 |
switch (true) {
|
34 |
case $block instanceof Mage_Catalog_Block_Product_View:
|
35 |
Mage::getSingleton('cache/observer_catalog')
|
36 |
->applyProductView($block);
|
37 |
break;
|
38 |
+
case $block instanceof Mage_Catalog_Block_Category_View:
|
39 |
+
Mage::getSingleton('cache/observer_catalog')
|
40 |
+
->applyCategoryView($block);
|
41 |
+
break;
|
42 |
case $block instanceof Mage_Catalog_Block_Product_List:
|
43 |
Mage::getSingleton('cache/observer_catalog')
|
44 |
->applyProductList($block);
|
57 |
->applyCartSidebar($block);
|
58 |
break;
|
59 |
}
|
60 |
+
|
61 |
+
Mage::dispatchEvent('made_cache_setup_block_after', array(
|
62 |
+
'block' => $block
|
63 |
+
));
|
64 |
}
|
65 |
|
66 |
/**
|
78 |
}
|
79 |
}
|
80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
/**
|
82 |
* CatalogRule invalidates cache on product save, so this must be cleaned
|
83 |
*
|
102 |
*/
|
103 |
public function clearQuoteCache(Varien_Event_Observer $observer)
|
104 |
{
|
105 |
+
// Only runs when there is an active quote in the session
|
106 |
$object = $observer->getEvent()->getQuote();
|
107 |
Mage::app()->cleanCache(array('SALES_QUOTE_' . $object->getId()));
|
108 |
}
|
111 |
* Unset the uenc param for redirection of blocks that have cached links.
|
112 |
* If we don't do this, links redirects to where user X came from when
|
113 |
* the block was cached. This also means that cached return links for
|
114 |
+
* ESI blocks return a visitor to the ESI URL, and we can't have that.
|
115 |
*
|
116 |
* @param Varien_Event_Observer $observer
|
117 |
*/
|
123 |
// To this day, the only used encoding type is PARAM_NAME_URL_ENCODED
|
124 |
$key = Mage_Core_Controller_Varien_Action::PARAM_NAME_URL_ENCODED;
|
125 |
if (($param = $request->getParam($key)) !== null) {
|
126 |
+
// Always remove redirections to Varnish actions
|
127 |
+
$paramValue = base64_decode($param);
|
128 |
+
if (strstr($paramValue, '/madecache/varnish/') ||
|
129 |
+
Mage::getStoreConfig('cache/general/remove_redirect_param')) {
|
130 |
+
$request->setParam($key, null);
|
131 |
+
}
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Private getter to determine if the profiler should be enabled
|
137 |
+
*
|
138 |
+
* @return bool
|
139 |
+
*/
|
140 |
+
protected function _getShouldProfile()
|
141 |
+
{
|
142 |
+
if (is_null($this->_shouldProfile)) {
|
143 |
+
$this->_shouldProfile = (bool)Mage::getStoreConfig('cache/general/enable_profiler');
|
144 |
+
}
|
145 |
+
|
146 |
+
return $this->_shouldProfile;
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Start counting the time of rendering an uncached block
|
151 |
+
*
|
152 |
+
* @param Varien_Event_Observer $observer
|
153 |
+
*/
|
154 |
+
public function profilerStart(Varien_Event_Observer $observer)
|
155 |
+
{
|
156 |
+
$shouldProfile = $this->_getShouldProfile();
|
157 |
+
if ($shouldProfile === true) {
|
158 |
+
$blockName = $observer->getEvent()
|
159 |
+
->getBlock()
|
160 |
+
->getNameInLayout();
|
161 |
+
|
162 |
+
Made_Cache_Model_Profiler::start($blockName);
|
163 |
+
}
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* Stop counting the time of rendering an uncached block
|
168 |
+
*
|
169 |
+
* @param Varien_Event_Observer $observer
|
170 |
+
*/
|
171 |
+
public function profilerEnd(Varien_Event_Observer $observer)
|
172 |
+
{
|
173 |
+
$shouldProfile = $this->_getShouldProfile();
|
174 |
+
if ($shouldProfile === true) {
|
175 |
+
$blockName = $observer->getEvent()
|
176 |
+
->getBlock()
|
177 |
+
->getNameInLayout();
|
178 |
+
|
179 |
+
Made_Cache_Model_Profiler::end($blockName);
|
180 |
}
|
181 |
}
|
182 |
}
|
app/code/community/Made/Cache/Model/Observer/Abstract.php
CHANGED
@@ -33,6 +33,8 @@ abstract class Made_Cache_Model_Observer_Abstract
|
|
33 |
$keys = array();
|
34 |
}
|
35 |
$keys[] = $block->getLayout()->getUpdate()->getCacheId();
|
|
|
|
|
36 |
return $keys;
|
37 |
}
|
38 |
}
|
33 |
$keys = array();
|
34 |
}
|
35 |
$keys[] = $block->getLayout()->getUpdate()->getCacheId();
|
36 |
+
$keys[] = 'SSL_' . intval(!empty($_SERVER['HTTPS']) &&
|
37 |
+
$_SERVER['HTTPS'] !== 'off') . '_';
|
38 |
return $keys;
|
39 |
}
|
40 |
}
|
app/code/community/Made/Cache/Model/Observer/Catalog.php
CHANGED
@@ -17,11 +17,9 @@ class Made_Cache_Model_Observer_Catalog
|
|
17 |
public function applyProductView(Mage_Catalog_Block_Product_View $block)
|
18 |
{
|
19 |
// The "messages" block is session-dependent, don't cache
|
20 |
-
if ((
|
21 |
-
|
22 |
-
|
23 |
-
return;
|
24 |
-
}
|
25 |
}
|
26 |
|
27 |
// Cart stuff is session-dependent
|
@@ -72,6 +70,22 @@ class Made_Cache_Model_Observer_Catalog
|
|
72 |
;
|
73 |
}
|
74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
/**
|
76 |
* Product list cache, needs to clear on displayed products
|
77 |
*
|
@@ -80,11 +94,9 @@ class Made_Cache_Model_Observer_Catalog
|
|
80 |
public function applyProductList(Mage_Catalog_Block_Product_List $block)
|
81 |
{
|
82 |
// The "messages" block is session-dependent, don't cache
|
83 |
-
if ((
|
84 |
-
|
85 |
-
|
86 |
-
return;
|
87 |
-
}
|
88 |
}
|
89 |
|
90 |
// Set cache tags
|
@@ -94,7 +106,7 @@ class Made_Cache_Model_Observer_Catalog
|
|
94 |
|
95 |
// The toolbar needs to apply sort order etc
|
96 |
$productCollection = $block->getLoadedProductCollection();
|
97 |
-
$_toolbar =
|
98 |
$_toolbar->setCollection($productCollection);
|
99 |
|
100 |
foreach ($productCollection as $_product) {
|
@@ -110,12 +122,10 @@ class Made_Cache_Model_Observer_Catalog
|
|
110 |
$_categoryId = $this->_getCategoryIdForProductList($block);
|
111 |
|
112 |
foreach (Mage::app()->getRequest()->getParams() as $key => $value) {
|
113 |
-
|
114 |
-
$value = implode('_', $value);
|
115 |
-
}
|
116 |
$keys[] = $key . '_' . $value;
|
117 |
}
|
118 |
-
|
119 |
$keys = array_merge($keys, array(
|
120 |
$_categoryId,
|
121 |
$_toolbar->getCurrentOrder(),
|
17 |
public function applyProductView(Mage_Catalog_Block_Product_View $block)
|
18 |
{
|
19 |
// The "messages" block is session-dependent, don't cache
|
20 |
+
if (Mage::helper('cache')->responseHasMessages()) {
|
21 |
+
$block->setData('cache_lifetime', null);
|
22 |
+
return;
|
|
|
|
|
23 |
}
|
24 |
|
25 |
// Cart stuff is session-dependent
|
70 |
;
|
71 |
}
|
72 |
|
73 |
+
/**
|
74 |
+
* Make sure that the category view doesn't cache when there are
|
75 |
+
* messages in the session
|
76 |
+
*
|
77 |
+
* @param Mage_Catalog_Block_Category_View $block
|
78 |
+
* @return type
|
79 |
+
*/
|
80 |
+
public function applyCategoryView(Mage_Catalog_Block_Category_View $block)
|
81 |
+
{
|
82 |
+
// The "messages" block is session-dependent, don't cache
|
83 |
+
if (Mage::helper('cache')->responseHasMessages()) {
|
84 |
+
$block->setData('cache_lifetime', null);
|
85 |
+
return;
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
/**
|
90 |
* Product list cache, needs to clear on displayed products
|
91 |
*
|
94 |
public function applyProductList(Mage_Catalog_Block_Product_List $block)
|
95 |
{
|
96 |
// The "messages" block is session-dependent, don't cache
|
97 |
+
if (Mage::helper('cache')->responseHasMessages()) {
|
98 |
+
$block->setData('cache_lifetime', null);
|
99 |
+
return;
|
|
|
|
|
100 |
}
|
101 |
|
102 |
// Set cache tags
|
106 |
|
107 |
// The toolbar needs to apply sort order etc
|
108 |
$productCollection = $block->getLoadedProductCollection();
|
109 |
+
$_toolbar = $block->getToolbarBlock();
|
110 |
$_toolbar->setCollection($productCollection);
|
111 |
|
112 |
foreach ($productCollection as $_product) {
|
122 |
$_categoryId = $this->_getCategoryIdForProductList($block);
|
123 |
|
124 |
foreach (Mage::app()->getRequest()->getParams() as $key => $value) {
|
125 |
+
$value = Mage::helper('cache')->paramValueToCacheKey($value);
|
|
|
|
|
126 |
$keys[] = $key . '_' . $value;
|
127 |
}
|
128 |
+
|
129 |
$keys = array_merge($keys, array(
|
130 |
$_categoryId,
|
131 |
$_toolbar->getCurrentOrder(),
|
app/code/community/Made/Cache/Model/Observer/Checkout.php
CHANGED
@@ -39,13 +39,9 @@ class Made_Cache_Model_Observer_Checkout
|
|
39 |
$block->setData('cache_tags', $tags);
|
40 |
|
41 |
// Set cache keys
|
42 |
-
$keys =
|
43 |
-
|
44 |
-
|
45 |
-
$block->getTemplateFile(),
|
46 |
-
'template' => $block->getTemplate(),
|
47 |
-
$this->_getQuoteId($block)
|
48 |
-
);
|
49 |
$block->setData('cache_key', $this->_getCacheKey($keys));
|
50 |
}
|
51 |
}
|
39 |
$block->setData('cache_tags', $tags);
|
40 |
|
41 |
// Set cache keys
|
42 |
+
$keys = $this->_getBasicKeys($block);
|
43 |
+
$keys[] = $this->_getQuoteId($block);
|
44 |
+
|
|
|
|
|
|
|
|
|
45 |
$block->setData('cache_key', $this->_getCacheKey($keys));
|
46 |
}
|
47 |
}
|
app/code/community/Made/Cache/Model/Observer/Cms.php
CHANGED
@@ -17,11 +17,9 @@ class Made_Cache_Model_Observer_Cms
|
|
17 |
public function applyCmsPage(Mage_Cms_Block_Page $block)
|
18 |
{
|
19 |
// The "messages" block is session-dependent, don't cache
|
20 |
-
if ((
|
21 |
-
|
22 |
-
|
23 |
-
return;
|
24 |
-
}
|
25 |
}
|
26 |
|
27 |
// Set cache tags
|
@@ -46,11 +44,9 @@ class Made_Cache_Model_Observer_Cms
|
|
46 |
public function applyCmsBlock($block)
|
47 |
{
|
48 |
// The "messages" block is session-dependent, don't cache
|
49 |
-
if ((
|
50 |
-
|
51 |
-
|
52 |
-
return;
|
53 |
-
}
|
54 |
}
|
55 |
|
56 |
// Set cache tags
|
17 |
public function applyCmsPage(Mage_Cms_Block_Page $block)
|
18 |
{
|
19 |
// The "messages" block is session-dependent, don't cache
|
20 |
+
if (Mage::helper('cache')->responseHasMessages()) {
|
21 |
+
$block->setData('cache_lifetime', null);
|
22 |
+
return;
|
|
|
|
|
23 |
}
|
24 |
|
25 |
// Set cache tags
|
44 |
public function applyCmsBlock($block)
|
45 |
{
|
46 |
// The "messages" block is session-dependent, don't cache
|
47 |
+
if (Mage::helper('cache')->responseHasMessages()) {
|
48 |
+
$block->setData('cache_lifetime', null);
|
49 |
+
return;
|
|
|
|
|
50 |
}
|
51 |
|
52 |
// Set cache tags
|
app/code/community/Made/Cache/Model/Profiler.php
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Model for keeping track of time spent rendering uncached blocks
|
4 |
+
*
|
5 |
+
* @package Made_Cache
|
6 |
+
* @author info@madepeople.se
|
7 |
+
* @copyright Copyright (c) 2012 Made People AB. (http://www.madepeople.se/)
|
8 |
+
*/
|
9 |
+
class Made_Cache_Model_Profiler
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* Holds both calculated and raw profiler data
|
13 |
+
*
|
14 |
+
* @var array
|
15 |
+
*/
|
16 |
+
private static $_profilerData = array(
|
17 |
+
'raw' => array(),
|
18 |
+
'calculated' => array()
|
19 |
+
);
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Starting profiler timestamp
|
23 |
+
*
|
24 |
+
* @param string $key
|
25 |
+
* @return void
|
26 |
+
*/
|
27 |
+
public static function start($key)
|
28 |
+
{
|
29 |
+
if (empty($key)) {
|
30 |
+
return;
|
31 |
+
}
|
32 |
+
|
33 |
+
self::$_profilerData['raw'][$key]['start'] = microtime(true);
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Ending profiler timestamp
|
38 |
+
*
|
39 |
+
* @param string $key
|
40 |
+
* @return void
|
41 |
+
*/
|
42 |
+
public static function end($key)
|
43 |
+
{
|
44 |
+
if (empty($key)) {
|
45 |
+
return;
|
46 |
+
}
|
47 |
+
|
48 |
+
self::$_profilerData['raw'][$key]['end'] = microtime(true);
|
49 |
+
self::$_profilerData['calculated'][$key] =
|
50 |
+
self::$_profilerData['raw'][$key]['end'] -
|
51 |
+
self::$_profilerData['raw'][$key]['start'];
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Return sorted profiler data, longest time first
|
56 |
+
*
|
57 |
+
* @return array
|
58 |
+
*/
|
59 |
+
public static function getProfilerData()
|
60 |
+
{
|
61 |
+
$profilerData = self::$_profilerData['calculated'];
|
62 |
+
arsort($profilerData);
|
63 |
+
return $profilerData;
|
64 |
+
}
|
65 |
+
}
|
app/code/community/Made/Cache/Model/VarnishObserver.php
ADDED
@@ -0,0 +1,304 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Manage tag-specific cache cleaning
|
4 |
+
*
|
5 |
+
* @package Made_Cache
|
6 |
+
* @author info@madepeople.se
|
7 |
+
* @copyright Copyright (c) 2012 Made People AB. (http://www.madepeople.se/)
|
8 |
+
*/
|
9 |
+
class Made_Cache_Model_VarnishObserver
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* Simple, default is 0 expiry meaning no caching. For every action that
|
13 |
+
* requires caching we add it explicitly. Static content is not within
|
14 |
+
* this scope.
|
15 |
+
*
|
16 |
+
* @param Varien_Event_Observer $observer
|
17 |
+
*/
|
18 |
+
public function initializeResponseHeaders(Varien_Event_Observer $observer)
|
19 |
+
{
|
20 |
+
// Only manipulate headers if Varnish is in front
|
21 |
+
if (!Mage::helper('cache/varnish')->shouldUse()) {
|
22 |
+
return;
|
23 |
+
}
|
24 |
+
|
25 |
+
$response = $observer->getEvent()
|
26 |
+
->getControllerAction()
|
27 |
+
->getResponse();
|
28 |
+
|
29 |
+
if (Mage::getStoreConfig('cache/varnish/debug')) {
|
30 |
+
$response->setHeader('X-Made-Cache-Debug', 1);
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Set TTL for varnish. Since we use ESI we only need to offer the
|
36 |
+
* simple possibility to blacklist per request route.
|
37 |
+
*
|
38 |
+
* @param Varien_Event_Observer $observer
|
39 |
+
*/
|
40 |
+
public function setVarnishCacheHeaders(Varien_Event_Observer $observer)
|
41 |
+
{
|
42 |
+
// Only manipulate headers if Varnish is in front or if there isn't
|
43 |
+
// a messages block in the layout
|
44 |
+
if (!Mage::helper('cache/varnish')->shouldUse()) {
|
45 |
+
return;
|
46 |
+
}
|
47 |
+
|
48 |
+
$controller = $observer->getEvent()->getControllerAction();
|
49 |
+
$ttl = Mage::helper('cache/varnish')->getRequestTtl($controller->getRequest());
|
50 |
+
if (empty($ttl)) {
|
51 |
+
return;
|
52 |
+
}
|
53 |
+
|
54 |
+
$response = $controller->getResponse();
|
55 |
+
$response->setHeader('X-Made-Cache-Ttl', $ttl, true);
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Add 'varnish_enabled' to the list of layout handles, so developers
|
60 |
+
* can target layout XML entries for when varnish is in front
|
61 |
+
*
|
62 |
+
* @param Varien_Event_Observer $observer
|
63 |
+
* @return void
|
64 |
+
*/
|
65 |
+
public function addLayoutHandle(Varien_Event_Observer $observer)
|
66 |
+
{
|
67 |
+
if (!Mage::helper('cache/varnish')->shouldUse()) {
|
68 |
+
return;
|
69 |
+
}
|
70 |
+
|
71 |
+
$observer->getEvent()->getControllerAction()
|
72 |
+
->getLayout()
|
73 |
+
->getUpdate()
|
74 |
+
->addHandle('varnish_enabled');
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* ESI tags for Varnish, needs the block to have the attribute esi === 1
|
79 |
+
* as well as Varnish configured with for instance Phoenix_VarnishCache
|
80 |
+
*
|
81 |
+
* @param Varien_Event_Observer $observer
|
82 |
+
*/
|
83 |
+
public function addEsiTag(Varien_Event_Observer $observer)
|
84 |
+
{
|
85 |
+
if (!Mage::helper('cache/varnish')->shouldUse()) {
|
86 |
+
return;
|
87 |
+
}
|
88 |
+
|
89 |
+
$block = $observer->getEvent()->getBlock();
|
90 |
+
|
91 |
+
if ($block->getData('esi')) {
|
92 |
+
$layoutHandles = $block->getLayout()->getUpdate()
|
93 |
+
->getHandles();
|
94 |
+
|
95 |
+
$esiPath = 'madecache/varnish/esi'
|
96 |
+
. '/hash/' . Mage::helper('cache/varnish')->getLayoutHash($block)
|
97 |
+
. '/block/' . base64_encode($block->getNameInLayout())
|
98 |
+
. '/layout/' . base64_encode(join(',', $layoutHandles))
|
99 |
+
;
|
100 |
+
|
101 |
+
if (($product = Mage::registry('product')) !== null) {
|
102 |
+
$esiPath .= '/misc/' . base64_encode(serialize(array(
|
103 |
+
'product' => $product->getId()
|
104 |
+
)));
|
105 |
+
}
|
106 |
+
|
107 |
+
$html = Mage::helper('cache/varnish')->getEsiTag($esiPath);
|
108 |
+
$transport = $observer->getEvent()->getTransport();
|
109 |
+
$transport->setHtml($html);
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Clear user-specific cache when at a non-cachable request because these
|
115 |
+
* are what modify the session
|
116 |
+
*
|
117 |
+
* @param Varien_Event_Observer $observer
|
118 |
+
*/
|
119 |
+
public function purgeUserCache(Varien_Event_Observer $observer)
|
120 |
+
{
|
121 |
+
// Only manipulate headers if Varnish is in front or if there isn't
|
122 |
+
// a messages block in the layout
|
123 |
+
if (!Mage::helper('cache/varnish')->shouldUse()) {
|
124 |
+
return;
|
125 |
+
}
|
126 |
+
|
127 |
+
$controller = $observer->getEvent()->getControllerAction();
|
128 |
+
$request = $controller->getRequest();
|
129 |
+
$ttl = Mage::helper('cache/varnish')->getRequestTtl($request);
|
130 |
+
if (!empty($ttl)) {
|
131 |
+
// Only purge for routes that don't cache
|
132 |
+
return;
|
133 |
+
}
|
134 |
+
|
135 |
+
if ($request->getModuleName() === 'madecache'
|
136 |
+
&& $request->getControllerName() === 'varnish') {
|
137 |
+
// It's stupid for ESI requests to clear themselves
|
138 |
+
return;
|
139 |
+
}
|
140 |
+
|
141 |
+
Mage::helper('cache/varnish')->purgeUserCache();
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Purge cache in Varnish including entity cache such as products,
|
146 |
+
* categories and CMS pages by doing lookups in the rewrite table
|
147 |
+
*
|
148 |
+
* Uses code from magneto-varnish.
|
149 |
+
*
|
150 |
+
* @see https://github.com/madalinoprea/magneto-varnish/blob/master/code/Varnish/Model/Observer.php#L65
|
151 |
+
* @param Varien_Event_Observer $observer
|
152 |
+
*/
|
153 |
+
public function purge(Varien_Event_Observer $observer)
|
154 |
+
{
|
155 |
+
if (!Mage::helper('cache/varnish')->shouldUse()) {
|
156 |
+
return;
|
157 |
+
}
|
158 |
+
|
159 |
+
$tags = $observer->getTags();
|
160 |
+
if (empty($tags)) {
|
161 |
+
$errors = Mage::helper('cache/varnish')->flush();
|
162 |
+
if (!empty($errors)) {
|
163 |
+
Mage::getSingleton('adminhtml/session')->addError("Varnish Purge failed");
|
164 |
+
} else {
|
165 |
+
Mage::getSingleton('adminhtml/session')->addSuccess("The Varnish cache storage has been flushed.");
|
166 |
+
}
|
167 |
+
return;
|
168 |
+
}
|
169 |
+
|
170 |
+
$urls = array();
|
171 |
+
|
172 |
+
// Compute the urls for affected entities
|
173 |
+
foreach ((array)$tags as $tag) {
|
174 |
+
$tag_fields = explode('_', $tag);
|
175 |
+
if (count($tag_fields) === 3) {
|
176 |
+
if ($tag_fields[1] == 'product') {
|
177 |
+
// Get urls for product
|
178 |
+
$product = Mage::getModel('catalog/product')->load($tag_fields[2]);
|
179 |
+
$urls = array_merge($urls, $this->_getUrlsForProduct($product));
|
180 |
+
} elseif ($tag_fields[1] == 'category') {
|
181 |
+
$category = Mage::getModel('catalog/category')->load($tag_fields[2]);
|
182 |
+
$category_urls = $this->_getUrlsForCategory($category);
|
183 |
+
$urls = array_merge($urls, $category_urls);
|
184 |
+
} elseif ($tag_fields[1] == 'page') {
|
185 |
+
$urls = $this->_getUrlsForCmsPage($tag_fields[2]);
|
186 |
+
}
|
187 |
+
}
|
188 |
+
}
|
189 |
+
|
190 |
+
// Transform urls to relative urls
|
191 |
+
$relativeUrls = array();
|
192 |
+
foreach ($urls as $url) {
|
193 |
+
$relativeUrls[] = parse_url($url, PHP_URL_PATH);
|
194 |
+
}
|
195 |
+
|
196 |
+
if (!empty($relativeUrls)) {
|
197 |
+
$relativeUrls = array_unique($relativeUrls);
|
198 |
+
$errors = Mage::helper('cache/varnish')->purge($relativeUrls);
|
199 |
+
if (!empty($errors)) {
|
200 |
+
Mage::getSingleton('adminhtml/session')->addError(
|
201 |
+
"Some Varnish purges failed: <br/>" . implode("<br/>", $errors));
|
202 |
+
} else {
|
203 |
+
Mage::getSingleton('adminhtml/session')->addSuccess(
|
204 |
+
"The following URLs have been cleared from Varnish: <br/> " . implode(", ", $relativeUrls));
|
205 |
+
}
|
206 |
+
}
|
207 |
+
|
208 |
+
return $this;
|
209 |
+
}
|
210 |
+
|
211 |
+
/**
|
212 |
+
* Returns all the urls related to product
|
213 |
+
*
|
214 |
+
* Uses code from magneto-varnish.
|
215 |
+
*
|
216 |
+
* @see https://github.com/madalinoprea/magneto-varnish/blob/master/code/Varnish/Model/Observer.php#L133
|
217 |
+
* @param Mage_Catalog_Model_Product $product
|
218 |
+
*/
|
219 |
+
protected function _getUrlsForProduct($product){
|
220 |
+
$urls = array();
|
221 |
+
|
222 |
+
$store_id = $product->getStoreId();
|
223 |
+
|
224 |
+
$routePath = 'catalog/product/view';
|
225 |
+
$routeParams['id'] = $product->getId();
|
226 |
+
$routeParams['s'] = $product->getUrlKey();
|
227 |
+
$routeParams['_store'] = (!$store_id ? 1: $store_id);
|
228 |
+
$url = Mage::getUrl($routePath, $routeParams);
|
229 |
+
$urls[] = $url;
|
230 |
+
|
231 |
+
// Collect all rewrites
|
232 |
+
$rewrites = Mage::getModel('core/url_rewrite')->getCollection();
|
233 |
+
if (!Mage::getConfig('catalog/seo/product_use_categories')) {
|
234 |
+
$rewrites->getSelect()
|
235 |
+
->where("id_path = 'product/{$product->getId()}'");
|
236 |
+
} else {
|
237 |
+
// Also show full links with categories
|
238 |
+
$rewrites->getSelect()
|
239 |
+
->where("id_path = 'product/{$product->getId()}' OR id_path like 'product/{$product->getId()}/%'");
|
240 |
+
}
|
241 |
+
foreach ($rewrites as $r) {
|
242 |
+
unset($routeParams);
|
243 |
+
$routePath = '';
|
244 |
+
$routeParams['_direct'] = $r->getRequestPath();
|
245 |
+
$routeParams['_store'] = $r->getStoreId();
|
246 |
+
$url = Mage::getUrl($routePath, $routeParams);
|
247 |
+
$urls[] = $url;
|
248 |
+
}
|
249 |
+
|
250 |
+
return $urls;
|
251 |
+
}
|
252 |
+
|
253 |
+
/**
|
254 |
+
* Returns all the urls pointing to the category
|
255 |
+
*
|
256 |
+
* Uses code from magneto-varnish.
|
257 |
+
*
|
258 |
+
* @see https://github.com/madalinoprea/magneto-varnish/blob/master/code/Varnish/Model/Observer.php#L171
|
259 |
+
*/
|
260 |
+
protected function _getUrlsForCategory($category) {
|
261 |
+
$urls = array();
|
262 |
+
$routePath = 'catalog/category/view';
|
263 |
+
|
264 |
+
$store_id = $category->getStoreId();
|
265 |
+
$routeParams['id'] = $category->getId();
|
266 |
+
$routeParams['s'] = $category->getUrlKey();
|
267 |
+
$routeParams['_store'] = (!$store_id ? 1 : $store_id); # Default store id is 1
|
268 |
+
$url = Mage::getUrl($routePath, $routeParams);
|
269 |
+
$urls[] = $url;
|
270 |
+
|
271 |
+
// Collect all rewrites
|
272 |
+
$rewrites = Mage::getModel('core/url_rewrite')->getCollection();
|
273 |
+
$rewrites->getSelect()->where("id_path = 'category/{$category->getId()}'");
|
274 |
+
foreach ($rewrites as $r) {
|
275 |
+
unset($routeParams);
|
276 |
+
$routePath = '';
|
277 |
+
$routeParams['_direct'] = $r->getRequestPath();
|
278 |
+
$routeParams['_store'] = $r->getStoreId();
|
279 |
+
$routeParams['_nosid'] = True;
|
280 |
+
$url = Mage::getUrl($routePath, $routeParams);
|
281 |
+
$urls[] = $url;
|
282 |
+
}
|
283 |
+
|
284 |
+
return $urls;
|
285 |
+
}
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Returns all urls related to this cms page
|
289 |
+
*
|
290 |
+
* Uses code from magneto-varnish.
|
291 |
+
*
|
292 |
+
* @see https://github.com/madalinoprea/magneto-varnish/blob/master/code/Varnish/Model/Observer.php#L201
|
293 |
+
*/
|
294 |
+
protected function _getUrlsForCmsPage($cmsPageId)
|
295 |
+
{
|
296 |
+
$urls = array();
|
297 |
+
$page = Mage::getModel('cms/page')->load($cmsPageId);
|
298 |
+
if ($page->getId()) {
|
299 |
+
$urls[] = '/' . $page->getIdentifier();
|
300 |
+
}
|
301 |
+
|
302 |
+
return $urls;
|
303 |
+
}
|
304 |
+
}
|
app/code/community/Made/Cache/controllers/VarnishController.php
CHANGED
@@ -42,4 +42,47 @@ class Made_Cache_VarnishController extends Mage_Core_Controller_Front_Action
|
|
42 |
$this->getResponse()->setBody($block->toHtml());
|
43 |
}
|
44 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
}
|
42 |
$this->getResponse()->setBody($block->toHtml());
|
43 |
}
|
44 |
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Render all messages from currently used session namespaces
|
48 |
+
*
|
49 |
+
* @return void
|
50 |
+
*/
|
51 |
+
public function messagesAction()
|
52 |
+
{
|
53 |
+
if (empty($_SESSION)) {
|
54 |
+
return;
|
55 |
+
}
|
56 |
+
|
57 |
+
$messagesBlock = $this->getLayout()
|
58 |
+
->createBlock('core/messages', 'messages')
|
59 |
+
->setBypassVarnish(true);
|
60 |
+
|
61 |
+
foreach ($_SESSION as $contents) {
|
62 |
+
if (isset($contents['messages']) &&
|
63 |
+
$contents['messages'] instanceof Mage_Core_Model_Message_Collection) {
|
64 |
+
if (!$contents['messages']->count()) {
|
65 |
+
continue;
|
66 |
+
}
|
67 |
+
$messagesBlock->addMessages($contents['messages']);
|
68 |
+
$contents['messages']->clear();
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
if (!$messagesBlock->getMessageCollection()->count()) {
|
73 |
+
return;
|
74 |
+
}
|
75 |
+
|
76 |
+
$this->getResponse()
|
77 |
+
->setBody($messagesBlock->toHtml());
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Simply make sure that the session is valid
|
82 |
+
*
|
83 |
+
* @see Made_Cache_Block_Footer
|
84 |
+
*/
|
85 |
+
public function cookieAction()
|
86 |
+
{
|
87 |
+
}
|
88 |
}
|
app/code/community/Made/Cache/etc/config.xml
CHANGED
@@ -9,10 +9,24 @@
|
|
9 |
<config>
|
10 |
<modules>
|
11 |
<Made_Cache>
|
12 |
-
<version>1.
|
13 |
</Made_Cache>
|
14 |
</modules>
|
15 |
<global>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
<models>
|
17 |
<cache>
|
18 |
<class>Made_Cache_Model</class>
|
@@ -27,8 +41,31 @@
|
|
27 |
<cache>
|
28 |
<class>Made_Cache_Block</class>
|
29 |
</cache>
|
|
|
|
|
|
|
|
|
|
|
30 |
</blocks>
|
31 |
<events>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
<controller_action_predispatch>
|
33 |
<observers>
|
34 |
<remove_uenc_param>
|
@@ -47,15 +84,6 @@
|
|
47 |
</cache_setup_block>
|
48 |
</observers>
|
49 |
</core_block_abstract_to_html_before>
|
50 |
-
<core_block_abstract_to_html_after>
|
51 |
-
<observers>
|
52 |
-
<cache_add_esi_tags>
|
53 |
-
<type>singleton</type>
|
54 |
-
<class>cache/observer</class>
|
55 |
-
<method>addEsiTag</method>
|
56 |
-
</cache_add_esi_tags>
|
57 |
-
</observers>
|
58 |
-
</core_block_abstract_to_html_after>
|
59 |
<sales_quote_save_after>
|
60 |
<observers>
|
61 |
<quote_save_after>
|
@@ -112,5 +140,106 @@
|
|
112 |
</Made_Cache>
|
113 |
</modules>
|
114 |
</translate>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
</frontend>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
</config>
|
9 |
<config>
|
10 |
<modules>
|
11 |
<Made_Cache>
|
12 |
+
<version>1.4.0</version>
|
13 |
</Made_Cache>
|
14 |
</modules>
|
15 |
<global>
|
16 |
+
<cache>
|
17 |
+
<types>
|
18 |
+
<varnish translate="label,description" module="cache">
|
19 |
+
<label>Varnish</label>
|
20 |
+
<description><![CDATA[Full page cache. Requires a configured Varnish daemon, see https://www.varnish-cache.org/]]></description>
|
21 |
+
<tags/>
|
22 |
+
</varnish>
|
23 |
+
</types>
|
24 |
+
</cache>
|
25 |
+
<helpers>
|
26 |
+
<cache>
|
27 |
+
<class>Made_Cache_Helper</class>
|
28 |
+
</cache>
|
29 |
+
</helpers>
|
30 |
<models>
|
31 |
<cache>
|
32 |
<class>Made_Cache_Model</class>
|
41 |
<cache>
|
42 |
<class>Made_Cache_Block</class>
|
43 |
</cache>
|
44 |
+
<core>
|
45 |
+
<rewrite>
|
46 |
+
<messages>Made_Cache_Block_Messages</messages>
|
47 |
+
</rewrite>
|
48 |
+
</core>
|
49 |
</blocks>
|
50 |
<events>
|
51 |
+
<adminhtml_cache_flush_all>
|
52 |
+
<observers>
|
53 |
+
<varnish_purge>
|
54 |
+
<type>singleton</type>
|
55 |
+
<class>cache/varnishObserver</class>
|
56 |
+
<method>purge</method>
|
57 |
+
</varnish_purge>
|
58 |
+
</observers>
|
59 |
+
</adminhtml_cache_flush_all>
|
60 |
+
<application_clean_cache>
|
61 |
+
<observers>
|
62 |
+
<varnish_purge>
|
63 |
+
<type>singleton</type>
|
64 |
+
<class>cache/varnishObserver</class>
|
65 |
+
<method>purge</method>
|
66 |
+
</varnish_purge>
|
67 |
+
</observers>
|
68 |
+
</application_clean_cache>
|
69 |
<controller_action_predispatch>
|
70 |
<observers>
|
71 |
<remove_uenc_param>
|
84 |
</cache_setup_block>
|
85 |
</observers>
|
86 |
</core_block_abstract_to_html_before>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
<sales_quote_save_after>
|
88 |
<observers>
|
89 |
<quote_save_after>
|
140 |
</Made_Cache>
|
141 |
</modules>
|
142 |
</translate>
|
143 |
+
<events>
|
144 |
+
<controller_action_predispatch>
|
145 |
+
<observers>
|
146 |
+
<add_layout_handle>
|
147 |
+
<type>singleton</type>
|
148 |
+
<class>cache/varnishObserver</class>
|
149 |
+
<method>addLayoutHandle</method>
|
150 |
+
</add_layout_handle>
|
151 |
+
</observers>
|
152 |
+
</controller_action_predispatch>
|
153 |
+
<controller_action_predispatch>
|
154 |
+
<observers>
|
155 |
+
<clear_cache_headers>
|
156 |
+
<type>singleton</type>
|
157 |
+
<class>cache/varnishObserver</class>
|
158 |
+
<method>initializeResponseHeaders</method>
|
159 |
+
</clear_cache_headers>
|
160 |
+
</observers>
|
161 |
+
</controller_action_predispatch>
|
162 |
+
<controller_action_postdispatch>
|
163 |
+
<observers>
|
164 |
+
<set_varnish_headers>
|
165 |
+
<type>singleton</type>
|
166 |
+
<class>cache/varnishObserver</class>
|
167 |
+
<method>setVarnishCacheHeaders</method>
|
168 |
+
</set_varnish_headers>
|
169 |
+
<purge_user_cache>
|
170 |
+
<type>singleton</type>
|
171 |
+
<class>cache/varnishObserver</class>
|
172 |
+
<method>purgeUserCache</method>
|
173 |
+
</purge_user_cache>
|
174 |
+
</observers>
|
175 |
+
</controller_action_postdispatch>
|
176 |
+
<core_block_abstract_to_html_after>
|
177 |
+
<observers>
|
178 |
+
<cache_add_esi_tags>
|
179 |
+
<type>singleton</type>
|
180 |
+
<class>cache/varnishObserver</class>
|
181 |
+
<method>addEsiTag</method>
|
182 |
+
</cache_add_esi_tags>
|
183 |
+
<cache_profiler_end>
|
184 |
+
<type>singleton</type>
|
185 |
+
<class>cache/observer</class>
|
186 |
+
<method>profilerEnd</method>
|
187 |
+
</cache_profiler_end>
|
188 |
+
</observers>
|
189 |
+
</core_block_abstract_to_html_after>
|
190 |
+
<core_block_abstract_to_html_before>
|
191 |
+
<observers>
|
192 |
+
<cache_profiler_start>
|
193 |
+
<type>singleton</type>
|
194 |
+
<class>cache/observer</class>
|
195 |
+
<method>profilerStart</method>
|
196 |
+
</cache_profiler_start>
|
197 |
+
</observers>
|
198 |
+
</core_block_abstract_to_html_before>
|
199 |
+
</events>
|
200 |
</frontend>
|
201 |
+
<adminhtml>
|
202 |
+
<acl>
|
203 |
+
<resources>
|
204 |
+
<admin>
|
205 |
+
<children>
|
206 |
+
<system>
|
207 |
+
<children>
|
208 |
+
<config>
|
209 |
+
<children>
|
210 |
+
<cache>
|
211 |
+
<title>Made Cache Section</title>
|
212 |
+
</cache>
|
213 |
+
</children>
|
214 |
+
</config>
|
215 |
+
</children>
|
216 |
+
</system>
|
217 |
+
</children>
|
218 |
+
</admin>
|
219 |
+
</resources>
|
220 |
+
</acl>
|
221 |
+
</adminhtml>
|
222 |
+
<default>
|
223 |
+
<cache>
|
224 |
+
<general>
|
225 |
+
<enable_profiler>0</enable_profiler>
|
226 |
+
<remove_redirect_param>0</remove_redirect_param>
|
227 |
+
</general>
|
228 |
+
<varnish>
|
229 |
+
<ttl>1w</ttl>
|
230 |
+
<nocache_routes><![CDATA[customer
|
231 |
+
checkout
|
232 |
+
streamcheckout
|
233 |
+
onestepcheckout
|
234 |
+
ajaxcart
|
235 |
+
catalog/product_compare
|
236 |
+
wishlist
|
237 |
+
moneybookers
|
238 |
+
paypal]]>
|
239 |
+
</nocache_routes>
|
240 |
+
<servers>127.0.0.1</servers>
|
241 |
+
<debug>0</debug>
|
242 |
+
</varnish>
|
243 |
+
</cache>
|
244 |
+
</default>
|
245 |
</config>
|
app/code/community/Made/Cache/etc/magento.vcl
CHANGED
@@ -1,98 +1,88 @@
|
|
1 |
-
|
2 |
-
#
|
3 |
-
# Modifications for use with ESI tags and Made_Cache
|
4 |
-
#
|
5 |
|
6 |
-
# default backend definition. Set this to point to your content server.
|
7 |
backend default {
|
8 |
-
|
9 |
-
|
10 |
}
|
11 |
|
12 |
-
# admin backend
|
13 |
backend admin {
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
}
|
19 |
|
20 |
-
#
|
21 |
acl purge {
|
22 |
-
|
23 |
-
|
24 |
}
|
25 |
|
26 |
sub vcl_recv {
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
} else {
|
32 |
-
set req.http.X-Forwarded-For = client.ip;
|
33 |
}
|
|
|
34 |
}
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
req.request != "POST" &&
|
40 |
-
req.request != "TRACE" &&
|
41 |
-
req.request != "OPTIONS" &&
|
42 |
-
req.request != "DELETE" &&
|
43 |
-
req.request != "PURGE") {
|
44 |
-
/* Non-RFC2616 or CONNECT which is weird. */
|
45 |
-
return (pipe);
|
46 |
-
}
|
47 |
-
|
48 |
-
# purge request
|
49 |
-
if (req.request == "PURGE") {
|
50 |
if (!client.ip ~ purge) {
|
51 |
error 405 "Not allowed.";
|
52 |
}
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
}
|
56 |
|
57 |
-
#
|
58 |
-
if (req.
|
59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
}
|
61 |
|
62 |
-
#
|
63 |
-
if (req.request
|
64 |
-
|
|
|
|
|
|
|
|
|
65 |
}
|
66 |
-
|
67 |
-
#
|
68 |
-
|
69 |
-
|
70 |
-
# static files are always cacheable. remove SSL flag and cookie
|
71 |
-
if (req.url ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico)$") {
|
72 |
-
unset req.http.Https;
|
73 |
-
unset req.http.Cookie;
|
74 |
}
|
75 |
|
76 |
-
#
|
77 |
-
if (req.http.
|
78 |
-
|
|
|
79 |
}
|
80 |
|
81 |
-
#
|
82 |
-
|
83 |
-
|
84 |
-
if (req.url ~ "^/(index)") {
|
85 |
return (pass);
|
86 |
}
|
87 |
|
88 |
-
#
|
89 |
-
# Modification for Made_Cache, ideally we should only disable cache per
|
90 |
-
# specific ruote
|
91 |
-
#if (req.http.cookie ~ "NO_CACHE=") {
|
92 |
-
# return (pass);
|
93 |
-
#}
|
94 |
-
|
95 |
-
# normalize Aceept-Encoding header
|
96 |
# http://varnish.projects.linpro.no/wiki/FAQ/Compression
|
97 |
if (req.http.Accept-Encoding) {
|
98 |
if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|flv)$") {
|
@@ -107,149 +97,93 @@ sub vcl_recv {
|
|
107 |
remove req.http.Accept-Encoding;
|
108 |
}
|
109 |
}
|
110 |
-
|
111 |
-
# remove Google gclid parameters
|
112 |
-
set req.url = regsuball(req.url,"\?gclid=[^&]+$",""); # strips when QS = "?gclid=AAA"
|
113 |
-
set req.url = regsuball(req.url,"\?gclid=[^&]+&","?"); # strips when QS = "?gclid=AAA&foo=bar"
|
114 |
-
set req.url = regsuball(req.url,"&gclid=[^&]+",""); # strips when QS = "?foo=bar&gclid=AAA" or QS = "?foo=bar&gclid=AAA&bar=baz"
|
115 |
-
|
116 |
return (lookup);
|
117 |
}
|
118 |
|
119 |
-
# sub vcl_pipe {
|
120 |
-
# # Note that only the first request to the backend will have
|
121 |
-
# # X-Forwarded-For set. If you use X-Forwarded-For and want to
|
122 |
-
# # have it set for all requests, make sure to have:
|
123 |
-
# # set bereq.http.connection = "close";
|
124 |
-
# # here. It is not set by default as it might break some broken web
|
125 |
-
# # applications, like IIS with NTLM authentication.
|
126 |
-
# return (pipe);
|
127 |
-
# }
|
128 |
-
#
|
129 |
-
# sub vcl_pass {
|
130 |
-
# return (pass);
|
131 |
-
# }
|
132 |
-
#
|
133 |
sub vcl_hash {
|
134 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
if (req.http.host) {
|
136 |
hash_data(req.http.host);
|
137 |
} else {
|
138 |
hash_data(server.ip);
|
139 |
}
|
140 |
-
|
141 |
-
call design_exception;
|
142 |
-
}
|
143 |
return (hash);
|
144 |
}
|
145 |
-
#
|
146 |
-
# sub vcl_hit {
|
147 |
-
# return (deliver);
|
148 |
-
# }
|
149 |
-
#
|
150 |
-
# sub vcl_miss {
|
151 |
-
# return (fetch);
|
152 |
-
# }
|
153 |
|
154 |
-
sub
|
155 |
-
if (req.
|
156 |
-
|
|
|
157 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
|
159 |
-
|
160 |
-
|
161 |
-
|
|
|
|
|
162 |
}
|
163 |
-
set beresp.grace = 5m;
|
164 |
|
165 |
-
#
|
166 |
-
|
167 |
-
set beresp.http.X-Purge-Host = req.http.host;
|
168 |
-
|
169 |
if (beresp.status == 200 || beresp.status == 301 || beresp.status == 404) {
|
170 |
if (beresp.http.Content-Type ~ "text/html" || beresp.http.Content-Type ~ "text/xml") {
|
171 |
set beresp.do_esi = true;
|
172 |
-
|
173 |
-
set beresp.ttl = 0s;
|
174 |
-
return (hit_for_pass);
|
175 |
-
}
|
176 |
-
|
177 |
-
# marker for vcl_deliver to reset Age:
|
178 |
-
set beresp.http.magicmarker = "1";
|
179 |
-
|
180 |
-
# Don't cache cookies
|
181 |
-
unset beresp.http.set-cookie;
|
182 |
} else {
|
183 |
-
#
|
184 |
-
set beresp.ttl =
|
185 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
return (deliver);
|
187 |
}
|
188 |
-
|
|
|
189 |
return (hit_for_pass);
|
190 |
}
|
191 |
|
192 |
sub vcl_deliver {
|
193 |
-
# debug
|
194 |
-
if (
|
195 |
-
|
196 |
-
set resp.http.X-Cache = "HIT";
|
197 |
-
set resp.http.X-Cache-Hits = obj.hits;
|
198 |
-
} else {
|
199 |
-
set resp.http.X-Cache = "MISS";
|
200 |
-
}
|
201 |
-
set resp.http.X-Cache-Expires = resp.http.Expires;
|
202 |
-
} else {
|
203 |
-
# remove Varnish/proxy header
|
204 |
-
remove resp.http.X-Varnish;
|
205 |
-
remove resp.http.Via;
|
206 |
-
remove resp.http.Age;
|
207 |
-
remove resp.http.X-Purge-URL;
|
208 |
-
remove resp.http.X-Purge-Host;
|
209 |
-
}
|
210 |
-
|
211 |
-
if (resp.http.magicmarker) {
|
212 |
-
# Remove the magic marker
|
213 |
-
unset resp.http.magicmarker;
|
214 |
-
|
215 |
-
set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
|
216 |
-
set resp.http.Pragma = "no-cache";
|
217 |
-
set resp.http.Expires = "Mon, 31 Mar 2008 10:00:00 GMT";
|
218 |
-
set resp.http.Age = "0";
|
219 |
}
|
220 |
-
}
|
221 |
|
222 |
-
|
223 |
-
#
|
224 |
-
|
225 |
-
|
226 |
-
#
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
# </head>
|
233 |
-
# <body>
|
234 |
-
# <h1>Error "} + obj.status + " " + obj.response + {"</h1>
|
235 |
-
# <p>"} + obj.response + {"</p>
|
236 |
-
# <h3>Guru Meditation:</h3>
|
237 |
-
# <p>XID: "} + req.xid + {"</p>
|
238 |
-
# <hr>
|
239 |
-
# <p>Varnish cache server</p>
|
240 |
-
# </body>
|
241 |
-
# </html>
|
242 |
-
# "};
|
243 |
-
# return (deliver);
|
244 |
-
# }
|
245 |
-
#
|
246 |
-
# sub vcl_init {
|
247 |
-
# return (ok);
|
248 |
-
# }
|
249 |
-
#
|
250 |
-
# sub vcl_fini {
|
251 |
-
# return (ok);
|
252 |
-
# }
|
253 |
-
|
254 |
-
sub design_exception {
|
255 |
-
}
|
1 |
+
import std;
|
|
|
|
|
|
|
2 |
|
|
|
3 |
backend default {
|
4 |
+
.host = "127.0.0.1";
|
5 |
+
.port = "9000";
|
6 |
}
|
7 |
|
8 |
+
# The admin backend needs longer timeout values
|
9 |
backend admin {
|
10 |
+
.host = "127.0.0.1";
|
11 |
+
.port = "9000";
|
12 |
+
.first_byte_timeout = 18000s;
|
13 |
+
.between_bytes_timeout = 18000s;
|
14 |
}
|
15 |
|
16 |
+
# Add additional (ie webserver) IPs here that should be able to purge cache
|
17 |
acl purge {
|
18 |
+
"localhost";
|
19 |
+
"127.0.0.1";
|
20 |
}
|
21 |
|
22 |
sub vcl_recv {
|
23 |
+
# Ban specific object in the cache
|
24 |
+
if (req.request == "PURGE") {
|
25 |
+
if (!client.ip ~ purge) {
|
26 |
+
error 405 "Not allowed.";
|
|
|
|
|
27 |
}
|
28 |
+
return (lookup);
|
29 |
}
|
30 |
+
|
31 |
+
# Ban something
|
32 |
+
if (req.request == "BAN") {
|
33 |
+
# Same ACL check as above:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
if (!client.ip ~ purge) {
|
35 |
error 405 "Not allowed.";
|
36 |
}
|
37 |
+
if (req.http.X-Ban-String) {
|
38 |
+
ban(req.http.X-Ban-String);
|
39 |
+
|
40 |
+
# Throw a synthetic page so the
|
41 |
+
# request won't go to the backend.
|
42 |
+
error 200 "Ban added";
|
43 |
+
}
|
44 |
+
|
45 |
+
error 400 "Bad request.";
|
46 |
}
|
47 |
|
48 |
+
# Flush the whole cache
|
49 |
+
if (req.request == "FLUSH") {
|
50 |
+
if (!client.ip ~ purge) {
|
51 |
+
error 405 "Not allowed.";
|
52 |
+
}
|
53 |
+
# If there are multiple vhosts we only want to clear all cache for
|
54 |
+
# the one issuing the request
|
55 |
+
ban("req.url ~ .*");
|
56 |
+
error 200 "Flushed";
|
57 |
}
|
58 |
|
59 |
+
# Refresh specific object
|
60 |
+
if (req.request == "REFRESH") {
|
61 |
+
if (!client.ip ~ purge) {
|
62 |
+
error 405 "Not allowed.";
|
63 |
+
}
|
64 |
+
set req.request = "GET";
|
65 |
+
set req.hash_always_miss = true;
|
66 |
}
|
67 |
+
|
68 |
+
# Switch to the admin backend
|
69 |
+
if (req.http.Cookie ~ "adminhtml=") {
|
70 |
+
set req.backend = admin;
|
|
|
|
|
|
|
|
|
71 |
}
|
72 |
|
73 |
+
# Keep track of logged in users
|
74 |
+
if (req.http.Cookie ~ "frontend=") {
|
75 |
+
set req.http.X-Session-UUID =
|
76 |
+
regsub(req.http.Cookie, "^.*?frontend=([^;]*);*.*$", "\1");
|
77 |
}
|
78 |
|
79 |
+
# Pass anything other than GET and HEAD directly.
|
80 |
+
if (req.request != "GET" && req.request != "HEAD") {
|
81 |
+
/* We only deal with GET and HEAD by default */
|
|
|
82 |
return (pass);
|
83 |
}
|
84 |
|
85 |
+
# Normalize Aceept-Encoding header to reduce vary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
# http://varnish.projects.linpro.no/wiki/FAQ/Compression
|
87 |
if (req.http.Accept-Encoding) {
|
88 |
if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|flv)$") {
|
97 |
remove req.http.Accept-Encoding;
|
98 |
}
|
99 |
}
|
100 |
+
|
|
|
|
|
|
|
|
|
|
|
101 |
return (lookup);
|
102 |
}
|
103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
sub vcl_hash {
|
105 |
+
# ESI request
|
106 |
+
if (req.url ~ "/madecache/varnish/(esi|messages)") {
|
107 |
+
hash_data(regsub(req.url, "(/hash/[^\/]+/).*", "\1"));
|
108 |
+
|
109 |
+
# Logged in user, cache on UUID level
|
110 |
+
if (req.http.X-Session-UUID) {
|
111 |
+
hash_data(req.http.X-Session-UUID);
|
112 |
+
}
|
113 |
+
} else {
|
114 |
+
hash_data(req.url);
|
115 |
+
}
|
116 |
+
|
117 |
+
# Also consider the host name for caching (multi-site with different themes etc)
|
118 |
if (req.http.host) {
|
119 |
hash_data(req.http.host);
|
120 |
} else {
|
121 |
hash_data(server.ip);
|
122 |
}
|
123 |
+
|
|
|
|
|
124 |
return (hash);
|
125 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
|
127 |
+
sub vcl_hit {
|
128 |
+
if (req.request == "PURGE") {
|
129 |
+
purge;
|
130 |
+
error 200 "Purged";
|
131 |
}
|
132 |
+
}
|
133 |
+
|
134 |
+
sub vcl_miss {
|
135 |
+
if (req.request == "PURGE") {
|
136 |
+
purge;
|
137 |
+
error 404 "Not in cache";
|
138 |
+
}
|
139 |
+
}
|
140 |
|
141 |
+
# Called when an object is fetched from the backend
|
142 |
+
sub vcl_fetch {
|
143 |
+
# Pass the cookie requests directly to the backend, without caching
|
144 |
+
if (req.url ~ "/madecache/varnish/cookie") {
|
145 |
+
return (hit_for_pass);
|
146 |
}
|
|
|
147 |
|
148 |
+
# If the X-Made-Cache-Ttl header is set, use it, otherwise default to
|
149 |
+
# not caching the contents (0s)
|
|
|
|
|
150 |
if (beresp.status == 200 || beresp.status == 301 || beresp.status == 404) {
|
151 |
if (beresp.http.Content-Type ~ "text/html" || beresp.http.Content-Type ~ "text/xml") {
|
152 |
set beresp.do_esi = true;
|
153 |
+
set beresp.ttl = std.duration(beresp.http.X-Made-Cache-Ttl, 0s);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
} else {
|
155 |
+
# TTL for static content
|
156 |
+
set beresp.ttl = 1w;
|
157 |
}
|
158 |
+
|
159 |
+
# Don't cache expire headers, we maintain those differently
|
160 |
+
unset beresp.http.expires;
|
161 |
+
|
162 |
+
# Caching the cookie header would make multiple clients share session
|
163 |
+
set req.http.tempCookie = beresp.http.Set-Cookie;
|
164 |
+
unset beresp.http.Set-Cookie;
|
165 |
+
|
166 |
+
# Cache (if positive TTL)
|
167 |
return (deliver);
|
168 |
}
|
169 |
+
|
170 |
+
# Don't cache
|
171 |
return (hit_for_pass);
|
172 |
}
|
173 |
|
174 |
sub vcl_deliver {
|
175 |
+
# To debug if it's a hit or a miss
|
176 |
+
if (req.http.X-Made-Cache-Debug) {
|
177 |
+
set resp.http.X-Cache-Hits = obj.hits;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
178 |
}
|
|
|
179 |
|
180 |
+
if (req.http.tempCookie) {
|
181 |
+
# We saved the cookie to give the user that cached the page a session
|
182 |
+
set resp.http.Set-Cookie = req.http.tempCookie;
|
183 |
+
|
184 |
+
# Version of https://www.varnish-cache.org/trac/wiki/VCLExampleLongerCaching
|
185 |
+
set resp.http.age = "0";
|
186 |
+
}
|
187 |
+
|
188 |
+
return (deliver);
|
189 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/code/community/Made/Cache/etc/system.xml
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<tabs>
|
4 |
+
<made translate="label" module="core">
|
5 |
+
<label>Made People</label>
|
6 |
+
<sort_order>101</sort_order>
|
7 |
+
</made>
|
8 |
+
</tabs>
|
9 |
+
<sections>
|
10 |
+
<cache>
|
11 |
+
<label>Cache</label>
|
12 |
+
<tab>made</tab>
|
13 |
+
<frontend_type>text</frontend_type>
|
14 |
+
<sort_order>1000</sort_order>
|
15 |
+
<show_in_default>1</show_in_default>
|
16 |
+
<show_in_website>1</show_in_website>
|
17 |
+
<show_in_store>1</show_in_store>
|
18 |
+
<groups>
|
19 |
+
<general translate="label">
|
20 |
+
<label>General Settings</label>
|
21 |
+
<frontend_type>text</frontend_type>
|
22 |
+
<sort_order>0</sort_order>
|
23 |
+
<show_in_default>1</show_in_default>
|
24 |
+
<show_in_website>1</show_in_website>
|
25 |
+
<show_in_store>1</show_in_store>
|
26 |
+
<fields>
|
27 |
+
<enable_profiler>
|
28 |
+
<label>Enable Block Profiler</label>
|
29 |
+
<comment>Displays hierarchical data of uncached block rendering times</comment>
|
30 |
+
<frontend_type>select</frontend_type>
|
31 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
32 |
+
<sort_order>1</sort_order>
|
33 |
+
<show_in_default>1</show_in_default>
|
34 |
+
<show_in_website>1</show_in_website>
|
35 |
+
<show_in_store>1</show_in_store>
|
36 |
+
</enable_profiler>
|
37 |
+
<remove_redirect_param>
|
38 |
+
<label>Remove Redirect Parameter</label>
|
39 |
+
<comment>Required if you display blocks with cached redirect links on more than one page, making redirects incorrect. This requires manual implementation which means you probably know what you're doing. Otherwise, disable.</comment>
|
40 |
+
<frontend_type>select</frontend_type>
|
41 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
42 |
+
<sort_order>2</sort_order>
|
43 |
+
<show_in_default>1</show_in_default>
|
44 |
+
<show_in_website>1</show_in_website>
|
45 |
+
<show_in_store>1</show_in_store>
|
46 |
+
</remove_redirect_param>
|
47 |
+
</fields>
|
48 |
+
</general>
|
49 |
+
<varnish translate="label">
|
50 |
+
<label>Varnish Settings (Enabled in Cache Management)</label>
|
51 |
+
<frontend_type>text</frontend_type>
|
52 |
+
<sort_order>1</sort_order>
|
53 |
+
<show_in_default>1</show_in_default>
|
54 |
+
<show_in_website>1</show_in_website>
|
55 |
+
<show_in_store>1</show_in_store>
|
56 |
+
<fields>
|
57 |
+
<ttl>
|
58 |
+
<label>Default Varnish TTL</label>
|
59 |
+
<comment><![CDATA[<a href="https://www.varnish-software.com/static/book/VCL_Basics.html#the-initial-value-of-beresp-ttl" target="_blank">Click here for an explanation of Varnish TTL values</a><br/>Default 1w]]></comment>
|
60 |
+
<frontend_type>text</frontend_type>
|
61 |
+
<sort_order>1</sort_order>
|
62 |
+
<show_in_default>1</show_in_default>
|
63 |
+
<show_in_website>1</show_in_website>
|
64 |
+
<show_in_store>1</show_in_store>
|
65 |
+
</ttl>
|
66 |
+
<nocache_routes>
|
67 |
+
<label>Routes to exclude from cache</label>
|
68 |
+
<comment>One per line: module, module/controller, or module/controller/action</comment>
|
69 |
+
<frontend_type>textarea</frontend_type>
|
70 |
+
<sort_order>2</sort_order>
|
71 |
+
<show_in_default>1</show_in_default>
|
72 |
+
<show_in_website>1</show_in_website>
|
73 |
+
<show_in_store>1</show_in_store>
|
74 |
+
</nocache_routes>
|
75 |
+
<servers>
|
76 |
+
<label>IPs to Varnish servers</label>
|
77 |
+
<comment>One per line</comment>
|
78 |
+
<frontend_type>textarea</frontend_type>
|
79 |
+
<sort_order>3</sort_order>
|
80 |
+
<show_in_default>1</show_in_default>
|
81 |
+
<show_in_website>1</show_in_website>
|
82 |
+
<show_in_store>1</show_in_store>
|
83 |
+
</servers>
|
84 |
+
<debug>
|
85 |
+
<label>Debug Mode</label>
|
86 |
+
<comment>Displays debug information as response headers</comment>
|
87 |
+
<frontend_type>select</frontend_type>
|
88 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
89 |
+
<sort_order>3</sort_order>
|
90 |
+
<show_in_default>1</show_in_default>
|
91 |
+
<show_in_website>1</show_in_website>
|
92 |
+
<show_in_store>1</show_in_store>
|
93 |
+
</debug>
|
94 |
+
</fields>
|
95 |
+
</varnish>
|
96 |
+
</groups>
|
97 |
+
</cache>
|
98 |
+
</sections>
|
99 |
+
</config>
|
app/design/frontend/base/default/layout/madecache.xml
CHANGED
@@ -20,23 +20,62 @@
|
|
20 |
<name>before_body_end</name>
|
21 |
<name>product.info</name>
|
22 |
<name>product_list</name>
|
23 |
-
<name>category.products</name>
|
24 |
<name lifetime="7200">cart_sidebar</name>
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
</cache>
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
<!--
|
28 |
Example of blocks that typically should render using ESI, this
|
29 |
-
is only used if Varnish is actually in front of Magento
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
-->
|
31 |
<esi>
|
|
|
32 |
<name>cart_sidebar</name>
|
33 |
<name>catalog.compare.sidebar</name>
|
34 |
-
<name>right.reports.product.viewed</name>
|
35 |
<name>right.reports.product.compared</name>
|
36 |
-
<name>
|
37 |
-
<name>google_analytics</name>
|
38 |
</esi>
|
39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
|
41 |
<checkout_onepage_index>
|
42 |
<nocache>
|
@@ -52,4 +91,4 @@
|
|
52 |
<name>content</name>
|
53 |
</nocache>
|
54 |
</streamcheckout_index_index>
|
55 |
-
</layout>
|
20 |
<name>before_body_end</name>
|
21 |
<name>product.info</name>
|
22 |
<name>product_list</name>
|
|
|
23 |
<name lifetime="7200">cart_sidebar</name>
|
24 |
+
|
25 |
+
<!--
|
26 |
+
People want to cache this one, but it works badly if you use
|
27 |
+
the toolbar block to switch listing types
|
28 |
+
-->
|
29 |
+
<!--<name>category.products</name>-->
|
30 |
</cache>
|
31 |
+
|
32 |
+
<!-- Inject profiler block into the bottom of the layout -->
|
33 |
+
<reference name="root">
|
34 |
+
<!-- This block can't be used with varnish cache enabled -->
|
35 |
+
<block type="cache/profiler" name="cache_profiler" output="toHtml" ifconfig="cache/general/enable_profiler"/>
|
36 |
+
</reference>
|
37 |
+
</default>
|
38 |
+
|
39 |
+
<varnish_enabled>
|
40 |
<!--
|
41 |
Example of blocks that typically should render using ESI, this
|
42 |
+
is only used if Varnish is actually in front of Magento.
|
43 |
+
|
44 |
+
It's best to keep these blocks at a minimum, and if possible,
|
45 |
+
bundled together as single big blocks. At the moment there is
|
46 |
+
no good way to serve the product view cached while recording
|
47 |
+
"recently viewed products", as this requires a costly backend
|
48 |
+
process for each product view.
|
49 |
-->
|
50 |
<esi>
|
51 |
+
<name>top.links</name>
|
52 |
<name>cart_sidebar</name>
|
53 |
<name>catalog.compare.sidebar</name>
|
|
|
54 |
<name>right.reports.product.compared</name>
|
55 |
+
<name>right.poll</name>
|
|
|
56 |
</esi>
|
57 |
+
|
58 |
+
<!--
|
59 |
+
Messages are fetched using ESI outside of the normal layout.
|
60 |
+
|
61 |
+
Stupid? Unsure. We must take care of all messages at every stage,
|
62 |
+
keeping the standard distributed way of rendering messages fails
|
63 |
+
here. The block is replaced under the hood with a special ESI tag.
|
64 |
+
|
65 |
+
Keep global_messages as a combined renderer
|
66 |
+
|
67 |
+
@see Made_Cache_Block_Messages
|
68 |
+
-->
|
69 |
+
<remove name="messages"/>
|
70 |
+
|
71 |
+
<!-- There is no good way to manage the recently viewed block -->
|
72 |
+
<remove name="right.reports.product.viewed"/>
|
73 |
+
<remove name="left.reports.product.viewed"/>
|
74 |
+
|
75 |
+
<reference name="root">
|
76 |
+
<block type="cache/varnish_footer" name="varnish_cache_footer" output="toHtml"/>
|
77 |
+
</reference>
|
78 |
+
</varnish_enabled>
|
79 |
|
80 |
<checkout_onepage_index>
|
81 |
<nocache>
|
91 |
<name>content</name>
|
92 |
</nocache>
|
93 |
</streamcheckout_index_index>
|
94 |
+
</layout>
|
package.xml
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Made_Cache</name>
|
4 |
-
<version>1.
|
5 |
<stability>stable</stability>
|
6 |
<license>OSL 3.0</license>
|
7 |
<channel>community</channel>
|
@@ -18,9 +18,9 @@ ESI is supported in conjunction with Phoenix_VarnishCache, and allows for super-
|
|
18 |
A good block cache is vital for scaling a site, be sure to implement it before residing to full page cache.</description>
|
19 |
<notes>N/A</notes>
|
20 |
<authors><author><name>Jonathan Selander</name><user>jonathan_made</user><email>info@madepeople.se</email></author></authors>
|
21 |
-
<date>2012-
|
22 |
-
<time>
|
23 |
-
<contents><target name="magecommunity"><dir name="Made"><dir name="Cache"><dir name="Block"><dir name="Catalog"><dir name="Product"><dir name="List"><file name="Product.php" hash="6356fde9c5acf5f0a96851e780a691b1"/></dir><file name="List.php" hash="
|
24 |
<compatible/>
|
25 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
26 |
</package>
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Made_Cache</name>
|
4 |
+
<version>1.4.0</version>
|
5 |
<stability>stable</stability>
|
6 |
<license>OSL 3.0</license>
|
7 |
<channel>community</channel>
|
18 |
A good block cache is vital for scaling a site, be sure to implement it before residing to full page cache.</description>
|
19 |
<notes>N/A</notes>
|
20 |
<authors><author><name>Jonathan Selander</name><user>jonathan_made</user><email>info@madepeople.se</email></author></authors>
|
21 |
+
<date>2012-11-15</date>
|
22 |
+
<time>21:05:37</time>
|
23 |
+
<contents><target name="magecommunity"><dir name="Made"><dir name="Cache"><dir name="Block"><dir name="Catalog"><dir name="Product"><dir name="List"><file name="Product.php" hash="6356fde9c5acf5f0a96851e780a691b1"/></dir><file name="List.php" hash="bb1e30501c95e83901de75bcb780d072"/></dir></dir><file name="Messages.php" hash="6d7eaed6a93c0deb6037ea36e88ec62f"/><file name="Profiler.php" hash="7d1fd856f08a1900b15a72ae46eb143d"/><dir name="Varnish"><file name="Footer.php" hash="4da9584f4cf4b70149b5c48f9657f668"/></dir></dir><dir name="Helper"><file name="Data.php" hash="6ea193010f6bf79c0c92f06d15e8d73b"/><file name="Varnish.php" hash="e94eaec8c45a829aba298ca4a0e4fe08"/></dir><dir name="Model"><file name="Layout.php" hash="0bfb72b6b9b5ccdeb2e9f8f2a5883367"/><dir name="Observer"><file name="Abstract.php" hash="e9f870d8766e1b2e5c6c091052565731"/><file name="Catalog.php" hash="39e069dd45ef75d2ab5b00c708181567"/><file name="Checkout.php" hash="4f6cc6aa7b2466976cad6c25f6a466e5"/><file name="Cms.php" hash="7bac2c6d57d3ff85d397c7cc1867c323"/></dir><file name="Observer.php" hash="8e641fbc376853a6237e0271288b0e4a"/><file name="Profiler.php" hash="888d3e38e212d872a4420a3556ca4b08"/><file name="VarnishObserver.php" hash="f1b479228036c3bd37144be0666cbaf0"/></dir><dir name="controllers"><file name="VarnishController.php" hash="507120591d2e0ad6b33e7816f2c654cd"/></dir><dir name="etc"><file name="config.xml" hash="02e4540714fd10428c614471a7c153f0"/><file name="magento.vcl" hash="a247cd54d96f824bacacda6704ad5285"/><file name="system.xml" hash="4ffc1ded6a50a61aeaf932c5a3556a28"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Made_Cache.xml" hash="4cf53cc9b4e525eb560f7fe1278d96bd"/></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="madecache.xml" hash="2dc3f6f914a30e1a57a7576585e58209"/></dir></dir></dir></dir></target></contents>
|
24 |
<compatible/>
|
25 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
26 |
</package>
|