Version Notes
Compatibility updates in data gathering
Download this release
Release Info
Developer | Radoslaw Gliniecki |
Extension | cartdefender_actions |
Version | 2.1.8 |
Comparing to | |
See all releases |
Code changes from version 2.1.0 to 2.1.8
- app/code/community/CartDefender/Actions/Helper/Data.php +44 -1
- app/code/community/CartDefender/Actions/Helper/Logger.php +1 -1
- app/code/community/CartDefender/Actions/Model/Api.php +266 -0
- app/code/community/CartDefender/Actions/Model/Api/V2.php +6 -0
- app/code/community/CartDefender/Actions/Model/AsyncLocalSender.php +157 -22
- app/code/community/CartDefender/Actions/Model/CorrelationIdManager.php +10 -0
- app/code/community/CartDefender/Actions/Model/EventAsyncLocalSender.php +8 -2
- app/code/community/CartDefender/Actions/Model/EventBuilder.php +40 -6
- app/code/community/CartDefender/Actions/Model/Observer.php +6 -3
- app/code/community/CartDefender/Actions/Model/System/Config/Source/Transport.php +20 -0
- app/code/community/CartDefender/Actions/controllers/CartDefenderSenderController.php +17 -3
- app/code/community/CartDefender/Actions/etc/api.xml +38 -0
- app/code/community/CartDefender/Actions/etc/config.xml +5 -77
- app/code/community/CartDefender/Actions/etc/system.xml +44 -12
- app/design/frontend/base/default/template/actions/script.phtml +1 -1
- package.xml +5 -5
app/code/community/CartDefender/Actions/Helper/Data.php
CHANGED
@@ -135,6 +135,47 @@ class CartDefender_Actions_Helper_Data extends Mage_Core_Helper_Abstract
|
|
135 |
return $sendKey;
|
136 |
}
|
137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
/**
|
139 |
* Returns an array containing Cart Defender configuration settings.
|
140 |
*
|
@@ -153,7 +194,9 @@ class CartDefender_Actions_Helper_Data extends Mage_Core_Helper_Abstract
|
|
153 |
'test_server_url_start' => $this->getTestServerUrlStart(),
|
154 |
'use_raw_test_url_for_biz_api' =>
|
155 |
$this->getUseRawTestUrlForBizApi(),
|
156 |
-
'send_key' => $this->getSendKey()
|
|
|
|
|
157 |
);
|
158 |
}
|
159 |
return $data;
|
135 |
return $sendKey;
|
136 |
}
|
137 |
|
138 |
+
/**
|
139 |
+
* Obtains the url to access the synchronous
|
140 |
+
* sender PHP script, used to send business events to Cart Defender
|
141 |
+
* servers.
|
142 |
+
*
|
143 |
+
* @return string URL needed to access the sender script.
|
144 |
+
*/
|
145 |
+
public function getSenderControllerUrl()
|
146 |
+
{
|
147 |
+
$senderControllerUrl = Mage::getStoreConfig('actions/settings/sender_controller_url');
|
148 |
+
if (empty($senderControllerUrl)) {
|
149 |
+
$senderControllerUrl = Mage::getUrl(
|
150 |
+
'cartdefender/CartDefenderSender/send',
|
151 |
+
array('_secure' => true)
|
152 |
+
);
|
153 |
+
Mage::getConfig()->saveConfig(
|
154 |
+
'actions/settings/sender_controller_url',
|
155 |
+
$senderControllerUrl,
|
156 |
+
'default',
|
157 |
+
0
|
158 |
+
);
|
159 |
+
}
|
160 |
+
return $senderControllerUrl;
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Obtains the selected transport method for store's data
|
165 |
+
*
|
166 |
+
* @return string code name of the selected transport method
|
167 |
+
*/
|
168 |
+
public function getTransportMethod()
|
169 |
+
{
|
170 |
+
$transportMethod = Mage::getStoreConfig('actions/settings/transport_method');
|
171 |
+
if (empty($transportMethod)) {
|
172 |
+
$transportMethod = CartDefender_Actions_Model_System_Config_Source_Transport::CURL_PROCESS;
|
173 |
+
Mage::getConfig()->saveConfig('actions/settings/transport_method', $transportMethod, 'default', 0);
|
174 |
+
}
|
175 |
+
return $transportMethod;
|
176 |
+
}
|
177 |
+
|
178 |
+
|
179 |
/**
|
180 |
* Returns an array containing Cart Defender configuration settings.
|
181 |
*
|
194 |
'test_server_url_start' => $this->getTestServerUrlStart(),
|
195 |
'use_raw_test_url_for_biz_api' =>
|
196 |
$this->getUseRawTestUrlForBizApi(),
|
197 |
+
'send_key' => $this->getSendKey(),
|
198 |
+
'sender_controller_url' => $this->getSenderControllerUrl(),
|
199 |
+
'transport_method' => $this->getTransportMethod()
|
200 |
);
|
201 |
}
|
202 |
return $data;
|
app/code/community/CartDefender/Actions/Helper/Logger.php
CHANGED
@@ -29,7 +29,7 @@ class CartDefender_Actions_Helper_Logger extends Mage_Core_Helper_Abstract
|
|
29 |
$this->enabled = ($settings ? $settings['test'] : null);
|
30 |
}
|
31 |
if ($this->enabled) {
|
32 |
-
Mage::log('[CD] [' . $function . '] ' . $message);
|
33 |
}
|
34 |
}
|
35 |
}
|
29 |
$this->enabled = ($settings ? $settings['test'] : null);
|
30 |
}
|
31 |
if ($this->enabled) {
|
32 |
+
Mage::log('[CD] [' . $function . '] ' . $message, null, 'cartdefender.log');
|
33 |
}
|
34 |
}
|
35 |
}
|
app/code/community/CartDefender/Actions/Model/Api.php
ADDED
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class CartDefender_Actions_Model_Api extends Mage_Api_Model_Resource_Abstract
|
4 |
+
{
|
5 |
+
|
6 |
+
private $storeId;
|
7 |
+
|
8 |
+
private $itemStartIndex;
|
9 |
+
|
10 |
+
private $itemCount;
|
11 |
+
|
12 |
+
private $excludeOutOfStock;
|
13 |
+
|
14 |
+
private $excludeDisabled;
|
15 |
+
|
16 |
+
private $excludeInvisible;
|
17 |
+
|
18 |
+
private $productIds;
|
19 |
+
|
20 |
+
private $store;
|
21 |
+
|
22 |
+
public function getVersion ()
|
23 |
+
{
|
24 |
+
// Get path to config file
|
25 |
+
$filePath = realpath(dirname(__FILE__)) . '/../etc/config.xml';
|
26 |
+
|
27 |
+
// Open the config file -- ignore errors
|
28 |
+
$configFileContents = @file_get_contents($filePath);
|
29 |
+
|
30 |
+
// Return message if config file could not be opened
|
31 |
+
if (empty($configFileContents) == true) {
|
32 |
+
return 'Could not open config.xml';
|
33 |
+
}
|
34 |
+
|
35 |
+
// Get version from config file
|
36 |
+
$pattern = '|<version>([^<]+)|i';
|
37 |
+
if (preg_match($pattern, $configFileContents, $matches) !== 1) {
|
38 |
+
return 'Could not get version from config.xml';
|
39 |
+
}
|
40 |
+
|
41 |
+
// Return the version string
|
42 |
+
return $matches[1];
|
43 |
+
}
|
44 |
+
|
45 |
+
private function initialize () // TODO add logging and CD API exception
|
46 |
+
{
|
47 |
+
// Increase maximum execution time to 4 hours
|
48 |
+
ini_set('max_execution_time', 14400);
|
49 |
+
|
50 |
+
// Check format of the item start and count
|
51 |
+
if (0 == preg_match('|^\d+$|', $this->itemStartIndex)) {
|
52 |
+
Mage::throwException(
|
53 |
+
'The specified item start index is not formatted correctly: ' .
|
54 |
+
$this->itemStartIndex);
|
55 |
+
}
|
56 |
+
if (0 == preg_match('|^\d+$|', $this->itemCount)) {
|
57 |
+
Mage::throwException(
|
58 |
+
'The specified item count is not formatted correctly: ' .
|
59 |
+
$this->itemCount);
|
60 |
+
}
|
61 |
+
// Check range of the item start and ccount
|
62 |
+
$this->itemStartIndex = intval($this->itemStartIndex);
|
63 |
+
$this->itemCount = intval($this->itemCount);
|
64 |
+
if ($this->itemStartIndex < 0) {
|
65 |
+
Mage::throwException(
|
66 |
+
'The specified item start index is less than zero: ' .
|
67 |
+
$this->itemStartIndex);
|
68 |
+
}
|
69 |
+
if ($this->itemCount <= 0) {
|
70 |
+
Mage::throwException(
|
71 |
+
'The specified item count is less than or equal to zero: ' .
|
72 |
+
$this->itemCount);
|
73 |
+
}
|
74 |
+
|
75 |
+
// Check format of the storeId
|
76 |
+
if (0 == preg_match('|^\d+$|', $this->storeId)) {
|
77 |
+
Mage::throwException(
|
78 |
+
'The specified Store is not formatted correctly: ' .
|
79 |
+
$this->storeId);
|
80 |
+
}
|
81 |
+
$this->storeId = intval($this->storeId);
|
82 |
+
try {
|
83 |
+
$this->store = Mage::app()->getStore($this->storeId);
|
84 |
+
} catch (Exception $e) {
|
85 |
+
Mage::throwException(
|
86 |
+
'Error getting store with ID ' . $this->storeId .
|
87 |
+
". The store probably does not exist. " .
|
88 |
+
get_class($e) . " " . $e->getMessage());
|
89 |
+
}
|
90 |
+
|
91 |
+
$this->excludeDisabled = (bool) $this->excludeDisabled;
|
92 |
+
$this->excludeInvisible = (bool) $this->excludeInvisible;
|
93 |
+
|
94 |
+
if (! is_array($this->productIds)) {
|
95 |
+
$this->productIds = null;
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
public function export ($storeId = 0, $itemStartIndex = 0, $itemCount = 100000,
|
100 |
+
$excludeDisabled = true, $excludeInvisible = true, $productIds = null)
|
101 |
+
{
|
102 |
+
$this->storeId = $storeId;
|
103 |
+
$this->itemStartIndex = $itemStartIndex;
|
104 |
+
$this->itemCount = $itemCount;
|
105 |
+
$this->excludeDisabled = $excludeDisabled;
|
106 |
+
$this->excludeInvisible = $excludeInvisible;
|
107 |
+
$this->productIds = $productIds;
|
108 |
+
|
109 |
+
$this->initialize();
|
110 |
+
|
111 |
+
// TODO Add FINAL price after rules applied
|
112 |
+
// TODO Check IMAGE URLS
|
113 |
+
|
114 |
+
try {
|
115 |
+
$collection = Mage::getResourceModel('catalog/product_collection')->setPage(
|
116 |
+
$itemStartIndex, $itemCount)
|
117 |
+
->addAttributeToSelect('entity_id')
|
118 |
+
->setOrder('entity_id', 'ASC')
|
119 |
+
->addAttributeToSelect('sku')
|
120 |
+
->addAttributeToSelect('status')
|
121 |
+
->addAttributeToSelect('visibility')
|
122 |
+
->addAttributeToSelect('created_at')
|
123 |
+
->addAttributeToSelect('updated_at')
|
124 |
+
->addAttributeToSelect('product_url')
|
125 |
+
->addAttributeToSelect('type_id');
|
126 |
+
|
127 |
+
if ($this->excludeInvisible === true) {
|
128 |
+
$collection->addFieldToFilter('visibility',
|
129 |
+
array(
|
130 |
+
'nlike' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE
|
131 |
+
));
|
132 |
+
}
|
133 |
+
|
134 |
+
if (is_array($this->productIds)) {
|
135 |
+
$collection->addFieldToFilter('entity_id',
|
136 |
+
array(
|
137 |
+
$this->productIds
|
138 |
+
));
|
139 |
+
}
|
140 |
+
|
141 |
+
if ($this->excludeDisabled === true) {
|
142 |
+
$collection->addAttributeToFilter('status', 1); // enabled
|
143 |
+
}
|
144 |
+
|
145 |
+
if (Mage::helper('catalog')->isModuleEnabled(
|
146 |
+
'Mage_CatalogInventory')) {
|
147 |
+
$collection->joinField('qty', 'cataloginventory/stock_item',
|
148 |
+
'qty', 'product_id=entity_id', '{{table}}.stock_id=1',
|
149 |
+
'left');
|
150 |
+
}
|
151 |
+
|
152 |
+
if ($this->store->getId()) {
|
153 |
+
$collection->addStoreFilter($this->store);
|
154 |
+
$collection->joinAttribute('name', 'catalog_product/name',
|
155 |
+
'entity_id', null, 'inner', $this->store->getId());
|
156 |
+
$collection->joinAttribute('description',
|
157 |
+
'catalog_product/description', 'entity_id', null,
|
158 |
+
'inner', $this->store->getId());
|
159 |
+
$collection->joinAttribute('short_description',
|
160 |
+
'catalog_product/short_description', 'entity_id', null,
|
161 |
+
'inner', $this->store->getId());
|
162 |
+
$collection->joinAttribute('image', 'catalog_product/image',
|
163 |
+
'entity_id', null, 'inner', $this->store->getId());
|
164 |
+
$collection->joinAttribute('price', 'catalog_product/price',
|
165 |
+
'entity_id', null, 'left', $this->store->getId());
|
166 |
+
$collection->joinAttribute('special_price',
|
167 |
+
'catalog_product/price', 'entity_id', null, 'left',
|
168 |
+
$this->store->getId());
|
169 |
+
} else {
|
170 |
+
$collection->addAttributeToSelect(
|
171 |
+
array(
|
172 |
+
'name',
|
173 |
+
'description',
|
174 |
+
'short_description',
|
175 |
+
'image',
|
176 |
+
'price',
|
177 |
+
'special_price'
|
178 |
+
));
|
179 |
+
}
|
180 |
+
$mediaConfig = Mage::getModel('catalog/product_media_config');
|
181 |
+
|
182 |
+
$productArray = array(
|
183 |
+
'entity_id' => '',
|
184 |
+
'sku' => '',
|
185 |
+
'status' => '',
|
186 |
+
'visibility' => '',
|
187 |
+
'created_at' => '',
|
188 |
+
'updated_at' => '',
|
189 |
+
'product_url' => '',
|
190 |
+
'type_id' => '',
|
191 |
+
'qty' => '',
|
192 |
+
'name' => '',
|
193 |
+
'description' => '',
|
194 |
+
'short_description' => '',
|
195 |
+
'base_image' => '',
|
196 |
+
'small_image' => '',
|
197 |
+
'thumbnail_image' => '',
|
198 |
+
'price' => '',
|
199 |
+
'special_price' => '',
|
200 |
+
'parent_id' => ''
|
201 |
+
);
|
202 |
+
|
203 |
+
$content .= implode(',', array_keys($productArray));
|
204 |
+
$content .= "\n";
|
205 |
+
|
206 |
+
foreach ($collection as $product) {
|
207 |
+
if ("no_selection" == $product->getImage()) {
|
208 |
+
$productImage = "";
|
209 |
+
} else {
|
210 |
+
$productImage = $mediaConfig->getMediaUrl(
|
211 |
+
$product->getImage());
|
212 |
+
}
|
213 |
+
|
214 |
+
$parentIdsList = '';
|
215 |
+
if ($product->getTypeId() ==
|
216 |
+
Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) {
|
217 |
+
$parentIds = Mage::getModel('catalog/product_type_grouped')->getParentIdsByChild(
|
218 |
+
$product->getId());
|
219 |
+
if (! $parentIds) {
|
220 |
+
$parentIds = Mage::getModel(
|
221 |
+
'catalog/product_type_configurable')->getParentIdsByChild(
|
222 |
+
$product->getId());
|
223 |
+
}
|
224 |
+
if (isset($parentIds[0])) {
|
225 |
+
$parentIdsList = implode(',', $parentIds);
|
226 |
+
}
|
227 |
+
}
|
228 |
+
$productArray['entity_id'] = $product->getId();
|
229 |
+
$productArray['sku'] = $product->getSku();
|
230 |
+
$productArray['status'] = $product->getStatus();
|
231 |
+
$productArray['visibility'] = $product->getVisibility();
|
232 |
+
$productArray['created_at'] = $product->getCreatedAt();
|
233 |
+
$productArray['updated_at'] = $product->getUpdatedAt();
|
234 |
+
$productArray['product_url'] = $product->setStoreId(
|
235 |
+
$this->store->getId())
|
236 |
+
->getProductUrl();
|
237 |
+
$productArray['type_id'] = $product->getTypeId();
|
238 |
+
$productArray['qty'] = $product->getQty();
|
239 |
+
$productArray['name'] = $product->getName();
|
240 |
+
$productArray['description'] = $product->getDescription();
|
241 |
+
$productArray['short_description'] = $product->getShortDescription();
|
242 |
+
$productArray['base_image'] = $productImage;
|
243 |
+
$productArray['small_image'] = $mediaConfig->getMediaUrl(
|
244 |
+
$product->getSmallImage());
|
245 |
+
$productArray['thumbnail_image'] = $mediaConfig->getMediaUrl(
|
246 |
+
$product->getThumbnail());
|
247 |
+
$productArray['price'] = $product->getPrice();
|
248 |
+
$productArray['special_price'] = $product->getSpecialPrice();
|
249 |
+
$productArray['parent_id'] = $parentIdsList; // get parent prod
|
250 |
+
// ids
|
251 |
+
|
252 |
+
// Escape double quotes
|
253 |
+
$escapedProductArray = str_replace('"', '""', $productArray);
|
254 |
+
|
255 |
+
// Write each product to the file
|
256 |
+
$content .= '"';
|
257 |
+
$content .= implode('","', $escapedProductArray);
|
258 |
+
$content .= "\"\n";
|
259 |
+
}
|
260 |
+
} catch (Exception $e) {
|
261 |
+
return 'The query resulted in an exception: ' . get_class($e) . ' ' .
|
262 |
+
$e->getMessage();
|
263 |
+
}
|
264 |
+
return $content;
|
265 |
+
}
|
266 |
+
}
|
app/code/community/CartDefender/Actions/Model/Api/V2.php
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class CartDefender_Actions_Model_Api_V2 extends CartDefender_Actions_Model_Api
|
4 |
+
{
|
5 |
+
|
6 |
+
}
|
app/code/community/CartDefender/Actions/Model/AsyncLocalSender.php
CHANGED
@@ -1,5 +1,7 @@
|
|
1 |
<?php
|
2 |
|
|
|
|
|
3 |
/**
|
4 |
* Asynchronous sender of text data to "synchronous remote sender" (another
|
5 |
* Cart Defender PHP script available on localhost), which then sends the
|
@@ -26,6 +28,99 @@ class CartDefender_Actions_Model_AsyncLocalSender extends Varien_Object
|
|
26 |
$this->logger = Mage::helper('actions/logger');
|
27 |
}
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
/**
|
30 |
* Asynchronously sends the data passed to "synchronous remote sender"
|
31 |
* (another Cart Defender PHP script available on localhost),
|
@@ -49,31 +144,58 @@ class CartDefender_Actions_Model_AsyncLocalSender extends Varien_Object
|
|
49 |
* by Cart Defender backend.
|
50 |
* @return void
|
51 |
*/
|
52 |
-
|
53 |
{
|
54 |
-
$remoteSenderConf = $this->getRemoteSenderConf();
|
55 |
$request = $this->createRequest(
|
56 |
$remoteSenderConf['path'],
|
57 |
$remoteSenderConf['host'],
|
58 |
$data,
|
59 |
$sequenceNo,
|
60 |
-
$correlationId
|
|
|
61 |
);
|
62 |
$socket = fsockopen(
|
63 |
$remoteSenderConf['protocol'] . $remoteSenderConf['host'],
|
64 |
$remoteSenderConf['port'],
|
65 |
$errno,
|
66 |
$errstr,
|
67 |
-
0.
|
68 |
);
|
69 |
-
$
|
70 |
-
|
71 |
-
$this->logger->log('AsyncLocalSender->send', ($success ? 'Success.'
|
72 |
-
: ('Error (num: [' . $errno . '], msg: [' . $errstr . '])'))
|
73 |
-
. ' Data: [' . $data . ']');
|
74 |
fclose($socket);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
}
|
76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
/**
|
78 |
* Retrieves the configuration of synchronous remote sender,
|
79 |
* specifically its URL parts.
|
@@ -81,15 +203,12 @@ class CartDefender_Actions_Model_AsyncLocalSender extends Varien_Object
|
|
81 |
* @return array the configuration of synchronous remote sender, with
|
82 |
* entries such as 'protocol', 'host', 'port', 'path'.
|
83 |
*/
|
84 |
-
private function getRemoteSenderConf()
|
85 |
{
|
86 |
// "static" to compute only once and return cached value later.
|
87 |
static $remoteSenderConf = null;
|
88 |
if ($remoteSenderConf === null) {
|
89 |
-
$remoteSenderConf = parse_url(
|
90 |
-
'cartdefender/CartDefenderSender/send',
|
91 |
-
array('_secure' => true)
|
92 |
-
));
|
93 |
if (empty($remoteSenderConf['port'])) {
|
94 |
$remoteSenderConf['port'] =
|
95 |
($remoteSenderConf['scheme'] == 'http') ? 80 : 443;
|
@@ -126,31 +245,47 @@ class CartDefender_Actions_Model_AsyncLocalSender extends Varien_Object
|
|
126 |
$remoteSenderHost,
|
127 |
$data,
|
128 |
$sequenceNo,
|
129 |
-
$correlationId
|
|
|
130 |
) {
|
131 |
-
$settings = Mage::helper('actions')->getSettings();
|
132 |
$queryParams = array(
|
133 |
'sequence_no' => $sequenceNo,
|
134 |
-
'data' => $data,
|
135 |
'is_local_request' => true, // PHP to PHP call within current server
|
136 |
'correlation_id' => $correlationId,
|
137 |
-
'send_key' => $
|
|
|
138 |
);
|
139 |
$postdata = http_build_query($queryParams);
|
140 |
|
141 |
// Note that Carriage Return (\r) characters below are in accordance
|
142 |
// with RFC 2616. See http://stackoverflow.com/questions/5757290 Also,
|
143 |
// note that double quotes let \r & \n be interpreted correctly.
|
144 |
-
|
145 |
$request = "";
|
146 |
$request.= "POST " . $remoteSenderUrlPath . " HTTP/1.1\r\n";
|
147 |
$request.= "Host: " . $remoteSenderHost . "\r\n";
|
148 |
-
$request.= "Content-
|
149 |
-
$request.= "Content-
|
150 |
$request.= "\r\n";
|
151 |
$request.= $postdata;
|
152 |
$request.= "\r\n\r\n";
|
153 |
|
154 |
return $request;
|
155 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
}
|
1 |
<?php
|
2 |
|
3 |
+
use CartDefender_Actions_Helper_Data as CDData;
|
4 |
+
|
5 |
/**
|
6 |
* Asynchronous sender of text data to "synchronous remote sender" (another
|
7 |
* Cart Defender PHP script available on localhost), which then sends the
|
28 |
$this->logger = Mage::helper('actions/logger');
|
29 |
}
|
30 |
|
31 |
+
/**
|
32 |
+
* Sends the data passed to this function using one of the possible
|
33 |
+
* transport methods.
|
34 |
+
*
|
35 |
+
* @param string $data
|
36 |
+
* the data to send.
|
37 |
+
* @param int $sequenceNo
|
38 |
+
* sequence number of the data being sent,
|
39 |
+
* used for logging purposes.
|
40 |
+
* @param string $correlationId
|
41 |
+
* the correlation identifier needed
|
42 |
+
* by Cart Defender backend.
|
43 |
+
* @return void
|
44 |
+
*/
|
45 |
+
public function send($data, $sequenceNo, $correlationId)
|
46 |
+
{
|
47 |
+
$settings = Mage::helper('actions')->getSettings();
|
48 |
+
$localControllerUrl = $settings['sender_controller_url'];
|
49 |
+
if ($settings['transport_method'] ===
|
50 |
+
CartDefender_Actions_Model_System_Config_Source_Transport::ASYNC_SOCKET) {
|
51 |
+
$this->sendAsyncSocket($data, $sequenceNo, $correlationId,
|
52 |
+
$settings['send_key'], $localControllerUrl);
|
53 |
+
} elseif ($settings['transport_method'] ===
|
54 |
+
CartDefender_Actions_Model_System_Config_Source_Transport::CURL_PROCESS) {
|
55 |
+
$this->sendCurl($data, $sequenceNo, $correlationId, //TODO check
|
56 |
+
$settings, $this->getUrl($correlationId, $settings));
|
57 |
+
} elseif ($settings['transport_method'] ===
|
58 |
+
CartDefender_Actions_Model_System_Config_Source_Transport::SYNC_HTTP) {
|
59 |
+
$this->sendSyncHttpClient($data, $sequenceNo, $correlationId,
|
60 |
+
$settings['send_key'], $localControllerUrl);
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Executes an async cURL process to send the data to the Cart Defender servers
|
66 |
+
*
|
67 |
+
*/
|
68 |
+
private function sendCurl($data, $sequenceNo, $correlationId, $settings, $targetUrl)
|
69 |
+
{
|
70 |
+
$apiKey = $settings['api'];
|
71 |
+
$cmd = "curl -u $apiKey: -X POST -H 'Content-Type: application/json'";
|
72 |
+
$cmd .= " -d '$data' " . " -L --post301 --post302 --post303 '$targetUrl'";
|
73 |
+
if ( ! $settings['test']) { // Async when in normal mode (not test)
|
74 |
+
$cmd .= " > /dev/null 2>&1 &";
|
75 |
+
}
|
76 |
+
exec($cmd, $output, $exit);
|
77 |
+
|
78 |
+
Mage::getSingleton('core/session')->setLastEventTime(time());
|
79 |
+
|
80 |
+
$this->logger->log(
|
81 |
+
'AsyncLocalSender->sendCurl', ' Correlation ID: '. $correlationId
|
82 |
+
. ' PHP Session ID: '. session_id()
|
83 |
+
. ' Sequence No: ' . $sequenceNo
|
84 |
+
. ' Executed curl request. '
|
85 |
+
. ' Command:' . $cmd
|
86 |
+
. ' Exec output: ' . print_r($output,true)
|
87 |
+
. ' Return Var: ' . $exit
|
88 |
+
);
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Mainly for connection and controller testing purposes.
|
93 |
+
* Synchronously sends the data passed to "synchronous remote sender"
|
94 |
+
* (another Cart Defender PHP script available on localhost),
|
95 |
+
* which then sends the data synchronously to Cart Defender servers.
|
96 |
+
*
|
97 |
+
*/
|
98 |
+
private function sendSyncHttpClient($data, $sequenceNo, $correlationId, $sendKey, $localControllerUrl)
|
99 |
+
{
|
100 |
+
$client = new Varien_Http_Client($localControllerUrl);
|
101 |
+
$client->setMethod(Varien_Http_Client::POST);
|
102 |
+
$client->setCookie('CartDefenderCorrelationId', $correlationId);
|
103 |
+
$client->setConfig(array('strictredirects' => true));
|
104 |
+
$client->setEncType();
|
105 |
+
$client->setParameterPost('sequence_no', $sequenceNo);
|
106 |
+
$client->setParameterPost('is_local_request', true);
|
107 |
+
$client->setParameterPost('correlation_id', $correlationId);
|
108 |
+
$client->setParameterPost('send_key', $sendKey);
|
109 |
+
$client->setParameterPost('data', $data);
|
110 |
+
$response = $client->request('POST');
|
111 |
+
$lastRequest = $client->getLastRequest();
|
112 |
+
|
113 |
+
Mage::getSingleton('core/session')->setLastEventTime(time());
|
114 |
+
|
115 |
+
$this->logger->log(
|
116 |
+
'AsyncLocalSender->sendSyncHttpClient', ' Correlation ID: '. $correlationId
|
117 |
+
. ' PHP Session ID: '. session_id() . 'Request: ' . $lastRequest
|
118 |
+
. ' Response: '. (($response->getStatus() == 200) ? 'Success ' : 'Error ')
|
119 |
+
. 'Response Status Code: ' . $response->getStatus()
|
120 |
+
. 'Entire Response string: ' . $response->asString()
|
121 |
+
);
|
122 |
+
}
|
123 |
+
|
124 |
/**
|
125 |
* Asynchronously sends the data passed to "synchronous remote sender"
|
126 |
* (another Cart Defender PHP script available on localhost),
|
144 |
* by Cart Defender backend.
|
145 |
* @return void
|
146 |
*/
|
147 |
+
private function sendAsyncSocket($data, $sequenceNo, $correlationId, $sendKey, $localControllerUrl)
|
148 |
{
|
149 |
+
$remoteSenderConf = $this->getRemoteSenderConf($localControllerUrl);
|
150 |
$request = $this->createRequest(
|
151 |
$remoteSenderConf['path'],
|
152 |
$remoteSenderConf['host'],
|
153 |
$data,
|
154 |
$sequenceNo,
|
155 |
+
$correlationId,
|
156 |
+
$sendKey
|
157 |
);
|
158 |
$socket = fsockopen(
|
159 |
$remoteSenderConf['protocol'] . $remoteSenderConf['host'],
|
160 |
$remoteSenderConf['port'],
|
161 |
$errno,
|
162 |
$errstr,
|
163 |
+
0.3 /*timeout*/
|
164 |
);
|
165 |
+
$strLen = strlen($request);
|
166 |
+
$writeResult = $this->fwriteStream($socket, $request, $strLen, 6);
|
|
|
|
|
|
|
167 |
fclose($socket);
|
168 |
+
$success = ($writeResult === $strLen);
|
169 |
+
|
170 |
+
Mage::getSingleton('core/session')->setLastEventTime(time());
|
171 |
+
|
172 |
+
$this->logger->log('AsyncLocalSender->sendAsyncSocket', ' Correlation ID: '. $correlationId
|
173 |
+
. ' PHP Session ID: '. session_id()
|
174 |
+
. ($success ? ' Success. ' : ('Error (num: [' . $errno . '], msg: [' . $errstr . '])'))
|
175 |
+
. ' Request: [' . $request . ']');
|
176 |
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Writes stream data over network sockets and expects the number of zero bytes written to be
|
180 |
+
* smaller than the set parameter.
|
181 |
+
*
|
182 |
+
* @return int the number of bytes written
|
183 |
+
*/
|
184 |
+
private function fwriteStream($fp, $string, $strLen, $maxZeros = 3)
|
185 |
+
{
|
186 |
+
$numZeros = 0;
|
187 |
+
for ($written = 0; $written < $strLen; $written += $fwrite) {
|
188 |
+
$fwrite = fwrite($fp, substr($string, $written));
|
189 |
+
if ($fwrite === false || $numZeros >= $maxZeros) {
|
190 |
+
return $written;
|
191 |
+
}
|
192 |
+
if ($fwrite === 0) {
|
193 |
+
$numZeros += 1;
|
194 |
+
}
|
195 |
+
}
|
196 |
+
return $written;
|
197 |
+
}
|
198 |
+
|
199 |
/**
|
200 |
* Retrieves the configuration of synchronous remote sender,
|
201 |
* specifically its URL parts.
|
203 |
* @return array the configuration of synchronous remote sender, with
|
204 |
* entries such as 'protocol', 'host', 'port', 'path'.
|
205 |
*/
|
206 |
+
private function getRemoteSenderConf($localControllerUrl)
|
207 |
{
|
208 |
// "static" to compute only once and return cached value later.
|
209 |
static $remoteSenderConf = null;
|
210 |
if ($remoteSenderConf === null) {
|
211 |
+
$remoteSenderConf = parse_url($localControllerUrl);
|
|
|
|
|
|
|
212 |
if (empty($remoteSenderConf['port'])) {
|
213 |
$remoteSenderConf['port'] =
|
214 |
($remoteSenderConf['scheme'] == 'http') ? 80 : 443;
|
245 |
$remoteSenderHost,
|
246 |
$data,
|
247 |
$sequenceNo,
|
248 |
+
$correlationId,
|
249 |
+
$sendKey
|
250 |
) {
|
|
|
251 |
$queryParams = array(
|
252 |
'sequence_no' => $sequenceNo,
|
|
|
253 |
'is_local_request' => true, // PHP to PHP call within current server
|
254 |
'correlation_id' => $correlationId,
|
255 |
+
'send_key' => $sendKey,
|
256 |
+
'data' => $data
|
257 |
);
|
258 |
$postdata = http_build_query($queryParams);
|
259 |
|
260 |
// Note that Carriage Return (\r) characters below are in accordance
|
261 |
// with RFC 2616. See http://stackoverflow.com/questions/5757290 Also,
|
262 |
// note that double quotes let \r & \n be interpreted correctly.
|
|
|
263 |
$request = "";
|
264 |
$request.= "POST " . $remoteSenderUrlPath . " HTTP/1.1\r\n";
|
265 |
$request.= "Host: " . $remoteSenderHost . "\r\n";
|
266 |
+
$request.= "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n";
|
267 |
+
$request.= "Content-Length: " . strlen($postdata) . "\r\n";
|
268 |
$request.= "\r\n";
|
269 |
$request.= $postdata;
|
270 |
$request.= "\r\n\r\n";
|
271 |
|
272 |
return $request;
|
273 |
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Returns the URL to which the data should be sent by this script.
|
277 |
+
*
|
278 |
+
* @param array $settings Cart Defender configuration settings.
|
279 |
+
* @return string URL to which the data should be sent by this script.
|
280 |
+
*/
|
281 |
+
private function getUrl($correlationId, $settings)
|
282 |
+
{
|
283 |
+
$path = CDData::CD_PLUGIN_BIZ_API_PATH_START
|
284 |
+
. '/' . $correlationId . '/'
|
285 |
+
. CDData::CD_PLUGIN_BIZ_API_VERSION
|
286 |
+
. CDData::CD_PLUGIN_BIZ_API_PATH_END;
|
287 |
+
$useRawTestUrl = $settings['use_raw_test_url_for_biz_api'];
|
288 |
+
return $settings['test'] ? ($settings['test_server_url_start']
|
289 |
+
. ($useRawTestUrl ? '' : $path)) : (CDData::CD_HOST . $path);
|
290 |
+
}
|
291 |
}
|
app/code/community/CartDefender/Actions/Model/CorrelationIdManager.php
CHANGED
@@ -110,12 +110,22 @@ class CartDefender_Actions_Model_CorrelationIdManager extends Varien_Object
|
|
110 |
if (!$corrIdExternal) {
|
111 |
// Take id from header if not present on cookie
|
112 |
$corrIdExternal = Mage::app()->getRequest()->getHeader(self::CD_CORRELATION_HEADER_NAME);
|
|
|
|
|
|
|
|
|
|
|
113 |
}
|
114 |
// If Correlation ID was not provided, generate it.
|
115 |
$this->correlationId = $corrIdExternal ?: $this->generateCorrelationId();
|
116 |
$phpSessionId = session_id();
|
117 |
if (!$corrIdExternal && !empty($phpSessionId)) {
|
118 |
$this->setCorrelationIdCookie();
|
|
|
|
|
|
|
|
|
|
|
119 |
// Notify CD servers of new correlation id.
|
120 |
$this->sender->sendEvent(
|
121 |
CDData::START_OF_SESSION,
|
110 |
if (!$corrIdExternal) {
|
111 |
// Take id from header if not present on cookie
|
112 |
$corrIdExternal = Mage::app()->getRequest()->getHeader(self::CD_CORRELATION_HEADER_NAME);
|
113 |
+
$this->logger->log(
|
114 |
+
'CorrelationIdManager->ensureCorrelationIdSet', 'Taken from header, not from cookie'
|
115 |
+
. ' Correlation ID: '. $this->correlationId
|
116 |
+
. ' PHP Session ID: '. session_id()
|
117 |
+
);
|
118 |
}
|
119 |
// If Correlation ID was not provided, generate it.
|
120 |
$this->correlationId = $corrIdExternal ?: $this->generateCorrelationId();
|
121 |
$phpSessionId = session_id();
|
122 |
if (!$corrIdExternal && !empty($phpSessionId)) {
|
123 |
$this->setCorrelationIdCookie();
|
124 |
+
$this->logger->log(
|
125 |
+
'CorrelationIdManager->ensureCorrelationIdSet', 'Generated and set on cookie'
|
126 |
+
. ' Correlation ID: '. $this->correlationId
|
127 |
+
. ' PHP Session ID: '. session_id()
|
128 |
+
);
|
129 |
// Notify CD servers of new correlation id.
|
130 |
$this->sender->sendEvent(
|
131 |
CDData::START_OF_SESSION,
|
app/code/community/CartDefender/Actions/Model/EventAsyncLocalSender.php
CHANGED
@@ -42,10 +42,16 @@ class CartDefender_Actions_Model_EventAsyncLocalSender
|
|
42 |
$data,
|
43 |
$sequenceNo
|
44 |
);
|
|
|
45 |
$this->send($event, $sequenceNo, $correlationId);
|
|
|
|
|
46 |
$this->logger->log(
|
47 |
-
'EventAsyncLocalSender->sendEvent',
|
48 |
-
'
|
|
|
|
|
|
|
49 |
);
|
50 |
}
|
51 |
}
|
42 |
$data,
|
43 |
$sequenceNo
|
44 |
);
|
45 |
+
$millisBefore = round(microtime(true) * 1000);
|
46 |
$this->send($event, $sequenceNo, $correlationId);
|
47 |
+
$millisAfter = round(microtime(true) * 1000);
|
48 |
+
|
49 |
$this->logger->log(
|
50 |
+
'EventAsyncLocalSender->sendEvent', ' Correlation ID: '. $correlationId
|
51 |
+
. ' PHP Session ID: '. session_id()
|
52 |
+
. ' Sent event: ' . $eventName
|
53 |
+
. ' Request time: ' . $millisBefore
|
54 |
+
. ' Request latency: ' . ($millisAfter - $millisBefore)
|
55 |
);
|
56 |
}
|
57 |
}
|
app/code/community/CartDefender/Actions/Model/EventBuilder.php
CHANGED
@@ -66,6 +66,11 @@ class CartDefender_Actions_Model_EventBuilder
|
|
66 |
);
|
67 |
$done = array();
|
68 |
$utf8izedEvent = Mage::helper('actions')->utf8ize($event, $done);
|
|
|
|
|
|
|
|
|
|
|
69 |
return Zend_Json::encode($utf8izedEvent, true);
|
70 |
}
|
71 |
|
@@ -133,17 +138,46 @@ class CartDefender_Actions_Model_EventBuilder
|
|
133 |
$cartData = $this->removePersonalData($quote->getData());
|
134 |
$productMediaConfig = Mage::getModel('catalog/product_media_config');
|
135 |
$items = $quote->getAllVisibleItems();
|
|
|
136 |
foreach ($items as $item) {
|
137 |
$itemData = $item->getData();
|
138 |
$productFromData = $itemData['product'];
|
139 |
-
$
|
140 |
-
$itemData['product_url'] = $productUrl;
|
141 |
-
$itemData['base_image_url'] = $productMediaConfig->getMediaUrl($productFromData->getImage());
|
142 |
-
$itemData['small_image_url'] = $productMediaConfig->getMediaUrl($productFromData->getSmallImage());
|
143 |
-
$itemData['thumbnail_url'] = $productMediaConfig->getMediaUrl($productFromData->getThumbnail());
|
144 |
-
$itemData['product_data'] = $productFromData->getData();
|
145 |
$cartItems[] = $itemData;
|
146 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
} else {
|
148 |
$quote = CDData::MISSING_VALUE;
|
149 |
$cartData[] = CDData::MISSING_VALUE;
|
66 |
);
|
67 |
$done = array();
|
68 |
$utf8izedEvent = Mage::helper('actions')->utf8ize($event, $done);
|
69 |
+
$logger = Mage::helper('actions/logger');
|
70 |
+
$logger->log(
|
71 |
+
'EventBuilder->buildEvent',
|
72 |
+
'Built event: ' . $eventName
|
73 |
+
);
|
74 |
return Zend_Json::encode($utf8izedEvent, true);
|
75 |
}
|
76 |
|
138 |
$cartData = $this->removePersonalData($quote->getData());
|
139 |
$productMediaConfig = Mage::getModel('catalog/product_media_config');
|
140 |
$items = $quote->getAllVisibleItems();
|
141 |
+
$productIds = array();
|
142 |
foreach ($items as $item) {
|
143 |
$itemData = $item->getData();
|
144 |
$productFromData = $itemData['product'];
|
145 |
+
$productIds[] = $productFromData->getId();
|
|
|
|
|
|
|
|
|
|
|
146 |
$cartItems[] = $itemData;
|
147 |
}
|
148 |
+
if (! empty($productIds)) {
|
149 |
+
Mage::getResourceModel('catalog/product_collection')->setStore($storeId);
|
150 |
+
$collection = Mage::getResourceModel('catalog/product_collection');
|
151 |
+
|
152 |
+
$prodCollection = Mage::getModel('catalog/product')->getCollection()
|
153 |
+
->setStore(Mage::app()->getStore()->getStoreId())
|
154 |
+
->addAttributeToSelect('entity_id')
|
155 |
+
->addAttributeToSelect('meta_title')
|
156 |
+
->addAttributeToSelect('name')
|
157 |
+
->addAttributeToSelect('short_description')
|
158 |
+
->addAttributeToSelect('price')
|
159 |
+
->addAttributeToSelect('final_price')
|
160 |
+
->addAttributeToSelect('image')
|
161 |
+
->addAttributeToSelect('small_image')
|
162 |
+
->addAttributeToSelect('thumbnail')
|
163 |
+
->addAttributeToSelect('product_url')
|
164 |
+
->addFieldToFilter('entity_id', array('in' => array(array_unique($productIds))
|
165 |
+
));
|
166 |
+
|
167 |
+
$prodInfo = array();
|
168 |
+
|
169 |
+
foreach ($prodCollection as $prodData) {
|
170 |
+
$prodData->setStoreId(Mage::app()->getStore()->getStoreId());
|
171 |
+
$productUrl = $prodData->getProductUrl();
|
172 |
+
$prodArray = $prodData->getData();
|
173 |
+
$prodArray['cd_product_url'] = $productUrl;
|
174 |
+
$prodArray['cd_base_image_url'] = $productMediaConfig->getMediaUrl($prodData->getImage());
|
175 |
+
$prodArray['cd_small_image_url'] = $productMediaConfig->getMediaUrl($prodData->getSmallImage());
|
176 |
+
$prodArray['cd_thumbnail_url'] = $productMediaConfig->getMediaUrl($prodData->getThumbnail());
|
177 |
+
$prodInfo[] = $prodArray;
|
178 |
+
}
|
179 |
+
$cartData['cd_all_products_info'] = $prodInfo;
|
180 |
+
}
|
181 |
} else {
|
182 |
$quote = CDData::MISSING_VALUE;
|
183 |
$cartData[] = CDData::MISSING_VALUE;
|
app/code/community/CartDefender/Actions/Model/Observer.php
CHANGED
@@ -50,9 +50,9 @@ class CartDefender_Actions_Model_Observer extends Varien_Event_Observer
|
|
50 |
}
|
51 |
|
52 |
/**
|
53 |
-
* Main event observer function.
|
54 |
*
|
55 |
-
*
|
56 |
*
|
57 |
* @param object $observer event data.
|
58 |
* @return void
|
@@ -150,7 +150,10 @@ class CartDefender_Actions_Model_Observer extends Varien_Event_Observer
|
|
150 |
$result = empty($lastEventAt)
|
151 |
|| (($now - $lastEventAt) > self::EVENT_TIME_THRESHOLD);
|
152 |
|
153 |
-
$this->logger->log('Observer->isLongSinceLastEvent', '
|
|
|
|
|
|
|
154 |
. ($result ? 'Y' : 'N') . ' Time diff: '
|
155 |
. ($lastEventAt ? ($now - $lastEventAt): 'N/A'));
|
156 |
return $result;
|
50 |
}
|
51 |
|
52 |
/**
|
53 |
+
* Main event observer function for selected Magento events.
|
54 |
*
|
55 |
+
* FYI, full list of events: http://www.nicksays.co.uk/magento-events-cheat-sheet-1-7/
|
56 |
*
|
57 |
* @param object $observer event data.
|
58 |
* @return void
|
150 |
$result = empty($lastEventAt)
|
151 |
|| (($now - $lastEventAt) > self::EVENT_TIME_THRESHOLD);
|
152 |
|
153 |
+
$this->logger->log('Observer->isLongSinceLastEvent', ' Correlation ID: '
|
154 |
+
. $this->correlationIdMgr->getCorrelationId()
|
155 |
+
. ' PHP Session ID: '. session_id()
|
156 |
+
. 'Result: '
|
157 |
. ($result ? 'Y' : 'N') . ' Time diff: '
|
158 |
. ($lastEventAt ? ($now - $lastEventAt): 'N/A'));
|
159 |
return $result;
|
app/code/community/CartDefender/Actions/Model/System/Config/Source/Transport.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class CartDefender_Actions_Model_System_Config_Source_Transport
|
4 |
+
{
|
5 |
+
const ASYNC_SOCKET = 'Async PHP script';
|
6 |
+
const CURL_PROCESS = 'Async CURL process';
|
7 |
+
const SYNC_HTTP = 'Sync HTTP client';
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Returns the value for transport mode selection in the admin config panel.
|
11 |
+
*/
|
12 |
+
public function toOptionArray()
|
13 |
+
{
|
14 |
+
return array(
|
15 |
+
array('value'=>self::ASYNC_SOCKET, 'label'=>self::ASYNC_SOCKET),
|
16 |
+
array('value'=>self::CURL_PROCESS, 'label'=>self::CURL_PROCESS),
|
17 |
+
array('value'=>self::SYNC_HTTP, 'label'=>self::SYNC_HTTP)
|
18 |
+
);
|
19 |
+
}
|
20 |
+
}
|
app/code/community/CartDefender/Actions/controllers/CartDefenderSenderController.php
CHANGED
@@ -64,6 +64,11 @@ class CartDefender_Actions_CartDefenderSenderController
|
|
64 |
{
|
65 |
$settings = Mage::helper('actions')->getSettings();
|
66 |
$request = $this->getRequest();
|
|
|
|
|
|
|
|
|
|
|
67 |
if ($this->isRequestAllowed($request, $settings)) {
|
68 |
$millisBefore = round(microtime(true) * 1000);
|
69 |
|
@@ -79,15 +84,23 @@ class CartDefender_Actions_CartDefenderSenderController
|
|
79 |
. ' Url: ' . $this->getUrl($settings)
|
80 |
. ' Request time: ' . $millisBefore
|
81 |
. ' Request latency: ' . ($millisAfter - $millisBefore)
|
|
|
|
|
|
|
82 |
);
|
83 |
} else {
|
84 |
$this->logger->log(
|
85 |
'CartDefenderSenderController->sendAction',
|
86 |
-
'Error - request not allowed.'
|
|
|
|
|
87 |
);
|
88 |
exit;
|
89 |
}
|
90 |
-
$this->logger->log('CartDefenderSenderController->sendAction', 'Done'
|
|
|
|
|
|
|
91 |
echo 'Done';
|
92 |
exit;
|
93 |
}
|
@@ -137,10 +150,11 @@ class CartDefender_Actions_CartDefenderSenderController
|
|
137 |
private function sendRequest($request, $settings)
|
138 |
{
|
139 |
$client = new Varien_Http_Client($this->getUrl($settings));
|
|
|
140 |
$client->setMethod(Varien_Http_Client::POST);
|
141 |
$client->setAuth($settings['api'], '', Zend_Http_Client::AUTH_BASIC);
|
142 |
$client->setRawData($request->getPost('data'));
|
143 |
$client->setEncType('application/json');
|
144 |
-
return $client->request();
|
145 |
}
|
146 |
}
|
64 |
{
|
65 |
$settings = Mage::helper('actions')->getSettings();
|
66 |
$request = $this->getRequest();
|
67 |
+
$this->logger->log(
|
68 |
+
'CartDefenderSenderController->sendAction',
|
69 |
+
'Received request with Correlation ID: ' . $request->getPost('correlation_id')
|
70 |
+
. ' PHP Session ID: ' . session_id()
|
71 |
+
);
|
72 |
if ($this->isRequestAllowed($request, $settings)) {
|
73 |
$millisBefore = round(microtime(true) * 1000);
|
74 |
|
84 |
. ' Url: ' . $this->getUrl($settings)
|
85 |
. ' Request time: ' . $millisBefore
|
86 |
. ' Request latency: ' . ($millisAfter - $millisBefore)
|
87 |
+
. ' Status code: ' . $response->getStatus()
|
88 |
+
. ' Correlation ID: ' . $request->getPost('correlation_id')
|
89 |
+
. ' PHP Session ID: ' . session_id()
|
90 |
);
|
91 |
} else {
|
92 |
$this->logger->log(
|
93 |
'CartDefenderSenderController->sendAction',
|
94 |
+
'Error - request not allowed. '
|
95 |
+
. 'Correlation ID: ' . $request->getPost('correlation_id')
|
96 |
+
. 'PHP Session ID: ' . session_id()
|
97 |
);
|
98 |
exit;
|
99 |
}
|
100 |
+
$this->logger->log('CartDefenderSenderController->sendAction', 'Done'
|
101 |
+
. 'Correlation ID: ' . $request->getPost('correlation_id')
|
102 |
+
. 'PHP Session ID: ' . session_id()
|
103 |
+
);
|
104 |
echo 'Done';
|
105 |
exit;
|
106 |
}
|
150 |
private function sendRequest($request, $settings)
|
151 |
{
|
152 |
$client = new Varien_Http_Client($this->getUrl($settings));
|
153 |
+
$client->setConfig(array('strictredirects' => true));
|
154 |
$client->setMethod(Varien_Http_Client::POST);
|
155 |
$client->setAuth($settings['api'], '', Zend_Http_Client::AUTH_BASIC);
|
156 |
$client->setRawData($request->getPost('data'));
|
157 |
$client->setEncType('application/json');
|
158 |
+
return $client->request('POST');
|
159 |
}
|
160 |
}
|
app/code/community/CartDefender/Actions/etc/api.xml
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<api>
|
4 |
+
<resources>
|
5 |
+
<cartdefender_product_feed>
|
6 |
+
<model>actions/api</model>
|
7 |
+
<title>Cart Defender's product feed API</title>
|
8 |
+
<acl>cartdefender</acl>
|
9 |
+
<methods>
|
10 |
+
<export translate="title" module="actions">
|
11 |
+
<title>Retrieve store's products</title>
|
12 |
+
<method>export</method>
|
13 |
+
</export>
|
14 |
+
<getVersion translate="title" module="actions">
|
15 |
+
<title>Retrieve store's products</title>
|
16 |
+
<method>getVersion</method>
|
17 |
+
</getVersion>
|
18 |
+
</methods>
|
19 |
+
</cartdefender_product_feed>
|
20 |
+
|
21 |
+
</resources>
|
22 |
+
<v2>
|
23 |
+
<resources_function_prefix>
|
24 |
+
<cartdefender_product_feed>cartdefender_productFeed</cartdefender_product_feed>
|
25 |
+
</resources_function_prefix>
|
26 |
+
</v2>
|
27 |
+
<acl>
|
28 |
+
<resources>
|
29 |
+
<cartdefender translate="title" module="actions">
|
30 |
+
<title>Cart Defender product feed data</title>
|
31 |
+
<product_export translate="title" module="actions">
|
32 |
+
<title>Product export</title>
|
33 |
+
</product_export>
|
34 |
+
</cartdefender>
|
35 |
+
</resources>
|
36 |
+
</acl>
|
37 |
+
</api>
|
38 |
+
</config>
|
app/code/community/CartDefender/Actions/etc/config.xml
CHANGED
@@ -12,7 +12,7 @@
|
|
12 |
<config>
|
13 |
<modules>
|
14 |
<CartDefender_Actions>
|
15 |
-
<version>2.
|
16 |
</CartDefender_Actions>
|
17 |
</modules>
|
18 |
|
@@ -54,24 +54,6 @@
|
|
54 |
</cartdefender_checkout_cart_save_after>
|
55 |
</observers>
|
56 |
</checkout_cart_save_after>
|
57 |
-
<checkout_controller_multishipping_shipping_post>
|
58 |
-
<observers>
|
59 |
-
<cartdefender_checkout_controller_multishipping_shipping_post>
|
60 |
-
<type>singleton</type>
|
61 |
-
<class>CartDefender_Actions_Model_Observer</class>
|
62 |
-
<method>captureEvent</method>
|
63 |
-
</cartdefender_checkout_controller_multishipping_shipping_post>
|
64 |
-
</observers>
|
65 |
-
</checkout_controller_multishipping_shipping_post>
|
66 |
-
<checkout_controller_onepage_save_shipping_method>
|
67 |
-
<observers>
|
68 |
-
<cartdefender_checkout_controller_onepage_save_shipping_method>
|
69 |
-
<type>singleton</type>
|
70 |
-
<class>CartDefender_Actions_Model_Observer</class>
|
71 |
-
<method>captureEvent</method>
|
72 |
-
</cartdefender_checkout_controller_onepage_save_shipping_method>
|
73 |
-
</observers>
|
74 |
-
</checkout_controller_onepage_save_shipping_method>
|
75 |
<checkout_multishipping_controller_success_action>
|
76 |
<observers>
|
77 |
<cartdefender_checkout_multishipping_controller_success_action>
|
@@ -135,69 +117,15 @@
|
|
135 |
</cartdefender_order_cancel_after>
|
136 |
</observers>
|
137 |
</order_cancel_after>
|
138 |
-
<
|
139 |
-
<observers>
|
140 |
-
<cartdefender_sales_order_payment_cancel>
|
141 |
-
<type>singleton</type>
|
142 |
-
<class>CartDefender_Actions_Model_Observer</class>
|
143 |
-
<method>captureEvent</method>
|
144 |
-
</cartdefender_sales_order_payment_cancel>
|
145 |
-
</observers>
|
146 |
-
</sales_order_payment_cancel>
|
147 |
-
<sales_order_payment_capture>
|
148 |
-
<observers>
|
149 |
-
<cartdefender_sales_order_payment_capture>
|
150 |
-
<type>singleton</type>
|
151 |
-
<class>CartDefender_Actions_Model_Observer</class>
|
152 |
-
<method>captureEvent</method>
|
153 |
-
</cartdefender_sales_order_payment_capture>
|
154 |
-
</observers>
|
155 |
-
</sales_order_payment_capture>
|
156 |
-
<sales_order_payment_pay>
|
157 |
-
<observers>
|
158 |
-
<cartdefender_sales_order_payment_pay>
|
159 |
-
<type>singleton</type>
|
160 |
-
<class>CartDefender_Actions_Model_Observer</class>
|
161 |
-
<method>captureEvent</method>
|
162 |
-
</cartdefender_sales_order_payment_pay>
|
163 |
-
</observers>
|
164 |
-
</sales_order_payment_pay>
|
165 |
-
<sales_order_payment_place_end>
|
166 |
-
<observers>
|
167 |
-
<cartdefender_sales_order_payment_place_end>
|
168 |
-
<type>singleton</type>
|
169 |
-
<class>CartDefender_Actions_Model_Observer</class>
|
170 |
-
<method>captureEvent</method>
|
171 |
-
</cartdefender_sales_order_payment_place_end>
|
172 |
-
</observers>
|
173 |
-
</sales_order_payment_place_end>
|
174 |
-
<sales_order_payment_place_start>
|
175 |
-
<observers>
|
176 |
-
<cartdefender_sales_order_payment_place_start>
|
177 |
-
<type>singleton</type>
|
178 |
-
<class>CartDefender_Actions_Model_Observer</class>
|
179 |
-
<method>captureEvent</method>
|
180 |
-
</cartdefender_sales_order_payment_place_start>
|
181 |
-
</observers>
|
182 |
-
</sales_order_payment_place_start>
|
183 |
-
<sales_order_payment_refund>
|
184 |
-
<observers>
|
185 |
-
<cartdefender_sales_order_payment_refund>
|
186 |
-
<type>singleton</type>
|
187 |
-
<class>CartDefender_Actions_Model_Observer</class>
|
188 |
-
<method>captureEvent</method>
|
189 |
-
</cartdefender_sales_order_payment_refund>
|
190 |
-
</observers>
|
191 |
-
</sales_order_payment_refund>
|
192 |
-
<sales_order_payment_void>
|
193 |
<observers>
|
194 |
-
<
|
195 |
<type>singleton</type>
|
196 |
<class>CartDefender_Actions_Model_Observer</class>
|
197 |
<method>captureEvent</method>
|
198 |
-
</
|
199 |
</observers>
|
200 |
-
</
|
201 |
<controller_action_predispatch_checkout_onepage_index>
|
202 |
<observers>
|
203 |
<cartdefender_controller_action_predispatch_checkout_onepage_index>
|
12 |
<config>
|
13 |
<modules>
|
14 |
<CartDefender_Actions>
|
15 |
+
<version>2.1.8</version>
|
16 |
</CartDefender_Actions>
|
17 |
</modules>
|
18 |
|
54 |
</cartdefender_checkout_cart_save_after>
|
55 |
</observers>
|
56 |
</checkout_cart_save_after>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
<checkout_multishipping_controller_success_action>
|
58 |
<observers>
|
59 |
<cartdefender_checkout_multishipping_controller_success_action>
|
117 |
</cartdefender_order_cancel_after>
|
118 |
</observers>
|
119 |
</order_cancel_after>
|
120 |
+
<sales_order_place_after>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
<observers>
|
122 |
+
<cartdefender_sales_order_place_after>
|
123 |
<type>singleton</type>
|
124 |
<class>CartDefender_Actions_Model_Observer</class>
|
125 |
<method>captureEvent</method>
|
126 |
+
</cartdefender_sales_order_place_after>
|
127 |
</observers>
|
128 |
+
</sales_order_place_after>
|
129 |
<controller_action_predispatch_checkout_onepage_index>
|
130 |
<observers>
|
131 |
<cartdefender_controller_action_predispatch_checkout_onepage_index>
|
app/code/community/CartDefender/Actions/etc/system.xml
CHANGED
@@ -44,7 +44,7 @@
|
|
44 |
<sort_order>1</sort_order>
|
45 |
<show_in_default>1</show_in_default>
|
46 |
<show_in_website>1</show_in_website>
|
47 |
-
<show_in_store>
|
48 |
</enabled>
|
49 |
<api translate="label">
|
50 |
<label>API key</label>
|
@@ -52,33 +52,65 @@
|
|
52 |
<sort_order>2</sort_order>
|
53 |
<show_in_default>1</show_in_default>
|
54 |
<show_in_website>1</show_in_website>
|
55 |
-
<show_in_store>
|
56 |
</api>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
<send_key translate="label">
|
58 |
-
<label>
|
59 |
<frontend_type>text</frontend_type>
|
60 |
-
<sort_order>
|
61 |
<show_in_default>1</show_in_default>
|
62 |
-
<show_in_website>
|
63 |
<show_in_store>0</show_in_store>
|
64 |
</send_key>
|
65 |
<test translate="label">
|
66 |
<label>Test mode</label>
|
67 |
<frontend_type>select</frontend_type>
|
68 |
<source_model>adminhtml/system_config_source_yesno</source_model>
|
69 |
-
<sort_order>
|
70 |
<show_in_default>1</show_in_default>
|
71 |
<show_in_website>1</show_in_website>
|
72 |
-
<show_in_store>
|
|
|
|
|
|
|
|
|
73 |
</test>
|
74 |
<!-- Don't use a trailing slash in test server URL.-->
|
75 |
<test_server_url_start>
|
76 |
-
<label>Send data to this URL: protocol, domain, and path prefix if any (e.g. http://localhost)</label>
|
77 |
<frontend_type>text</frontend_type>
|
78 |
-
<sort_order>
|
79 |
<show_in_default>1</show_in_default>
|
80 |
<show_in_website>1</show_in_website>
|
81 |
-
<show_in_store>
|
82 |
<depends><test>1</test></depends>
|
83 |
</test_server_url_start>
|
84 |
<!-- This setting controls if the "Test server URL" value is used exactly
|
@@ -89,10 +121,10 @@
|
|
89 |
<label>Use unadorned target server URL for JSON API</label>
|
90 |
<frontend_type>select</frontend_type>
|
91 |
<source_model>adminhtml/system_config_source_yesno</source_model>
|
92 |
-
<sort_order>
|
93 |
<show_in_default>1</show_in_default>
|
94 |
<show_in_website>1</show_in_website>
|
95 |
-
<show_in_store>
|
96 |
<depends><test>1</test></depends>
|
97 |
</use_raw_test_url_for_biz_api>
|
98 |
</fields>
|
44 |
<sort_order>1</sort_order>
|
45 |
<show_in_default>1</show_in_default>
|
46 |
<show_in_website>1</show_in_website>
|
47 |
+
<show_in_store>0</show_in_store>
|
48 |
</enabled>
|
49 |
<api translate="label">
|
50 |
<label>API key</label>
|
52 |
<sort_order>2</sort_order>
|
53 |
<show_in_default>1</show_in_default>
|
54 |
<show_in_website>1</show_in_website>
|
55 |
+
<show_in_store>0</show_in_store>
|
56 |
</api>
|
57 |
+
<transport_method translate="label">
|
58 |
+
<label>Select how data is sent to Cart Defender</label>
|
59 |
+
<frontend_type>select</frontend_type>
|
60 |
+
<source_model>actions/system_config_source_transport</source_model>
|
61 |
+
<sort_order>3</sort_order>
|
62 |
+
<show_in_default>1</show_in_default>
|
63 |
+
<show_in_website>1</show_in_website>
|
64 |
+
<show_in_store>0</show_in_store>
|
65 |
+
<comment><![CDATA[ <p>Please select the method that will work best in your system:</p>
|
66 |
+
<p>CURL requires access to the exec() function to fork a separate process.</p>
|
67 |
+
<p>Async PHP script relies on a separate Controller which sends data to Cart Defender.</p>
|
68 |
+
<p>Synchronous PHP is encouraged when testing the connection.</p>
|
69 |
+
]]>
|
70 |
+
</comment>
|
71 |
+
</transport_method>
|
72 |
+
<sender_controller_url translate="label">
|
73 |
+
<label>Cart Defender Sender Controller URL (auto-populated)</label>
|
74 |
+
<frontend_type>text</frontend_type>
|
75 |
+
<sort_order>4</sort_order>
|
76 |
+
<show_in_default>1</show_in_default>
|
77 |
+
<show_in_website>1</show_in_website>
|
78 |
+
<show_in_store>0</show_in_store>
|
79 |
+
<depends><transport_method>Async PHP script</transport_method></depends>
|
80 |
+
<comment><![CDATA[ <p>This is the URL of the internal Async PHP controller. It is populated automatically if left blank.
|
81 |
+
Afterwards, changes might be required to tweak the URL according to your website setup.</p>
|
82 |
+
]]>
|
83 |
+
</comment>
|
84 |
+
</sender_controller_url>
|
85 |
<send_key translate="label">
|
86 |
+
<label>Internal request key (generated)</label>
|
87 |
<frontend_type>text</frontend_type>
|
88 |
+
<sort_order>5</sort_order>
|
89 |
<show_in_default>1</show_in_default>
|
90 |
+
<show_in_website>1</show_in_website>
|
91 |
<show_in_store>0</show_in_store>
|
92 |
</send_key>
|
93 |
<test translate="label">
|
94 |
<label>Test mode</label>
|
95 |
<frontend_type>select</frontend_type>
|
96 |
<source_model>adminhtml/system_config_source_yesno</source_model>
|
97 |
+
<sort_order>6</sort_order>
|
98 |
<show_in_default>1</show_in_default>
|
99 |
<show_in_website>1</show_in_website>
|
100 |
+
<show_in_store>0</show_in_store>
|
101 |
+
<comment><![CDATA[ <p>Test mode enables logging (into a separate file: cartdefender.log)
|
102 |
+
and allows to configure the URL where the data is send to.</p>
|
103 |
+
]]>
|
104 |
+
</comment>
|
105 |
</test>
|
106 |
<!-- Don't use a trailing slash in test server URL.-->
|
107 |
<test_server_url_start>
|
108 |
+
<label>Send data to this target URL: protocol, domain, and path prefix if any (e.g. http://localhost)</label>
|
109 |
<frontend_type>text</frontend_type>
|
110 |
+
<sort_order>7</sort_order>
|
111 |
<show_in_default>1</show_in_default>
|
112 |
<show_in_website>1</show_in_website>
|
113 |
+
<show_in_store>0</show_in_store>
|
114 |
<depends><test>1</test></depends>
|
115 |
</test_server_url_start>
|
116 |
<!-- This setting controls if the "Test server URL" value is used exactly
|
121 |
<label>Use unadorned target server URL for JSON API</label>
|
122 |
<frontend_type>select</frontend_type>
|
123 |
<source_model>adminhtml/system_config_source_yesno</source_model>
|
124 |
+
<sort_order>8</sort_order>
|
125 |
<show_in_default>1</show_in_default>
|
126 |
<show_in_website>1</show_in_website>
|
127 |
+
<show_in_store>0</show_in_store>
|
128 |
<depends><test>1</test></depends>
|
129 |
</use_raw_test_url_for_biz_api>
|
130 |
</fields>
|
app/design/frontend/base/default/template/actions/script.phtml
CHANGED
@@ -11,7 +11,7 @@
|
|
11 |
|
12 |
<?php if ($this->getSetting('enabled')) { ?>
|
13 |
<?php if ($this->getSetting('test')) { ?>
|
14 |
-
<p> Cart Defender Actions module is running in TEST MODE. </p>
|
15 |
<?php } ?>
|
16 |
<script type='text/javascript'>
|
17 |
/* <![CDATA[ */
|
11 |
|
12 |
<?php if ($this->getSetting('enabled')) { ?>
|
13 |
<?php if ($this->getSetting('test')) { ?>
|
14 |
+
<p hidden> Cart Defender Actions module is running in TEST MODE. </p>
|
15 |
<?php } ?>
|
16 |
<script type='text/javascript'>
|
17 |
/* <![CDATA[ */
|
package.xml
CHANGED
@@ -1,19 +1,19 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>cartdefender_actions</name>
|
4 |
-
<version>2.1.
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://opensource.org/licenses/osl-3.0.php">Open Software License (OSL)</license>
|
7 |
<channel>community</channel>
|
8 |
<extends/>
|
9 |
<summary>Increase sales with this state-of-the-art product recommendations and targeted popups, including a FREE exit intent message. Engage your visitors in real time or later via email!</summary>
|
10 |
<description>You can instantly use product recommendations, messages and offers which convert your visitors into customers. Start with FREE exit intent messages. Do it without A/B tests, because Cart Defender learns which messages convert the best and adjusts itself automatically.</description>
|
11 |
-
<notes>
|
12 |
</notes>
|
13 |
<authors><author><name>Radoslaw Gliniecki</name><user>Cart_Defender</user><email>radek@cartdefender.com</email></author><author><name>Jan Zankowski</name><user>janzankowski</user><email>jan@cartdefender.com</email></author><author><name>Przemyslaw Gliniecki</name><user>psgliniecki</user><email>psg@cartdefender.com</email></author></authors>
|
14 |
-
<date>2017-
|
15 |
-
<time>
|
16 |
-
<contents><target name="magecommunity"><dir name="CartDefender"><dir name="Actions"><dir name="Block"><file name="Script.php" hash="247305c63594b6442e94122b226e3bb2"/></dir><dir name="Helper"><file name="Data.php" hash="
|
17 |
<compatible/>
|
18 |
<dependencies><required><php><min>5.3.0</min><max>6.0.0</max></php><package><name>Mage_Core_Modules</name><channel>community</channel><min>1.7.0.2</min><max>1.9.3.2</max></package><extension><name>openssl</name><min>0.9.6</min><max>1.1.0</max></extension></required></dependencies>
|
19 |
</package>
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>cartdefender_actions</name>
|
4 |
+
<version>2.1.8</version>
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://opensource.org/licenses/osl-3.0.php">Open Software License (OSL)</license>
|
7 |
<channel>community</channel>
|
8 |
<extends/>
|
9 |
<summary>Increase sales with this state-of-the-art product recommendations and targeted popups, including a FREE exit intent message. Engage your visitors in real time or later via email!</summary>
|
10 |
<description>You can instantly use product recommendations, messages and offers which convert your visitors into customers. Start with FREE exit intent messages. Do it without A/B tests, because Cart Defender learns which messages convert the best and adjusts itself automatically.</description>
|
11 |
+
<notes>Compatibility updates in data gathering
|
12 |
</notes>
|
13 |
<authors><author><name>Radoslaw Gliniecki</name><user>Cart_Defender</user><email>radek@cartdefender.com</email></author><author><name>Jan Zankowski</name><user>janzankowski</user><email>jan@cartdefender.com</email></author><author><name>Przemyslaw Gliniecki</name><user>psgliniecki</user><email>psg@cartdefender.com</email></author></authors>
|
14 |
+
<date>2017-05-04</date>
|
15 |
+
<time>13:59:52</time>
|
16 |
+
<contents><target name="magecommunity"><dir name="CartDefender"><dir name="Actions"><dir name="Block"><file name="Script.php" hash="247305c63594b6442e94122b226e3bb2"/></dir><dir name="Helper"><file name="Data.php" hash="f6da7288d3b111b4e9d82aeee64aebb6"/><file name="Logger.php" hash="aca3233298074d3cf8f436e668969bb9"/></dir><dir name="Model"><dir name="Api"><file name="V2.php" hash="64b8b03a84578a6f9a1fbf1321e109f2"/></dir><file name="Api.php" hash="a2d9ede9d01bb14ff31ebd792c9bbc51"/><file name="AsyncLocalSender.php" hash="2e22d4c07c7f983d98687d6faa6fe413"/><file name="CorrelationIdManager.php" hash="56f619241fdec54bcc4457937af893b8"/><file name="EventAsyncLocalSender.php" hash="4bcc43959212d0610e3e4b653d01c6cc"/><file name="EventBuilder.php" hash="18f0e4637a03fb6ea767fcab375a0984"/><file name="Observer.php" hash="44922ecc47fdf4a60fa86b929c5877c8"/><dir name="System"><dir name="Config"><dir name="Source"><file name="Transport.php" hash="f63ca41ae1242de7bb18854d0f450b00"/></dir></dir></dir></dir><dir name="controllers"><file name="CartDefenderSenderController.php" hash="c3fb495d4ad88ac658867c77447d2b2b"/></dir><dir name="etc"><file name="api.xml" hash="3d9558fa5df621470460d4c9d62ba7f3"/><file name="config.xml" hash="ec73ff2a9115f7150b034f3e6eacd163"/><file name="system.xml" hash="3bc66fa6869648811f2283f54abac2f5"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="CartDefender_Actions.xml" hash="f9e77235e41f79ac086160ef2e494837"/></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="actions"><file name="script.phtml" hash="4de68c84b01a9532595d2d13c494ef6c"/></dir></dir><dir name="layout"><file name="actions.xml" hash="e6a4b2f6d8132a833a1b5f8b9fce7166"/></dir></dir></dir></dir></target></contents>
|
17 |
<compatible/>
|
18 |
<dependencies><required><php><min>5.3.0</min><max>6.0.0</max></php><package><name>Mage_Core_Modules</name><channel>community</channel><min>1.7.0.2</min><max>1.9.3.2</max></package><extension><name>openssl</name><min>0.9.6</min><max>1.1.0</max></extension></required></dependencies>
|
19 |
</package>
|