1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Nexcess.net Turpentine Extension for Magento |
5
|
|
|
* Copyright (C) 2012 Nexcess.net L.L.C. |
6
|
|
|
* |
7
|
|
|
* This program is free software; you can redistribute it and/or modify |
8
|
|
|
* it under the terms of the GNU General Public License as published by |
9
|
|
|
* the Free Software Foundation; either version 2 of the License, or |
10
|
|
|
* (at your option) any later version. |
11
|
|
|
* |
12
|
|
|
* This program is distributed in the hope that it will be useful, |
13
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15
|
|
|
* GNU General Public License for more details. |
16
|
|
|
* |
17
|
|
|
* You should have received a copy of the GNU General Public License along |
18
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc., |
19
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
20
|
|
|
*/ |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Most of this is taken from @link https://github.com/huguesalary/Magento-Varnish |
24
|
|
|
*/ |
25
|
|
|
|
26
|
|
|
class Nexcessnet_Turpentine_Model_Observer_Ban extends Varien_Event_Observer { |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Cache the varnish admin object |
30
|
|
|
* @var Nexcessnet_Turpentine_Model_Varnish_Admin |
31
|
|
|
*/ |
32
|
|
|
protected $_varnishAdmin = null; |
33
|
|
|
/** |
34
|
|
|
* Flag to prevent doing the ESI cache clear more than once per request |
35
|
|
|
* @var boolean |
36
|
|
|
*/ |
37
|
|
|
protected $_esiClearFlag = array(); |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Clear the ESI block cache for a specific client |
41
|
|
|
* |
42
|
|
|
* Events: |
43
|
|
|
* the events are applied dynamically according to what events are set |
44
|
|
|
* for the various blocks' esi policies |
45
|
|
|
* |
46
|
|
|
* @param Varien_Object $eventObject |
47
|
|
|
* @return null |
48
|
|
|
*/ |
49
|
|
|
public function banClientEsiCache($eventObject) { |
50
|
|
|
$eventName = $eventObject->getEvent()->getName(); |
51
|
|
|
if (Mage::helper('turpentine/esi')->getEsiEnabled() && |
52
|
|
|
! in_array($eventName, $this->_esiClearFlag)) { |
53
|
|
|
$sessionId = Mage::app()->getRequest()->getCookie('frontend'); |
54
|
|
|
if ($sessionId) { |
55
|
|
|
$result = $this->_getVarnishAdmin()->flushExpression( |
56
|
|
|
'obj.http.X-Varnish-Session', '==', $sessionId, |
57
|
|
|
'&&', 'obj.http.X-Turpentine-Flush-Events', '~', |
58
|
|
|
$eventName ); |
59
|
|
|
Mage::dispatchEvent('turpentine_ban_client_esi_cache', $result); |
60
|
|
|
if ($this->_checkResult($result)) { |
61
|
|
|
Mage::helper('turpentine/debug') |
62
|
|
|
->logDebug('Cleared ESI cache for client (%s) on event: %s', |
63
|
|
|
$sessionId, $eventName); |
64
|
|
|
} else { |
65
|
|
|
Mage::helper('turpentine/debug') |
66
|
|
|
->logWarn( |
67
|
|
|
'Failed to clear Varnish ESI cache for client: %s', |
68
|
|
|
$sessionId ); |
69
|
|
|
} |
70
|
|
|
} |
71
|
|
|
$this->_esiClearFlag[] = $eventName; |
72
|
|
|
} |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Ban a specific product page from the cache |
77
|
|
|
* |
78
|
|
|
* Events: |
79
|
|
|
* catalog_product_save_commit_after |
80
|
|
|
* |
81
|
|
|
* @param Varien_Object $eventObject |
82
|
|
|
* @return null |
83
|
|
|
*/ |
84
|
|
|
public function banProductPageCache($eventObject) { |
85
|
|
|
if (Mage::helper('turpentine/varnish')->getVarnishEnabled()) { |
86
|
|
|
$banHelper = Mage::helper('turpentine/ban'); |
87
|
|
|
$product = $eventObject->getProduct(); |
88
|
|
|
$urlPattern = $banHelper->getProductBanRegex($product); |
89
|
|
|
$result = $this->_getVarnishAdmin()->flushUrl($urlPattern); |
90
|
|
|
Mage::dispatchEvent('turpentine_ban_product_cache', $result); |
91
|
|
|
$cronHelper = Mage::helper('turpentine/cron'); |
92
|
|
View Code Duplication |
if ($this->_checkResult($result) && |
|
|
|
|
93
|
|
|
$cronHelper->getCrawlerEnabled()) { |
94
|
|
|
$cronHelper->addProductToCrawlerQueue($product); |
95
|
|
|
foreach ($banHelper->getParentProducts($product) |
96
|
|
|
as $parentProduct) { |
97
|
|
|
$cronHelper->addProductToCrawlerQueue($parentProduct); |
98
|
|
|
} |
99
|
|
|
} |
100
|
|
|
} |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* Ban a product page from the cache if it's stock status changed |
105
|
|
|
* |
106
|
|
|
* Events: |
107
|
|
|
* cataloginventory_stock_item_save_after |
108
|
|
|
* |
109
|
|
|
* @param Varien_Object $eventObject |
110
|
|
|
* @return null |
111
|
|
|
*/ |
112
|
|
|
public function banProductPageCacheCheckStock($eventObject) { |
113
|
|
|
if (Mage::helper('turpentine/varnish')->getVarnishEnabled()) { |
114
|
|
|
$item = $eventObject->getItem(); |
115
|
|
|
if ($item->getStockStatusChangedAutomatically() || |
116
|
|
|
($item->getOriginalInventoryQty() <= 0 && |
117
|
|
|
$item->getQty() > 0 && |
118
|
|
|
$item->getQtyCorrection() > 0)) { |
119
|
|
|
$banHelper = Mage::helper('turpentine/ban'); |
120
|
|
|
$cronHelper = Mage::helper('turpentine/cron'); |
121
|
|
|
$product = Mage::getModel('catalog/product') |
122
|
|
|
->load($item->getProductId()); |
123
|
|
|
$urlPattern = $banHelper->getProductBanRegex($product); |
124
|
|
|
$result = $this->_getVarnishAdmin()->flushUrl($urlPattern); |
125
|
|
|
Mage::dispatchEvent('turpentine_ban_product_cache_check_stock', |
126
|
|
|
$result); |
127
|
|
View Code Duplication |
if ($this->_checkResult($result) && |
|
|
|
|
128
|
|
|
$cronHelper->getCrawlerEnabled()) { |
129
|
|
|
$cronHelper->addProductToCrawlerQueue($product); |
130
|
|
|
foreach ($banHelper->getParentProducts($product) |
131
|
|
|
as $parentProduct) { |
132
|
|
|
$cronHelper->addProductToCrawlerQueue($parentProduct); |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Ban a category page, and any subpages on save |
141
|
|
|
* |
142
|
|
|
* Events: |
143
|
|
|
* catalog_category_save_commit_after |
144
|
|
|
* |
145
|
|
|
* @param Varien_Object $eventObject |
146
|
|
|
* @return null |
147
|
|
|
*/ |
148
|
|
View Code Duplication |
public function banCategoryCache($eventObject) { |
|
|
|
|
149
|
|
|
if (Mage::helper('turpentine/varnish')->getVarnishEnabled()) { |
150
|
|
|
$category = $eventObject->getCategory(); |
151
|
|
|
$result = $this->_getVarnishAdmin()->flushUrl($category->getUrlKey()); |
152
|
|
|
Mage::dispatchEvent('turpentine_ban_category_cache', $result); |
153
|
|
|
$cronHelper = Mage::helper('turpentine/cron'); |
154
|
|
|
if ($this->_checkResult($result) && |
155
|
|
|
$cronHelper->getCrawlerEnabled()) { |
156
|
|
|
$cronHelper->addCategoryToCrawlerQueue($category); |
157
|
|
|
} |
158
|
|
|
} |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Clear the media (CSS/JS) cache, corresponds to the buttons on the cache |
163
|
|
|
* page in admin |
164
|
|
|
* |
165
|
|
|
* Events: |
166
|
|
|
* clean_media_cache_after |
167
|
|
|
* |
168
|
|
|
* @param Varien_Object $eventObject |
169
|
|
|
* @return null |
170
|
|
|
*/ |
171
|
|
View Code Duplication |
public function banMediaCache($eventObject) { |
|
|
|
|
172
|
|
|
if (Mage::helper('turpentine/varnish')->getVarnishEnabled()) { |
173
|
|
|
$result = $this->_getVarnishAdmin()->flushUrl('media/(?:js|css)/'); |
174
|
|
|
Mage::dispatchEvent('turpentine_ban_media_cache', $result); |
175
|
|
|
$this->_checkResult($result); |
176
|
|
|
} |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Flush catalog images cache, corresponds to same button in admin cache |
181
|
|
|
* management page |
182
|
|
|
* |
183
|
|
|
* Events: |
184
|
|
|
* clean_catalog_images_cache_after |
185
|
|
|
* |
186
|
|
|
* @param Varien_Object $eventObject |
187
|
|
|
* @return null |
188
|
|
|
*/ |
189
|
|
View Code Duplication |
public function banCatalogImagesCache($eventObject) { |
|
|
|
|
190
|
|
|
if (Mage::helper('turpentine/varnish')->getVarnishEnabled()) { |
191
|
|
|
$result = $this->_getVarnishAdmin()->flushUrl( |
192
|
|
|
'media/catalog/product/cache/' ); |
193
|
|
|
Mage::dispatchEvent('turpentine_ban_catalog_images_cache', $result); |
194
|
|
|
$this->_checkResult($result); |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Ban a specific CMS page from cache after edit |
200
|
|
|
* |
201
|
|
|
* Events: |
202
|
|
|
* cms_page_save_commit_after |
203
|
|
|
* |
204
|
|
|
* @param Varien_Object $eventObject |
205
|
|
|
* @return null |
206
|
|
|
*/ |
207
|
|
View Code Duplication |
public function banCmsPageCache($eventObject) { |
|
|
|
|
208
|
|
|
if (Mage::helper('turpentine/varnish')->getVarnishEnabled()) { |
209
|
|
|
$pageId = $eventObject->getDataObject()->getIdentifier(); |
210
|
|
|
$result = $this->_getVarnishAdmin()->flushUrl($pageId.'(?:\.html?)?\/?$'); |
211
|
|
|
Mage::dispatchEvent('turpentine_ban_cms_page_cache', $result); |
212
|
|
|
$cronHelper = Mage::helper('turpentine/cron'); |
213
|
|
|
if ($this->_checkResult($result) && |
214
|
|
|
$cronHelper->getCrawlerEnabled()) { |
215
|
|
|
$cronHelper->addCmsPageToCrawlerQueue($pageId); |
216
|
|
|
} |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
/** |
221
|
|
|
* Ban a specific CMS page revision from cache after edit (enterprise edition only) |
222
|
|
|
* Events: |
223
|
|
|
* enterprise_cms_revision_save_commit_after |
224
|
|
|
* |
225
|
|
|
* @param Varien_Object $eventObject |
226
|
|
|
* @return null |
227
|
|
|
*/ |
228
|
|
|
public function banCmsPageRevisionCache($eventObject) { |
229
|
|
|
if (Mage::helper('turpentine/varnish')->getVarnishEnabled()) { |
230
|
|
|
$pageId = $eventObject->getDataObject()->getPageId(); |
231
|
|
|
$page = Mage::getModel('cms/page')->load($pageId); |
232
|
|
|
|
233
|
|
|
// Don't do anything if the page isn't found. |
234
|
|
|
if ( ! $page) { |
235
|
|
|
return; |
236
|
|
|
} |
237
|
|
|
$pageIdentifier = $page->getIdentifier(); |
238
|
|
|
$result = $this->_getVarnishAdmin()->flushUrl($pageIdentifier.'(?:\.html?)?$'); |
239
|
|
|
Mage::dispatchEvent('turpentine_ban_cms_page_cache', $result); |
240
|
|
|
$cronHelper = Mage::helper('turpentine/cron'); |
241
|
|
|
if ($this->_checkResult($result) && |
242
|
|
|
$cronHelper->getCrawlerEnabled()) { |
243
|
|
|
$cronHelper->addCmsPageToCrawlerQueue($pageIdentifier); |
244
|
|
|
} |
245
|
|
|
} |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* Do a full cache flush, corresponds to "Flush Magento Cache" and |
250
|
|
|
* "Flush Cache Storage" buttons in admin > cache management |
251
|
|
|
* |
252
|
|
|
* Events: |
253
|
|
|
* adminhtml_cache_flush_system |
254
|
|
|
* adminhtml_cache_flush_all |
255
|
|
|
* |
256
|
|
|
* @param Varien_Object $eventObject |
257
|
|
|
* @return null |
258
|
|
|
*/ |
259
|
|
View Code Duplication |
public function banAllCache($eventObject) { |
|
|
|
|
260
|
|
|
if (Mage::helper('turpentine/varnish')->getVarnishEnabled()) { |
261
|
|
|
$result = $this->_getVarnishAdmin()->flushAll(); |
262
|
|
|
Mage::dispatchEvent('turpentine_ban_all_cache', $result); |
263
|
|
|
$this->_checkResult($result); |
264
|
|
|
} |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* Do a flush on the ESI blocks |
269
|
|
|
* |
270
|
|
|
* Events: |
271
|
|
|
* adminhtml_cache_refresh_type |
272
|
|
|
* |
273
|
|
|
* @param Varien_Object $eventObject |
274
|
|
|
* @return null |
275
|
|
|
*/ |
276
|
|
|
public function banCacheType($eventObject) { |
277
|
|
|
switch ($eventObject->getType()) { |
278
|
|
|
//note this is the name of the container xml tag in config.xml, |
279
|
|
|
// **NOT** the cache tag name |
280
|
|
|
case Mage::helper('turpentine/esi')->getMageCacheName(): |
281
|
|
|
if (Mage::helper('turpentine/esi')->getEsiEnabled()) { |
282
|
|
|
$result = $this->_getVarnishAdmin()->flushUrl( |
283
|
|
|
'/turpentine/esi/getBlock/' ); |
284
|
|
|
Mage::dispatchEvent('turpentine_ban_esi_cache', $result); |
285
|
|
|
$this->_checkResult($result); |
286
|
|
|
} |
287
|
|
|
break; |
288
|
|
|
case Mage::helper('turpentine/varnish')->getMageCacheName(): |
289
|
|
|
$this->banAllCache($eventObject); |
290
|
|
|
break; |
291
|
|
|
} |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* Ban a product's reviews page |
296
|
|
|
* |
297
|
|
|
* @param Varien_Object $eventObject |
298
|
|
|
* @return bool |
299
|
|
|
*/ |
300
|
|
|
public function banProductReview($eventObject) { |
301
|
|
|
if (Mage::helper('turpentine/varnish')->getVarnishEnabled()) { |
302
|
|
|
$patterns = array(); |
303
|
|
|
/* @var $review \Mage_Review_Model_Review*/ |
304
|
|
|
$review = $eventObject->getObject(); |
305
|
|
|
|
306
|
|
|
/* @var $productCollection \Mage_Review_Model_Resource_Review_Product_Collection*/ |
307
|
|
|
$productCollection = $review->getProductCollection(); |
308
|
|
|
|
309
|
|
|
$products = $productCollection->addEntityFilter((int) $review->getEntityPkValue())->getItems(); |
310
|
|
|
|
311
|
|
|
$productIds = array_unique(array_map( |
312
|
|
|
create_function('$p', 'return $p->getEntityId();'), |
313
|
|
|
$products )); |
314
|
|
|
$patterns[] = sprintf('/review/product/list/id/(?:%s)/category/', |
315
|
|
|
implode('|', array_unique($productIds))); |
316
|
|
|
$patterns[] = sprintf('/review/product/view/id/%d/', |
317
|
|
|
$review->getEntityId()); |
318
|
|
|
$productPatterns = array(); |
319
|
|
|
foreach ($products as $p) { |
320
|
|
|
$urlKey = $p->getUrlModel()->formatUrlKey($p->getName()); |
321
|
|
|
if ($urlKey) { |
322
|
|
|
$productPatterns[] = $urlKey; |
323
|
|
|
} |
324
|
|
|
} |
325
|
|
|
if ( ! empty($productPatterns)) { |
326
|
|
|
$productPatterns = array_unique($productPatterns); |
327
|
|
|
$patterns[] = sprintf('(?:%s)', implode('|', $productPatterns)); |
328
|
|
|
} |
329
|
|
|
$urlPattern = implode('|', $patterns); |
330
|
|
|
|
331
|
|
|
$result = $this->_getVarnishAdmin()->flushUrl($urlPattern); |
332
|
|
|
return $this->_checkResult($result); |
333
|
|
|
} |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
/** |
337
|
|
|
* Check a result from varnish admin action, log if result has errors |
338
|
|
|
* |
339
|
|
|
* @param array $result stored as $socketName => $result |
340
|
|
|
* @return bool |
341
|
|
|
*/ |
342
|
|
|
protected function _checkResult($result) { |
343
|
|
|
$rvalue = true; |
344
|
|
|
foreach ($result as $socketName => $value) { |
345
|
|
|
if ($value !== true) { |
346
|
|
|
Mage::helper('turpentine/debug')->logWarn( |
347
|
|
|
'Error in Varnish action result for server [%s]: %s', |
348
|
|
|
$socketName, $value ); |
349
|
|
|
$rvalue = false; |
350
|
|
|
} |
351
|
|
|
} |
352
|
|
|
return $rvalue; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* Get the varnish admin socket |
357
|
|
|
* |
358
|
|
|
* @return Nexcessnet_Turpentine_Model_Varnish_Admin |
359
|
|
|
*/ |
360
|
|
|
protected function _getVarnishAdmin() { |
361
|
|
|
if (is_null($this->_varnishAdmin)) { |
362
|
|
|
$this->_varnishAdmin = Mage::getModel('turpentine/varnish_admin'); |
363
|
|
|
} |
364
|
|
|
return $this->_varnishAdmin; |
365
|
|
|
} |
366
|
|
|
} |
367
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.