choiceai - Version 1.0.9

Version Notes

Initial Code

Download this release

Release Info

Developer MineWhat Inc.
Extension choiceai
Version 1.0.9
Comparing to
See all releases


Code changes from version 1.0.8 to 1.0.9

Files changed (75) hide show
  1. app/code/community/ChoiceAI/Personalisation/controllers/ApiController.php +220 -16
  2. app/code/local/ChoiceAI/Search/Block/Catalog/Layer/Filter/Attribute.php +45 -0
  3. app/code/local/ChoiceAI/Search/Block/Catalog/Layer/Filter/Boolean.php +20 -0
  4. app/code/local/ChoiceAI/Search/Block/Catalog/Layer/Filter/Category.php +33 -0
  5. app/code/local/ChoiceAI/Search/Block/Catalog/Layer/Filter/Decimal.php +45 -0
  6. app/code/local/ChoiceAI/Search/Block/Catalog/Layer/Filter/Price.php +50 -0
  7. app/code/local/ChoiceAI/Search/Block/Catalog/Layer/View.php +120 -0
  8. app/code/local/ChoiceAI/Search/Block/Catalog/Product/List.php +52 -0
  9. app/code/local/ChoiceAI/Search/Block/Catalog/Product/List/Toolbar.php +34 -0
  10. app/code/local/ChoiceAI/Search/Block/Catalogsearch/Enterprise/Layer.php +115 -0
  11. app/code/local/ChoiceAI/Search/Block/Catalogsearch/Layer.php +115 -0
  12. app/code/local/ChoiceAI/Search/Block/Catalogsearch/Layer/Filter/Attribute.php +46 -0
  13. app/code/local/ChoiceAI/Search/Block/Catalogsearch/Result.php +36 -0
  14. app/code/local/ChoiceAI/Search/Helper/Catalogsearch.php +19 -0
  15. app/code/local/ChoiceAI/Search/Helper/Choiceaisearch.php +16 -0
  16. app/code/local/ChoiceAI/Search/Helper/Data.php +670 -0
  17. app/code/local/ChoiceAI/Search/Model/Catalog/Category.php +74 -0
  18. app/code/local/ChoiceAI/Search/Model/Catalog/Config.php +120 -0
  19. app/code/local/ChoiceAI/Search/Model/Catalog/Layer.php +37 -0
  20. app/code/local/ChoiceAI/Search/Model/Catalog/Layer/Filter/Attribute.php +168 -0
  21. app/code/local/ChoiceAI/Search/Model/Catalog/Layer/Filter/Boolean.php +41 -0
  22. app/code/local/ChoiceAI/Search/Model/Catalog/Layer/Filter/Category.php +132 -0
  23. app/code/local/ChoiceAI/Search/Model/Catalog/Layer/Filter/Decimal.php +190 -0
  24. app/code/local/ChoiceAI/Search/Model/Catalog/Layer/Filter/Price.php +154 -0
  25. app/code/local/ChoiceAI/Search/Model/Catalogsearch/Layer.php +31 -0
  26. app/code/local/ChoiceAI/Search/Model/Catalogsearch/Layer/Filter/Attribute.php +16 -0
  27. app/code/local/ChoiceAI/Search/Model/Resource/Catalog/Product/Collection.php +368 -0
  28. app/code/local/ChoiceAI/Search/Model/Resource/Engine/Abstract.php +453 -0
  29. app/code/local/ChoiceAI/Search/Model/Resource/Engine/Choiceaisearch.php +242 -0
  30. app/code/local/ChoiceAI/Search/Model/Resource/Engine/Choiceaisearch/Client.php +29 -0
  31. app/code/local/ChoiceAI/Search/etc/config.xml +101 -0
  32. app/code/local/ChoiceAI/Searchcore/Helper/Confighelper.php +472 -0
  33. app/code/local/ChoiceAI/Searchcore/Helper/Constants.php +195 -0
  34. app/code/local/ChoiceAI/Searchcore/Helper/Data.php +233 -0
  35. app/code/local/ChoiceAI/Searchcore/Helper/Feedhelper.php +288 -0
  36. app/code/local/ChoiceAI/Searchcore/Model/Api/Request.php +212 -0
  37. app/code/local/ChoiceAI/Searchcore/Model/Api/Response.php +165 -0
  38. app/code/local/ChoiceAI/Searchcore/Model/Api/Task.php +84 -0
  39. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Analyticsimpression.php +49 -0
  40. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Autosuggestindex.php +52 -0
  41. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Feeddetails.php +71 -0
  42. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Searchimpression.php +57 -0
  43. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Searchsetup.php +52 -0
  44. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Supportmail.php +48 -0
  45. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Trackcart.php +46 -0
  46. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Trackorder.php +46 -0
  47. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Triggerfeedupload.php +42 -0
  48. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Updatefeaturefields.php +83 -0
  49. app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Validatekeys.php +73 -0
  50. app/code/local/ChoiceAI/Searchcore/Model/Config.php +47 -0
  51. app/code/local/ChoiceAI/Searchcore/Model/Field.php +342 -0
  52. app/code/local/ChoiceAI/Searchcore/Model/Observer.php +201 -0
  53. app/code/local/ChoiceAI/Searchcore/Model/Resource/Attribute.php +27 -0
  54. app/code/local/ChoiceAI/Searchcore/Model/Resource/Config.php +213 -0
  55. app/code/local/ChoiceAI/Searchcore/Model/Resource/Config/Collection.php +21 -0
  56. app/code/local/ChoiceAI/Searchcore/Model/Resource/Field.php +146 -0
  57. app/code/local/ChoiceAI/Searchcore/Model/Resource/Field/Collection.php +66 -0
  58. app/code/local/ChoiceAI/Searchcore/Model/Resource/Product/Collection.php +110 -0
  59. app/code/local/ChoiceAI/Searchcore/etc/config.xml +133 -0
  60. app/code/local/ChoiceAI/Searchcore/sql/choiceai_searchcore_setup/mysql4-install-1.0.0.php +91 -0
  61. app/code/local/ChoiceAI/Searchcore/sql/choiceai_searchcore_setup/upgrade-1.0.21-1.0.22.php +46 -0
  62. app/design/frontend/base/default/template/choiceai/personalisation/base/script.phtml +1 -0
  63. app/design/frontend/base/default/template/choiceai/personalisation/event/checkout/onepage/success.phtml +0 -21
  64. app/design/frontend/default/default/template/choiceai/personalisation/base/script.phtml +5 -0
  65. app/design/frontend/default/default/template/choiceai/personalisation/event/catalog/product/view.phtml +0 -61
  66. app/design/frontend/default/default/template/choiceai/personalisation/event/checkout/cart/index.phtml +0 -17
  67. app/design/frontend/default/default/template/choiceai/personalisation/event/checkout/onepage/success.phtml +0 -20
  68. app/etc/modules/ChoiceAI_Personalisation.xml +8 -0
  69. lib/ChoiceAI/Client.php +304 -0
  70. lib/ChoiceAI/Response.php +45 -0
  71. lib/ChoiceAI/Result.php +65 -0
  72. lib/ChoiceAI/ResultSet.php +229 -0
  73. lib/ChoiceAI/Service.php +190 -0
  74. lib/ChoiceAI/test.php +53 -0
  75. package.xml +5 -5
app/code/community/ChoiceAI/Personalisation/controllers/ApiController.php CHANGED
@@ -10,6 +10,8 @@
10
  class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_Action {
11
 
12
  const CONFIG_API_KEY = 'choiceai_personalisation/settings/api_key';
 
 
13
 
14
  public function _authorise() {
15
 
@@ -19,7 +21,7 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
19
  if(!$API_KEY && strlen($API_KEY) === 0) {
20
  // Api access disabled
21
  $this->getResponse()
22
- ->setBody(json_encode(array('status' => 'error', 'message' => 'API access disabled', 'version' => 2)))
23
  ->setHttpResponseCode(403)
24
  ->setHeader('Content-type', 'application/json', true);
25
  return false;
@@ -36,7 +38,7 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
36
  Mage::log('Unable to extract authorization header from request', null, 'choiceai.log');
37
  // Internal server error
38
  $this->getResponse()
39
- ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error, Authorization header not found', 'version' => 2)))
40
  ->setHttpResponseCode(500)
41
  ->setHeader('Content-type', 'application/json', true);
42
  return false;
@@ -45,7 +47,7 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
45
  if(trim($authHeader) !== trim($API_KEY)) {
46
  // Api access denied
47
  $this->getResponse()
48
- ->setBody(json_encode(array('status' => 'error', 'message' => 'Api access denied', 'version' => 2)))
49
  ->setHttpResponseCode(401)
50
  ->setHeader('Content-type', 'application/json', true);
51
  return false;
@@ -55,6 +57,56 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
55
 
56
  }
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  public function ordersAction() {
59
 
60
  try {
@@ -109,7 +161,7 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
109
  }
110
  }
111
 
112
- $responseObj['version'] = 2;
113
  $this->getResponse()
114
  ->setBody(json_encode($responseObj))
115
  ->setHttpResponseCode(200)
@@ -141,7 +193,7 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
141
  }
142
 
143
  $this->getResponse()
144
- ->setBody(json_encode(array('orders' => $orders, 'fromDate' => $fromDate, 'toDate' => $toDate, 'version' => 2)))
145
  ->setHttpResponseCode(200)
146
  ->setHeader('Content-type', 'application/json', true);
147
 
@@ -149,7 +201,7 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
149
 
150
  } catch(Exception $e) {
151
  $this->getResponse()
152
- ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => 2)))
153
  ->setHttpResponseCode(500)
154
  ->setHeader('Content-type', 'application/json', true);
155
  }
@@ -158,6 +210,106 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
158
 
159
  }
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  public function productsAction() {
162
 
163
  try {
@@ -225,14 +377,14 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
225
  $currency = Mage::app()->getStore()->getCurrentCurrencyCode();
226
 
227
  $this->getResponse()
228
- ->setBody(json_encode(array('products' => $products, 'currency' => $currency, 'version' => 2)))
229
  ->setHttpResponseCode(200)
230
  ->setHeader('Content-type', 'application/json', true);
231
 
232
 
233
  } catch(Exception $e) {
234
  $this->getResponse()
235
- ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => 2)))
236
  ->setHttpResponseCode(500)
237
  ->setHeader('Content-type', 'application/json', true);
238
  }
@@ -318,14 +470,14 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
318
  }
319
 
320
  $this->getResponse()
321
- ->setBody(json_encode(array('categories' => $categories, 'version' => 2)))
322
  ->setHttpResponseCode(200)
323
  ->setHeader('Content-type', 'application/json', true);
324
 
325
 
326
  } catch(Exception $e) {
327
  $this->getResponse()
328
- ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => 2)))
329
  ->setHttpResponseCode(500)
330
  ->setHeader('Content-type', 'application/json', true);
331
  }
@@ -398,13 +550,13 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
398
 
399
 
400
  $this->getResponse()
401
- ->setBody(json_encode(array('users' => $users, 'version' => 2)))
402
  ->setHttpResponseCode(200)
403
  ->setHeader('Content-type', 'application/json', true);
404
 
405
  } catch(Exception $e) {
406
  $this->getResponse()
407
- ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => 2)))
408
  ->setHttpResponseCode(500)
409
  ->setHeader('Content-type', 'application/json', true);
410
  }
@@ -429,7 +581,7 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
429
  if(!$productId || strlen($productId) <= 0) {
430
 
431
  $this->getResponse()
432
- ->setBody(json_encode(array('status' => 'error', 'message' => 'product id required', 'version' => 2)))
433
  ->setHttpResponseCode(500)
434
  ->setHeader('Content-type', 'application/json', true);
435
 
@@ -440,7 +592,7 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
440
  $product = Mage::getModel('catalog/product')->loadByAttribute('sku', $productId);
441
  if($product == null) {
442
  $this->getResponse()
443
- ->setBody(json_encode(array('status' => 'error', 'message' => 'invalid sku', 'version' => 2)))
444
  ->setHttpResponseCode(500)
445
  ->setHeader('Content-type', 'application/json', true);
446
  return $this;
@@ -454,7 +606,7 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
454
  $stock = $stockObj->getQty();
455
 
456
  $this->getResponse()
457
- ->setBody(json_encode(array('id' => $productId, 'stock' => $stock, 'version' => 2)))
458
  ->setHttpResponseCode(200)
459
  ->setHeader('Content-type', 'application/json', true);
460
 
@@ -462,7 +614,7 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
462
 
463
  } catch(Exception $e) {
464
  $this->getResponse()
465
- ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => 2)))
466
  ->setHttpResponseCode(500)
467
  ->setHeader('Content-type', 'application/json', true);
468
  }
@@ -563,4 +715,56 @@ class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_
563
 
564
  }
565
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
566
  }
10
  class ChoiceAI_Personalisation_ApiController extends Mage_Core_Controller_Front_Action {
11
 
12
  const CONFIG_API_KEY = 'choiceai_personalisation/settings/api_key';
13
+ const CONFIG_KEY = 'choiceai_personalisation/settings/config';
14
+ const API_VERSION = 3;
15
 
16
  public function _authorise() {
17
 
21
  if(!$API_KEY && strlen($API_KEY) === 0) {
22
  // Api access disabled
23
  $this->getResponse()
24
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'API access disabled', 'version' => self::API_VERSION)))
25
  ->setHttpResponseCode(403)
26
  ->setHeader('Content-type', 'application/json', true);
27
  return false;
38
  Mage::log('Unable to extract authorization header from request', null, 'choiceai.log');
39
  // Internal server error
40
  $this->getResponse()
41
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error, Authorization header not found', 'version' => self::API_VERSION)))
42
  ->setHttpResponseCode(500)
43
  ->setHeader('Content-type', 'application/json', true);
44
  return false;
47
  if(trim($authHeader) !== trim($API_KEY)) {
48
  // Api access denied
49
  $this->getResponse()
50
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'Api access denied', 'version' => self::API_VERSION)))
51
  ->setHttpResponseCode(401)
52
  ->setHeader('Content-type', 'application/json', true);
53
  return false;
57
 
58
  }
59
 
60
+ public function configAction() {
61
+
62
+ try {
63
+
64
+ if(!$this->_authorise()) {
65
+ return $this;
66
+ }
67
+
68
+ $responseObj = array();
69
+
70
+ if ($_SERVER["REQUEST_METHOD"] == "GET") {
71
+ $STORE_CONFIG = Mage::getStoreConfig(self::CONFIG_KEY);
72
+ $responseObj["status"] = "ok";
73
+ $responseObj["config"] = json_decode($STORE_CONFIG);
74
+ } else if ($_SERVER["REQUEST_METHOD"] == "PUT") {
75
+ $store_config = $this->getRequest()->getParam('config');
76
+ if($store_config ==""){
77
+ $input = file_get_contents('php://input');
78
+ $input = utf8_encode($input);
79
+ $store_config = json_encode(json_decode($input)->config);
80
+ }
81
+ $store_config_json = json_decode($store_config);
82
+ if ($store_config_json == NULL) {
83
+ throw new Exception();
84
+ }
85
+ Mage::getModel('core/config')->saveConfig(self::CONFIG_KEY, $store_config);
86
+ Mage::app()->getStore()->resetConfig();
87
+ $responseObj["status"] = "ok";
88
+ } else {
89
+ $responseObj['status'] = 'error';
90
+ $responseObj['message'] = 'Invalid request';
91
+ }
92
+
93
+ $responseObj['version'] = self::API_VERSION;
94
+ $this->getResponse()
95
+ ->setBody(json_encode($responseObj))
96
+ ->setHttpResponseCode(200)
97
+ ->setHeader('Content-type', 'application/json', true);
98
+
99
+ } catch(Exception $e) {
100
+ $this->getResponse()
101
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => self::API_VERSION)))
102
+ ->setHttpResponseCode(500)
103
+ ->setHeader('Content-type', 'application/json', true);
104
+ }
105
+
106
+ return this;
107
+
108
+ }
109
+
110
  public function ordersAction() {
111
 
112
  try {
161
  }
162
  }
163
 
164
+ $responseObj['version'] = self::API_VERSION;
165
  $this->getResponse()
166
  ->setBody(json_encode($responseObj))
167
  ->setHttpResponseCode(200)
193
  }
194
 
195
  $this->getResponse()
196
+ ->setBody(json_encode(array('orders' => $orders, 'fromDate' => $fromDate, 'toDate' => $toDate, 'version' => self::API_VERSION)))
197
  ->setHttpResponseCode(200)
198
  ->setHeader('Content-type', 'application/json', true);
199
 
201
 
202
  } catch(Exception $e) {
203
  $this->getResponse()
204
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => self::API_VERSION)))
205
  ->setHttpResponseCode(500)
206
  ->setHeader('Content-type', 'application/json', true);
207
  }
210
 
211
  }
212
 
213
+ public function productattributesAction() {
214
+
215
+ try {
216
+
217
+ if(!$this->_authorise()) {
218
+ return $this;
219
+ }
220
+
221
+ $sections = explode('/', trim($this->getRequest()->getPathInfo(), '/'));
222
+
223
+ if(!isset($sections[3])) {
224
+
225
+ throw new Exception();
226
+
227
+ }
228
+
229
+ $productId = $sections[3];
230
+
231
+ $product = Mage::getModel('catalog/product')->load($productId);
232
+
233
+ $product_info = array();
234
+
235
+ $product_info["is_available"] = $product->isAvailable();
236
+ $product_info["name"] = $product->getName();
237
+ $product_info["id"] = $product->getId();
238
+ $product_info["sku"] = $product->getSku();
239
+ $product_info["price"] = $product->getPrice();
240
+ $product_info["final_price"] = $product->getFinalPrice();
241
+ $product_info["special_price"] = $product->getSpecialPrice();
242
+ $product_info["type"] = $product->getTypeId();
243
+
244
+ $variants = array();
245
+ $options = array();
246
+
247
+ if ($product->getTypeId() == "configurable") {
248
+
249
+ $productAttributeOptions = $product->getTypeInstance(true)->getConfigurableAttributesAsArray($product);
250
+ $attributeTypes = array();
251
+
252
+ foreach ($productAttributeOptions as $productAttribute) {
253
+
254
+ $attributes = array();
255
+ foreach ($productAttribute['values'] as $attribute) {
256
+ $attributes[] = array(
257
+ "id" => $attribute["value_index"],
258
+ "name" => $attribute["store_label"]
259
+ );
260
+ }
261
+
262
+ $attributeType = $productAttribute["attribute_code"];
263
+ $options[] = array(
264
+ "id" => $productAttribute["id"],
265
+ "key" => $attributeType,
266
+ "name" => $productAttribute["store_label"],
267
+ "values" => $attributes,
268
+ "position" => $productAttribute["position"]
269
+ );
270
+
271
+ $attributeTypes[] = $attributeType;
272
+
273
+ }
274
+
275
+ $associatedProducts = $product->getTypeInstance()->getUsedProducts();
276
+ foreach ($associatedProducts as $associatedProduct) {
277
+
278
+ $variant = array();
279
+ $variant["is_available"] = $associatedProduct->isAvailable();
280
+ $variant["id"] = $associatedProduct->getId();
281
+ $variant["sku"] = $associatedProduct->getSku();
282
+ $variant["price"] = $associatedProduct->getPrice();
283
+ $variant["final_price"] = $associatedProduct->getFinalPrice();
284
+ $variant["special_price"] = $associatedProduct->getSpecialPrice();
285
+
286
+ $associatedProductData = $associatedProduct->getData();
287
+ foreach ($attributeTypes as $attributeType) {
288
+ $variant[$attributeType] = $associatedProductData[$attributeType];
289
+ }
290
+
291
+ $variants[] = $variant;
292
+
293
+ }
294
+
295
+ }
296
+
297
+ $this->getResponse()
298
+ ->setBody(json_encode(array('product' => $product_info, 'variants' => $variants, 'options' => $options, 'version' => self::API_VERSION)))
299
+ ->setHttpResponseCode(200)
300
+ ->setHeader('Content-type', 'application/json', true);
301
+
302
+ } catch(Exception $e) {
303
+ $this->getResponse()
304
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => self::API_VERSION)))
305
+ ->setHttpResponseCode(500)
306
+ ->setHeader('Content-type', 'application/json', true);
307
+ }
308
+
309
+ return $this;
310
+
311
+ }
312
+
313
  public function productsAction() {
314
 
315
  try {
377
  $currency = Mage::app()->getStore()->getCurrentCurrencyCode();
378
 
379
  $this->getResponse()
380
+ ->setBody(json_encode(array('products' => $products, 'currency' => $currency, 'version' => self::API_VERSION)))
381
  ->setHttpResponseCode(200)
382
  ->setHeader('Content-type', 'application/json', true);
383
 
384
 
385
  } catch(Exception $e) {
386
  $this->getResponse()
387
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => self::API_VERSION)))
388
  ->setHttpResponseCode(500)
389
  ->setHeader('Content-type', 'application/json', true);
390
  }
470
  }
471
 
472
  $this->getResponse()
473
+ ->setBody(json_encode(array('categories' => $categories, 'version' => self::API_VERSION)))
474
  ->setHttpResponseCode(200)
475
  ->setHeader('Content-type', 'application/json', true);
476
 
477
 
478
  } catch(Exception $e) {
479
  $this->getResponse()
480
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => self::API_VERSION)))
481
  ->setHttpResponseCode(500)
482
  ->setHeader('Content-type', 'application/json', true);
483
  }
550
 
551
 
552
  $this->getResponse()
553
+ ->setBody(json_encode(array('users' => $users, 'version' => self::API_VERSION)))
554
  ->setHttpResponseCode(200)
555
  ->setHeader('Content-type', 'application/json', true);
556
 
557
  } catch(Exception $e) {
558
  $this->getResponse()
559
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => self::API_VERSION)))
560
  ->setHttpResponseCode(500)
561
  ->setHeader('Content-type', 'application/json', true);
562
  }
581
  if(!$productId || strlen($productId) <= 0) {
582
 
583
  $this->getResponse()
584
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'product id required', 'version' => self::API_VERSION)))
585
  ->setHttpResponseCode(500)
586
  ->setHeader('Content-type', 'application/json', true);
587
 
592
  $product = Mage::getModel('catalog/product')->loadByAttribute('sku', $productId);
593
  if($product == null) {
594
  $this->getResponse()
595
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'invalid sku', 'version' => self::API_VERSION)))
596
  ->setHttpResponseCode(500)
597
  ->setHeader('Content-type', 'application/json', true);
598
  return $this;
606
  $stock = $stockObj->getQty();
607
 
608
  $this->getResponse()
609
+ ->setBody(json_encode(array('id' => $productId, 'stock' => $stock, 'version' => self::API_VERSION)))
610
  ->setHttpResponseCode(200)
611
  ->setHeader('Content-type', 'application/json', true);
612
 
614
 
615
  } catch(Exception $e) {
616
  $this->getResponse()
617
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => self::API_VERSION)))
618
  ->setHttpResponseCode(500)
619
  ->setHeader('Content-type', 'application/json', true);
620
  }
715
 
716
  }
717
 
718
+ public function sortbyAction() {
719
+
720
+ try {
721
+
722
+ if(!$this->_authorise()) {
723
+ return $this;
724
+ }
725
+
726
+ $sortByOptions = array();
727
+ // $attributesData = Mage::getResourceModel('catalog/config')->getAttributesUsedForSortBy();
728
+
729
+ // foreach ($attributesData as $attributeData) {
730
+ // $sortByOptions[$attributeData['attribute_code']] = array(
731
+ // "attribute_id"=> $attributeData['attribute_id'],
732
+ // "attribute_code"=> $attributeData['attribute_code'],
733
+ // "frontend_label"=> $attributeData['frontend_label'],
734
+ // "store_label"=> $attributeData['store_label']
735
+ // );
736
+ // }
737
+
738
+ $category = Mage::getModel('catalog/category');
739
+
740
+ $attributesData = $category->getAvailableSortByOptions();
741
+ $defaultSort = $category->getDefaultSortBy();
742
+
743
+ $i = 1;
744
+
745
+ foreach ($attributesData as $key => $attributeData) {
746
+ $sortByOptions[] = array(
747
+ "_id"=> $key,
748
+ "name"=> $attributeData,
749
+ "default"=> $key==$defaultSort ? true:false,
750
+ "order"=> $i
751
+ );
752
+ $i++;
753
+ }
754
+
755
+ $this->getResponse()
756
+ ->setBody(json_encode(array('status' => "ok", 'options' => $sortByOptions, 'version' => self::API_VERSION)))
757
+ ->setHttpResponseCode(200)
758
+ ->setHeader('Content-type', 'application/json', true);
759
+
760
+ } catch(Exception $e) {
761
+ $this->getResponse()
762
+ ->setBody(json_encode(array('status' => 'error', 'message' => 'Internal server error', 'version' => self::API_VERSION)))
763
+ ->setHttpResponseCode(500)
764
+ ->setHeader('Content-type', 'application/json', true);
765
+ }
766
+
767
+ return $this;
768
+ }
769
+
770
  }
app/code/local/ChoiceAI/Search/Block/Catalog/Layer/Filter/Attribute.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @package ChoiceAI_Search
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Search_Block_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Block_Layer_Filter_Abstract
9
+ {
10
+ /**
11
+ * Defines specific filter model name.
12
+ *
13
+ * @see ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute
14
+ */
15
+ public function __construct()
16
+ {
17
+ parent::__construct();
18
+ $this->_filterModelName = 'choiceai_search/catalog_layer_filter_attribute';
19
+ }
20
+
21
+ /**
22
+ * Prepares filter model.
23
+ *
24
+ * @return ChoiceAI_Search_Block_Catalog_Layer_Filter_Attribute
25
+ */
26
+ protected function _prepareFilter()
27
+ {
28
+ $this->_filter->setAttributeModel($this->getAttributeModel());
29
+
30
+ return $this;
31
+ }
32
+
33
+ /**
34
+ * Adds facet condition to filter.
35
+ *
36
+ * @see ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute::addFacetCondition()
37
+ * @return ChoiceAI_Search_Block_Catalog_Layer_Filter_Attribute
38
+ */
39
+ public function addFacetCondition()
40
+ {
41
+ $this->_filter->addFacetCondition();
42
+
43
+ return $this;
44
+ }
45
+ }
app/code/local/ChoiceAI/Search/Block/Catalog/Layer/Filter/Boolean.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @package ChoiceAI_Search
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Search_Block_Catalog_Layer_Filter_Boolean extends ChoiceAI_Search_Block_Catalog_Layer_Filter_Attribute
9
+ {
10
+ /**
11
+ * Defines specific filter model name.
12
+ *
13
+ * @see ChoiceAI_Search_Model_Catalog_Layer_Filter_Boolean
14
+ */
15
+ public function __construct()
16
+ {
17
+ parent::__construct();
18
+ $this->_filterModelName = 'choiceai_search/catalog_layer_filter_boolean';
19
+ }
20
+ }
app/code/local/ChoiceAI/Search/Block/Catalog/Layer/Filter/Category.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @package ChoiceAI_Search
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Search_Block_Catalog_Layer_Filter_Category extends Mage_Catalog_Block_Layer_Filter_Abstract
9
+ {
10
+ /**
11
+ * Defines specific filter model name.
12
+ *
13
+ * @see ChoiceAI_Search_Model_Catalog_Layer_Filter_Category
14
+ */
15
+ public function __construct()
16
+ {
17
+ parent::__construct();
18
+ $this->_filterModelName = 'choiceai_search/catalog_layer_filter_category';
19
+ }
20
+
21
+ /**
22
+ * Adds facet condition to filter.
23
+ *
24
+ * @see ChoiceAI_Search_Model_Catalog_Layer_Filter_Category::addFacetCondition()
25
+ * @return ChoiceAI_Search_Block_Catalog_Layer_Filter_Attribute
26
+ */
27
+ public function addFacetCondition()
28
+ {
29
+ $this->_filter->addFacetCondition();
30
+
31
+ return $this;
32
+ }
33
+ }
app/code/local/ChoiceAI/Search/Block/Catalog/Layer/Filter/Decimal.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @package ChoiceAI_Search
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Search_Block_Catalog_Layer_Filter_Decimal extends Mage_Catalog_Block_Layer_Filter_Abstract
9
+ {
10
+ /**
11
+ * Defines specific filter model name.
12
+ *
13
+ * @see ChoiceAI_Search_Model_Catalog_Layer_Filter_Decimal
14
+ */
15
+ public function __construct()
16
+ {
17
+ parent::__construct();
18
+ $this->_filterModelName = 'choiceai_search/catalog_layer_filter_decimal';
19
+ }
20
+
21
+ /**
22
+ * Prepares filter model.
23
+ *
24
+ * @return ChoiceAI_Search_Block_Catalog_Layer_Filter_Decimal
25
+ */
26
+ protected function _prepareFilter()
27
+ {
28
+ $this->_filter->setAttributeModel($this->getAttributeModel());
29
+
30
+ return $this;
31
+ }
32
+
33
+ /**
34
+ * Adds facet condition to filter.
35
+ *
36
+ * @see ChoiceAI_Search_Model_Catalog_Layer_Filter_Decimal::addFacetCondition()
37
+ * @return ChoiceAI_Search_Block_Catalog_Layer_Filter_Decimal
38
+ */
39
+ public function addFacetCondition()
40
+ {
41
+ $this->_filter->addFacetCondition();
42
+
43
+ return $this;
44
+ }
45
+ }
app/code/local/ChoiceAI/Search/Block/Catalog/Layer/Filter/Price.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @package ChoiceAI_Search
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Search_Block_Catalog_Layer_Filter_Price extends Mage_Catalog_Block_Layer_Filter_Abstract
9
+ {
10
+ /**
11
+ * Defines specific filter model name.
12
+ *
13
+ * @see ChoiceAI_Search_Model_Catalog_Layer_Filter_Price
14
+ */
15
+ public function __construct()
16
+ {
17
+ parent::__construct();
18
+ $this->_filterModelName = 'choiceai_search/catalog_layer_filter_price';
19
+ }
20
+
21
+ /**
22
+ * Prepares filter model.
23
+ *
24
+ * @return ChoiceAI_Search_Block_Catalog_Layer_Filter_Price
25
+ */
26
+ protected function _prepareFilter()
27
+ {
28
+ $this->_filter->setAttributeModel($this->getAttributeModel());
29
+
30
+ return $this;
31
+ }
32
+
33
+ /**
34
+ * Adds facet condition to filter.
35
+ *
36
+ * @see ChoiceAI_Search_Model_Catalog_Layer_Filter_Price::addFacetCondition()
37
+ * @return ChoiceAI_Search_Block_Catalog_Layer_Filter_Price
38
+ */
39
+ public function addFacetCondition()
40
+ {
41
+ if (!$this->getRequest()->getParam('price')) {
42
+ $this->_filter->addFacetCondition();
43
+ }
44
+
45
+ return $this;
46
+ }
47
+
48
+
49
+
50
+ }
app/code/local/ChoiceAI/Search/Block/Catalog/Layer/View.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Overrides default layer view process to define custom filter blocks.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Block_Catalog_Layer_View extends Mage_Catalog_Block_Layer_View
10
+ {
11
+ /**
12
+ * Boolean block name.
13
+ *
14
+ * @var string
15
+ */
16
+ protected $_booleanFilterBlockName;
17
+
18
+ /**
19
+ * Registers current layer in registry.
20
+ *
21
+ * @see Mage_Catalog_Block_Product_List::getLayer()
22
+ */
23
+ protected function _construct()
24
+ {
25
+ parent::_construct();
26
+ Mage::unregister('current_layer');
27
+ Mage::register('current_layer', $this->getLayer());
28
+ }
29
+
30
+ /**
31
+ * Modifies default block names to specific ones if engine is active.
32
+ */
33
+ protected function _initBlocks()
34
+ {
35
+ parent::_initBlocks();
36
+ if (Mage::helper('choiceai_search')->isActiveEngine()) {
37
+ $this->_categoryBlockName = 'choiceai_search/catalog_layer_filter_category';
38
+ $this->_attributeFilterBlockName = 'choiceai_search/catalog_layer_filter_attribute';
39
+ $this->_priceFilterBlockName = 'choiceai_search/catalog_layer_filter_price';
40
+ $this->_decimalFilterBlockName = 'choiceai_search/catalog_layer_filter_decimal';
41
+ $this->_booleanFilterBlockName = 'choiceai_search/catalog_layer_filter_boolean';
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Prepares layout if engine is active.
47
+ * Difference between parent method is addFacetCondition() call on each created block.
48
+ *
49
+ * @return ChoiceAI_Search_Block_Catalog_Layer_View
50
+ */
51
+ protected function _prepareLayout()
52
+ {
53
+ if (Mage::helper('choiceai_search')->isActiveEngine()) {
54
+ $stateBlock = $this->getLayout()->createBlock($this->_stateBlockName)
55
+ ->setLayer($this->getLayer());
56
+
57
+ $categoryBlock = $this->getLayout()->createBlock($this->_categoryBlockName)
58
+ ->setLayer($this->getLayer())
59
+ ->init();
60
+
61
+ $this->setChild('layer_state', $stateBlock);
62
+ $this->setChild('category_filter', $categoryBlock->addFacetCondition());
63
+
64
+ $filterableAttributes = $this->_getFilterableAttributes();
65
+ $filters = array();
66
+ foreach ($filterableAttributes as $attribute) {
67
+ if ($attribute->getAttributeCode() == 'price') {
68
+ $filterBlockName = $this->_priceFilterBlockName;
69
+ } elseif ($attribute->getBackendType() == 'decimal') {
70
+ $filterBlockName = $this->_decimalFilterBlockName;
71
+ } elseif ($attribute->getSourceModel() == 'eav/entity_attribute_source_boolean') {
72
+ $filterBlockName = $this->_booleanFilterBlockName;
73
+ } else {
74
+ $filterBlockName = $this->_attributeFilterBlockName;
75
+ }
76
+
77
+ $filters[$attribute->getAttributeCode() . '_filter'] = $this->getLayout()->createBlock($filterBlockName)
78
+ ->setLayer($this->getLayer())
79
+ ->setAttributeModel($attribute)
80
+ ->init();
81
+ }
82
+
83
+ foreach ($filters as $filterName => $block) {
84
+ $this->setChild($filterName, $block->addFacetCondition());
85
+ }
86
+
87
+ $this->getLayer()->apply();
88
+ $this->getLayer()->getProductCollection()->load();
89
+ } else {
90
+ parent::_prepareLayout();
91
+
92
+ }
93
+
94
+ return $this;
95
+ }
96
+
97
+
98
+ public function getRequest(){
99
+ $controller = Mage::app()->getFrontController();
100
+ if ($controller) {
101
+ $this->_request = $controller->getRequest();
102
+ } else {
103
+ throw new Exception(Mage::helper('core')->__("Can't retrieve request object"));
104
+ }
105
+ return $this->_request;
106
+ }
107
+
108
+ /**
109
+ * Returns current catalog layer.
110
+ *
111
+ * @return ChoiceAI_Search_Model_Catalog_Layer|Mage_Catalog_Model_Layer
112
+ */
113
+ public function getLayer()
114
+ {
115
+ if (Mage::helper('choiceai_search')->isActiveEngine()) {
116
+ return Mage::getSingleton('choiceai_search/catalog_layer');
117
+ }
118
+ return parent::getLayer();
119
+ }
120
+ }
app/code/local/ChoiceAI/Search/Block/Catalog/Product/List.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magento.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magento.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Catalog
23
+ * @copyright Copyright (c) 2006-2017 X.commerce, Inc. and affiliates (http://www.magento.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+
28
+ /**
29
+ * Product list
30
+ *
31
+ * @category Mage
32
+ * @package Mage_Catalog
33
+ * @author Magento Core Team <core@magentocommerce.com>
34
+ */
35
+ class ChoiceAI_Search_Block_Catalog_Product_List extends Mage_Catalog_Block_Product_List
36
+ {
37
+ /**
38
+ * Get catalog layer model
39
+ *
40
+ * @return Mage_Catalog_Model_Layer
41
+ */
42
+ public function getLayer()
43
+ {
44
+ /** @var $helper ChoiceAI_Search_Helper_Data */
45
+ $helper = Mage::helper('choiceai_search');
46
+ if ($helper->isActiveEngine()) {
47
+ return Mage::getSingleton('choiceai_search/catalogsearch_layer');
48
+ }
49
+ return parent::getLayer();
50
+ }
51
+
52
+ }
app/code/local/ChoiceAI/Search/Block/Catalog/Product/List/Toolbar.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: harkirat
5
+ * Date: 16/5/17
6
+ * Time: 6:04 PM
7
+ */
8
+
9
+ class ChoiceAI_Search_Block_Catalog_Product_List_Toolbar extends Mage_Catalog_Block_Product_List_Toolbar {
10
+
11
+ const IS_ACTIVE = 'choiceai_personalisation/settings/active';
12
+
13
+ /**
14
+ * Set default Order field
15
+ *
16
+ * @param string $field
17
+ * @return Mage_Catalog_Block_Product_List_Toolbar
18
+ */
19
+ public function getCurrentOrder()
20
+ {
21
+ // To set currently selected sort by option to extended/overridden one, in case of search/productlist
22
+ if(Mage::getStoreConfig(self::IS_ACTIVE)=='1') {
23
+ if (is_null($_REQUEST['order']) && isset($_SESSION['plist_sort_by'])) {
24
+ return $_SESSION['plist_sort_by'];
25
+ } else if ($_REQUEST['order'] == $_SESSION['plist_sort_by']) {
26
+ return $_SESSION['plist_sort_by'];
27
+ } else{
28
+ return parent::getCurrentOrder();
29
+ }
30
+ } else {
31
+ return parent::getCurrentOrder();
32
+ }
33
+ }
34
+ }
app/code/local/ChoiceAI/Search/Block/Catalogsearch/Enterprise/Layer.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Overrides default layer view process to define custom filter blocks.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Block_Catalogsearch_Enterprise_Layer extends Enterprise_Search_Block_Catalogsearch_Layer
10
+ {
11
+ /**
12
+ * Boolean block name.
13
+ *
14
+ * @var string
15
+ */
16
+ protected $_booleanFilterBlockName;
17
+
18
+ /**
19
+ * Modifies default block names to specific ones if engine is active.
20
+ */
21
+ protected function _initBlocks()
22
+ {
23
+ parent::_initBlocks();
24
+
25
+ if (Mage::helper('choiceai_search')->isActiveEngine()) {
26
+ Mage::unregister('current_layer');
27
+ Mage::register('current_layer', $this->getLayer());
28
+ $this->_categoryBlockName = 'choiceai_search/catalog_layer_filter_category';
29
+ $this->_attributeFilterBlockName = 'choiceai_search/catalogsearch_layer_filter_attribute';
30
+ $this->_priceFilterBlockName = 'choiceai_search/catalog_layer_filter_price';
31
+ $this->_decimalFilterBlockName = 'choiceai_search/catalog_layer_filter_decimal';
32
+ $this->_booleanFilterBlockName = 'choiceai_search/catalog_layer_filter_boolean';
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Prepares layout if engine is active.
38
+ * Difference between parent method is addFacetCondition() call on each created block.
39
+ *
40
+ * @return ChoiceAI_Search_Block_Catalogsearch_Layer
41
+ */
42
+ protected function _prepareLayout()
43
+ {
44
+ /** @var $helper ChoiceAI_Search_Helper_Data */
45
+ $helper = Mage::helper('choiceai_search');
46
+ if ($helper->isActiveEngine()) {
47
+
48
+ $stateBlock = $this->getLayout()->createBlock($this->_stateBlockName)
49
+ ->setLayer($this->getLayer());
50
+
51
+ $categoryBlock = $this->getLayout()->createBlock($this->_categoryBlockName)
52
+ ->setLayer($this->getLayer())
53
+ ->init();
54
+
55
+ $this->setChild('layer_state', $stateBlock);
56
+ $this->setChild('category_filter', $categoryBlock->addFacetCondition());
57
+
58
+ $filterableAttributes = $this->_getFilterableAttributes();
59
+ $filters = array();
60
+ foreach ($filterableAttributes as $attribute) {
61
+ if ($attribute->getAttributeCode() == 'price') {
62
+ $filterBlockName = $this->_priceFilterBlockName;
63
+ } elseif ($attribute->getSourceModel() == 'eav/entity_attribute_source_boolean') {
64
+ $filterBlockName = $this->_booleanFilterBlockName;
65
+ } elseif ($attribute->getBackendType() == 'decimal') {
66
+ $filterBlockName = $this->_decimalFilterBlockName;
67
+ } else {
68
+ $filterBlockName = $this->_attributeFilterBlockName;
69
+ }
70
+
71
+ $filters[$attribute->getAttributeCode() . '_filter'] = $this->getLayout()->createBlock($filterBlockName)
72
+ ->setLayer($this->getLayer())
73
+ ->setAttributeModel($attribute)
74
+ ->init();
75
+ }
76
+
77
+ foreach ($filters as $filterName => $block) {
78
+ $this->setChild($filterName, $block->addFacetCondition());
79
+ }
80
+
81
+ $this->getLayer()->apply();
82
+ $this->getLayer()->getProductCollection()->load();
83
+ }else{
84
+ parent::_prepareLayout();
85
+ }
86
+
87
+ return $this;
88
+ }
89
+
90
+ /**
91
+ * Checks display availability of layer block.
92
+ *
93
+ * @return bool
94
+ */
95
+ public function canShowBlock()
96
+ {
97
+ $this->getLayer()->getProductCollection();
98
+ return ($this->canShowOptions() || count($this->getLayer()->getState()->getFilters()));
99
+ }
100
+
101
+ /**
102
+ * Returns current catalog layer.
103
+ *
104
+ * @return ChoiceAI_Search_Model_Catalogsearch_Layer|Mage_Catalog_Model_Layer
105
+ */
106
+ public function getLayer()
107
+ {
108
+ /** @var $helper ChoiceAI_Search_Helper_Data */
109
+ $helper = Mage::helper('choiceai_search');
110
+ if ($helper->isActiveEngine()) {
111
+ return Mage::getSingleton('choiceai_search/catalogsearch_layer');
112
+ }
113
+ return parent::getLayer();
114
+ }
115
+ }
app/code/local/ChoiceAI/Search/Block/Catalogsearch/Layer.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Overrides default layer view process to define custom filter blocks.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Block_Catalogsearch_Layer extends Mage_CatalogSearch_Block_Layer
10
+ {
11
+ /**
12
+ * Boolean block name.
13
+ *
14
+ * @var string
15
+ */
16
+ protected $_booleanFilterBlockName;
17
+
18
+ /**
19
+ * Modifies default block names to specific ones if engine is active.
20
+ */
21
+ protected function _initBlocks()
22
+ {
23
+ parent::_initBlocks();
24
+
25
+ if (Mage::helper('choiceai_search')->isActiveEngine()) {
26
+ Mage::unregister('current_layer');
27
+ Mage::register('current_layer', $this->getLayer());
28
+ $this->_categoryBlockName = 'choiceai_search/catalog_layer_filter_category';
29
+ $this->_attributeFilterBlockName = 'choiceai_search/catalogsearch_layer_filter_attribute';
30
+ $this->_priceFilterBlockName = 'choiceai_search/catalog_layer_filter_price';
31
+ $this->_decimalFilterBlockName = 'choiceai_search/catalog_layer_filter_decimal';
32
+ $this->_booleanFilterBlockName = 'choiceai_search/catalog_layer_filter_boolean';
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Prepares layout if engine is active.
38
+ * Difference between parent method is addFacetCondition() call on each created block.
39
+ *
40
+ * @return ChoiceAI_Search_Block_Catalogsearch_Layer
41
+ */
42
+ protected function _prepareLayout()
43
+ {
44
+ /** @var $helper ChoiceAI_Search_Helper_Data */
45
+ $helper = Mage::helper('choiceai_search');
46
+ if ($helper->isActiveEngine()) {
47
+
48
+ $stateBlock = $this->getLayout()->createBlock($this->_stateBlockName)
49
+ ->setLayer($this->getLayer());
50
+
51
+ $categoryBlock = $this->getLayout()->createBlock($this->_categoryBlockName)
52
+ ->setLayer($this->getLayer())
53
+ ->init();
54
+
55
+ $this->setChild('layer_state', $stateBlock);
56
+ $this->setChild('category_filter', $categoryBlock->addFacetCondition());
57
+
58
+ $filterableAttributes = $this->_getFilterableAttributes();
59
+ $filters = array();
60
+ foreach ($filterableAttributes as $attribute) {
61
+ if ($attribute->getAttributeCode() == 'price') {
62
+ $filterBlockName = $this->_priceFilterBlockName;
63
+ } elseif ($attribute->getSourceModel() == 'eav/entity_attribute_source_boolean') {
64
+ $filterBlockName = $this->_booleanFilterBlockName;
65
+ } elseif ($attribute->getBackendType() == 'decimal') {
66
+ $filterBlockName = $this->_decimalFilterBlockName;
67
+ } else {
68
+ $filterBlockName = $this->_attributeFilterBlockName;
69
+ }
70
+
71
+ $filters[$attribute->getAttributeCode() . '_filter'] = $this->getLayout()->createBlock($filterBlockName)
72
+ ->setLayer($this->getLayer())
73
+ ->setAttributeModel($attribute)
74
+ ->init();
75
+ }
76
+
77
+ foreach ($filters as $filterName => $block) {
78
+ $this->setChild($filterName, $block->addFacetCondition());
79
+ }
80
+
81
+ $this->getLayer()->apply();
82
+ $this->getLayer()->getProductCollection()->load();
83
+ }else{
84
+ parent::_prepareLayout();
85
+ }
86
+
87
+ return $this;
88
+ }
89
+
90
+ /**
91
+ * Checks display availability of layer block.
92
+ *
93
+ * @return bool
94
+ */
95
+ public function canShowBlock()
96
+ {
97
+ $this->getLayer()->getProductCollection();
98
+ return ($this->canShowOptions() || count($this->getLayer()->getState()->getFilters()));
99
+ }
100
+
101
+ /**
102
+ * Returns current catalog layer.
103
+ *
104
+ * @return ChoiceAI_Search_Model_Catalogsearch_Layer|Mage_Catalog_Model_Layer
105
+ */
106
+ public function getLayer()
107
+ {
108
+ /** @var $helper ChoiceAI_Search_Helper_Data */
109
+ $helper = Mage::helper('choiceai_search');
110
+ if ($helper->isActiveEngine()) {
111
+ return Mage::getSingleton('choiceai_search/catalogsearch_layer');
112
+ }
113
+ return parent::getLayer();
114
+ }
115
+ }
app/code/local/ChoiceAI/Search/Block/Catalogsearch/Layer/Filter/Attribute.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handles attribute filtering in layered navigation in a query search context.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Block_Catalogsearch_Layer_Filter_Attribute extends Mage_Catalog_Block_Layer_Filter_Abstract
10
+ {
11
+ /**
12
+ * Defines specific filter model name.
13
+ *
14
+ * @see ChoiceAI_Search_Model_Catalogsearch_Layer_Filter_Attribute
15
+ */
16
+ public function __construct()
17
+ {
18
+ parent::__construct();
19
+ $this->_filterModelName = 'choiceai_search/catalogsearch_layer_filter_attribute';
20
+ }
21
+
22
+ /**
23
+ * Prepares filter model.
24
+ *
25
+ * @return ChoiceAI_Search_Block_Catalogsearch_Layer_Filter_Attribute
26
+ */
27
+ protected function _prepareFilter()
28
+ {
29
+ $this->_filter->setAttributeModel($this->getAttributeModel());
30
+
31
+ return $this;
32
+ }
33
+
34
+ /**
35
+ * Adds facet condition to filter.
36
+ *
37
+ * @see ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute::addFacetCondition()
38
+ * @return ChoiceAI_Search_Block_Catalogsearch_Layer_Filter_Attribute
39
+ */
40
+ public function addFacetCondition()
41
+ {
42
+ $this->_filter->addFacetCondition();
43
+
44
+ return $this;
45
+ }
46
+ }
app/code/local/ChoiceAI/Search/Block/Catalogsearch/Result.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: Harkirat
5
+ * Date: 12/5/17
6
+ * Time: 12:47 PM
7
+ */
8
+
9
+ class ChoiceAI_Search_Block_Catalogsearch_Result extends Mage_CatalogSearch_Block_Result {
10
+ const IS_ACTIVE = 'choiceai_personalisation/settings/active';
11
+ /**
12
+ * Set search available list orders
13
+ *
14
+ * @return Mage_CatalogSearch_Block_Result
15
+ */
16
+ public function setListOrders()
17
+ {
18
+ if(Mage::getStoreConfig(self::IS_ACTIVE)=='1') {
19
+ $category = Mage::getSingleton('catalog/layer')
20
+ ->getCurrentCategory();
21
+ /* @var $category Mage_Catalog_Model_Category */
22
+ $availableOrders = $category->getAvailableSortByOptions();
23
+ unset($availableOrders['position']);
24
+
25
+ // Removed addition of 'Relevance' option here, which is in core functionality
26
+ $this->getListBlock()
27
+ ->setAvailableOrders($availableOrders)
28
+ ->setDefaultDirection('desc');
29
+ // ->setSortBy('relevance');
30
+ }else{
31
+ return parent::setListOrders();
32
+ }
33
+
34
+ return $this;
35
+ }
36
+ }
app/code/local/ChoiceAI/Search/Helper/Catalogsearch.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Recommendation
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Helper_Catalogsearch extends Mage_CatalogSearch_Helper_Data {
10
+
11
+ public function getResultUrl($query = null) {
12
+ if(Mage::helper('choiceai_search')->isHostedSearchActive()) {
13
+ $redirectUrl = Mage::helper('choiceai_search')->getHostedRedirectUrl();
14
+ return $redirectUrl . ((!is_null($query) && $query != "")?($this->getQueryParamName()."=".$query):"");
15
+ }
16
+ return parent::getResultUrl($query);
17
+ }
18
+
19
+ }
app/code/local/ChoiceAI/Search/Helper/Choiceaisearch.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @package ChoiceAI_Search
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Search_Helper_ChoiceAIsearch extends ChoiceAI_Search_Helper_Data
9
+ {
10
+
11
+ public function getEngineConfigData($prefix = '', $website = null)
12
+ {
13
+ return Mage::helper('choiceai_searchcore')->getEngineConfigData($prefix, $website);
14
+
15
+ }
16
+ }
app/code/local/ChoiceAI/Search/Helper/Data.php ADDED
@@ -0,0 +1,670 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * @package ChoiceAI_Search
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Search_Helper_Data extends Mage_Core_Helper_Abstract
9
+ {
10
+ /**
11
+ * Allowed languages.
12
+ * Example: array('en_US' => 'en', 'fr_FR' => 'fr')
13
+ *
14
+ * @var array
15
+ */
16
+ protected $_languageCodes = array();
17
+
18
+ /**
19
+ * Searchable attributes.
20
+ *
21
+ * @var array
22
+ */
23
+ protected $_searchableAttributes;
24
+
25
+ /**
26
+ * Sortable attributes.
27
+ *
28
+ * @var array
29
+ */
30
+ protected $_sortableAttributes;
31
+
32
+ /**
33
+ * Text field types.
34
+ *
35
+ * @var array
36
+ */
37
+ protected $_textFieldTypes = array(
38
+ 'text',
39
+ 'varchar',
40
+ );
41
+
42
+ /**
43
+ * Unlocalized field types.
44
+ *
45
+ * @var array
46
+ */
47
+ protected $_unlocalizedFieldTypes = array(
48
+ 'datetime',
49
+ 'decimal',
50
+ );
51
+
52
+ /**
53
+ * Boolean field which stores choiceai active or not
54
+ *
55
+ * @var boolean
56
+ */
57
+ public $is_active = NULL;
58
+
59
+
60
+ const IS_ACTIVE = 'choiceai_personalisation/settings/active';
61
+ const CONFIG_KEY = 'choiceai_personalisation/settings/config';
62
+
63
+ /**
64
+ * Returns attribute field name (localized if needed).
65
+ *
66
+ * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute
67
+ * @param string $localeCode
68
+ * @return string
69
+ */
70
+ public function getAttributeFieldName($attribute, $localeCode = null)
71
+ {
72
+ if (is_string($attribute)) {
73
+ $this->getSearchableAttributes(); // populate searchable attributes if not already set
74
+ if (!isset($this->_searchableAttributes[$attribute])) {
75
+ return $attribute;
76
+ }
77
+ $attribute = $this->_searchableAttributes[$attribute];
78
+ }
79
+ $attributeCode = $attribute->getAttributeCode();
80
+ $backendType = $attribute->getBackendType();
81
+
82
+ if ($attributeCode != 'score' && in_array($backendType, $this->_textFieldTypes)) {
83
+ if (null === $localeCode) {
84
+ $localeCode = $this->getLocaleCode();
85
+ }
86
+ // $languageCode = $this->getLanguageCodeByLocaleCode($localeCode);
87
+ // $languageSuffix = "_fq";
88
+ //$attributeCode .= $languageSuffix;
89
+ }
90
+
91
+ return $attributeCode;
92
+ }
93
+
94
+ /**
95
+ * Returns cache lifetime in seconds.
96
+ *
97
+ * @return int
98
+ */
99
+ public function getCacheLifetime()
100
+ {
101
+ return Mage::getStoreConfig('core/cache/lifetime');
102
+ }
103
+
104
+ /**
105
+ * Returns search engine config data.
106
+ *
107
+ * @param string $prefix
108
+ * @param mixed $store
109
+ * @return array
110
+ */
111
+ public function getEngineConfigData($prefix = '', $website = null)
112
+ {
113
+ return Mage::helper('choiceai_searchcore')->getEngineConfigData($prefix, $website);
114
+ }
115
+
116
+ /**
117
+ * Returns EAV config singleton.
118
+ *
119
+ * @return Mage_Eav_Model_Config
120
+ */
121
+ public function getEavConfig()
122
+ {
123
+ return Mage::getSingleton('eav/config');
124
+ }
125
+
126
+ /**
127
+ * Returns language code of specified locale code.
128
+ *
129
+ * @param string $localeCode
130
+ * @return bool
131
+ */
132
+ public function getLanguageCodeByLocaleCode($localeCode)
133
+ {
134
+ $localeCode = (string) $localeCode;
135
+ if (!$localeCode) {
136
+ return false;
137
+ }
138
+
139
+ if (!isset($this->_languageCodes[$localeCode])) {
140
+ $languages = $this->getSupportedLanguages();
141
+ $this->_languageCodes[$localeCode] = false;
142
+ foreach ($languages as $code => $locales) {
143
+ if (is_array($locales)) {
144
+ if (in_array($localeCode, $locales)) {
145
+ $this->_languageCodes[$localeCode] = $code;
146
+ }
147
+ } elseif ($localeCode == $locales) {
148
+ $this->_languageCodes[$localeCode] = $code;
149
+ }
150
+ }
151
+ }
152
+
153
+ return $this->_languageCodes[$localeCode];
154
+ }
155
+
156
+ /**
157
+ * Returns store language code.
158
+ *
159
+ * @param mixed $store
160
+ * @return bool
161
+ */
162
+ public function getLanguageCodeByStore($store = null)
163
+ {
164
+ return $this->getLanguageCodeByLocaleCode($this->getLocaleCode($store));
165
+ }
166
+
167
+ /**
168
+ * Returns store locale code.
169
+ *
170
+ * @param null $store
171
+ * @return string
172
+ */
173
+ public function getLocaleCode($store = null)
174
+ {
175
+ return Mage::getStoreConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_LOCALE, $store);
176
+ }
177
+
178
+ /**
179
+ * Retrieves all searchable product attributes.
180
+ * Possibility to filter attributes by backend type.
181
+ *
182
+ * @param array $backendType
183
+ * @return array
184
+ */
185
+ public function getSearchableAttributes($backendType = null)
186
+ {
187
+ if (null === $this->_searchableAttributes) {
188
+ $this->_searchableAttributes = array();
189
+ $entityType = $this->getEavConfig()->getEntityType('catalog_product');
190
+ $entity = $entityType->getEntity();
191
+
192
+ /* @var $productAttributeCollection Mage_Catalog_Model_Resource_Product_Attribute_Collection */
193
+ $productAttributeCollection = Mage::getResourceModel('catalog/product_attribute_collection')
194
+ ->setEntityTypeFilter($entityType->getEntityTypeId())
195
+ ->addVisibleFilter()
196
+ ->addToIndexFilter(true);
197
+
198
+ $attributes = $productAttributeCollection->getItems();
199
+ foreach ($attributes as $attribute) {
200
+ /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */
201
+ $attribute->setEntity($entity);
202
+ $this->_searchableAttributes[$attribute->getAttributeCode()] = $attribute;
203
+ }
204
+ }
205
+
206
+ if (null !== $backendType) {
207
+ $backendType = (array) $backendType;
208
+ $attributes = array();
209
+ foreach ($this->_searchableAttributes as $attribute) {
210
+ /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */
211
+ if (in_array($attribute->getBackendType(), $backendType)) {
212
+ $attributes[$attribute->getAttributeCode()] = $attribute;
213
+ }
214
+ }
215
+
216
+ return $attributes;
217
+ }
218
+
219
+ return $this->_searchableAttributes;
220
+ }
221
+
222
+ /**
223
+ * Returns seach config data.
224
+ *
225
+ * @param string $field
226
+ * @param mixed $store
227
+ * @return array
228
+ */
229
+ public function getSearchConfigData($field, $store = null)
230
+ {
231
+ $path = 'catalog/search/' . $field;
232
+
233
+ return Mage::getStoreConfig($path, $store);
234
+ }
235
+
236
+
237
+ /**
238
+ * Returns searched parameter as array.
239
+ *
240
+ * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute
241
+ * @param mixed $value
242
+ * @return array
243
+ */
244
+ public function getSearchParam($attribute, $value)
245
+ {
246
+ if (empty($value) ||
247
+ (isset($value['from']) && empty($value['from']) &&
248
+ isset($value['to']) && empty($value['to']))) {
249
+ return false;
250
+ }
251
+
252
+ $field = $this->getAttributeFieldName($attribute);
253
+ $backendType = $attribute->getBackendType();
254
+ if ($backendType == 'datetime') {
255
+ $format = Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT);
256
+ if (is_array($value)) {
257
+ foreach ($value as &$val) {
258
+ if (!is_empty_date($val)) {
259
+ $date = new Zend_Date($val, $format);
260
+ $val = $date->toString(Zend_Date::ISO_8601) . 'Z';
261
+ }
262
+ }
263
+ unset($val);
264
+ } else {
265
+ if (!is_empty_date($value)) {
266
+ $date = new Zend_Date($value, $format);
267
+ $value = $date->toString(Zend_Date::ISO_8601) . 'Z';
268
+ }
269
+ }
270
+ }
271
+
272
+ if ($attribute->usesSource()) {
273
+ $attribute->setStoreId(Mage::app()->getStore()->getId());
274
+ }
275
+
276
+ return array($field => $value);
277
+ }
278
+
279
+ /**
280
+ * Returns sortable attribute field name (localized if needed).
281
+ *
282
+ * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute
283
+ * @param string $locale
284
+ * @return string
285
+ */
286
+ public function getSortableAttributeFieldName($attribute, $locale = null)
287
+ {
288
+ if (is_string($attribute)) {
289
+ $this->getSortableAttributes(); // populate sortable attributes if not already set
290
+ if (!isset($this->_sortableAttributes[$attribute])) {
291
+ return $attribute;
292
+ }
293
+ $attribute = $this->_sortableAttributes[$attribute];
294
+ }
295
+
296
+ $attributeCode = $attribute->getAttributeCode();
297
+
298
+ if ($attributeCode != 'score' && !in_array($attribute->getBackendType(), $this->_unlocalizedFieldTypes)) {
299
+ if (null === $locale) {
300
+ $locale = $this->getLocaleCode();
301
+ }
302
+ $languageCode = $this->getLanguageCodeByLocaleCode($locale);
303
+ $languageSuffix = $languageCode ? '_' . $languageCode : '';
304
+ $attributeCode .= $languageSuffix;
305
+ }
306
+
307
+ return 'sort_by_' . $attributeCode;
308
+ }
309
+
310
+ /**
311
+ * Retrieves all sortable product attributes.
312
+ *
313
+ * @return array
314
+ */
315
+ public function getSortableAttributes()
316
+ {
317
+ if (null === $this->_sortableAttributes) {
318
+ $this->_sortableAttributes = Mage::getSingleton('catalog/config')->getAttributesUsedForSortBy();
319
+ if (array_key_exists('price', $this->_sortableAttributes)) {
320
+ unset($this->_sortableAttributes['price']); // Price sorting is handled with searchable attribute.
321
+ }
322
+ }
323
+
324
+ return $this->_sortableAttributes;
325
+ }
326
+
327
+ /**
328
+ * Defines supported languages for snowball filter.
329
+ *
330
+ * @return array
331
+ */
332
+ public function getSupportedLanguages()
333
+ {
334
+ $default = array(
335
+ /**
336
+ * SnowBall filter based
337
+ */
338
+ // Danish
339
+ 'da' => 'da_DK',
340
+ // Dutch
341
+ 'nl' => 'nl_NL',
342
+ // English
343
+ 'en' => array('en_AU', 'en_CA', 'en_NZ', 'en_GB', 'en_US'),
344
+ // Finnish
345
+ 'fi' => 'fi_FI',
346
+ // French
347
+ 'fr' => array('fr_CA', 'fr_FR'),
348
+ // German
349
+ 'de' => array('de_DE','de_DE','de_AT'),
350
+ // Italian
351
+ 'it' => array('it_IT','it_CH'),
352
+ // Norwegian
353
+ 'nb' => array('nb_NO', 'nn_NO'),
354
+ // Portuguese
355
+ 'pt' => array('pt_BR', 'pt_PT'),
356
+ // Romanian
357
+ 'ro' => 'ro_RO',
358
+ // Russian
359
+ 'ru' => 'ru_RU',
360
+ // Spanish
361
+ 'es' => array('es_AR', 'es_CL', 'es_CO', 'es_CR', 'es_ES', 'es_MX', 'es_PA', 'es_PE', 'es_VE'),
362
+ // Swedish
363
+ 'sv' => 'sv_SE',
364
+ // Turkish
365
+ 'tr' => 'tr_TR',
366
+
367
+ /**
368
+ * Lucene class based
369
+ */
370
+ // Czech
371
+ 'cs' => 'cs_CZ',
372
+ // Greek
373
+ 'el' => 'el_GR',
374
+ // Thai
375
+ 'th' => 'th_TH',
376
+ // Chinese
377
+ 'zh' => array('zh_CN', 'zh_HK', 'zh_TW'),
378
+ // Japanese
379
+ 'ja' => 'ja_JP',
380
+ // Korean
381
+ 'ko' => 'ko_KR'
382
+ );
383
+
384
+ return $default;
385
+ }
386
+
387
+ /**
388
+ * Checks if configured engine is active.
389
+ *
390
+ * @return bool
391
+ */
392
+ public function isActiveEngine() {
393
+
394
+ if(is_null($this->is_active)) {
395
+ $storeConfig = json_decode(Mage::getStoreConfig(self::CONFIG_KEY));
396
+ $sortbyObjs = $storeConfig->sortby;
397
+
398
+ // Getting URL Path
399
+ $currentReqPath = explode("?", $_SERVER['REQUEST_URI'])[0];
400
+ $currentReqPath = rtrim($currentReqPath, "/");
401
+
402
+ // Getting param keys in array var $paramPairs
403
+ parse_str($_SERVER['QUERY_STRING'], $paramPairs);
404
+ // Getting query keys
405
+ $currentReqParams = array();
406
+ if (count($paramPairs)) {
407
+ foreach ($paramPairs as $key => $paramPair)
408
+ $currentReqParams[] = $key;
409
+ }
410
+
411
+ // Refining URL path
412
+ // My own local installation case: localhost/magento/
413
+ if (strpos($currentReqPath, "/magento/") !== false)
414
+ $currentReqPath = str_replace("/magento/", "/", $currentReqPath);
415
+
416
+ // Making www.store.com/index.php/abcd => www.store.com/abcd
417
+ if (strpos($currentReqPath, "/index.php/") !== false)
418
+ $currentReqPath = str_replace("/index.php/", "/", $currentReqPath);
419
+
420
+ $isPluginActive = Mage::getStoreConfig(self::IS_ACTIVE) == '1';
421
+
422
+ if ($isPluginActive) {
423
+ foreach ($sortbyObjs as $sortbyObj) {
424
+ if (isset($sortbyObj->rule->paths)) {
425
+ if (in_array($currentReqPath, $sortbyObj->rule->paths)) {
426
+ $choiceOptions = $this->_getOptionsAddedByChoice($sortbyObj);
427
+
428
+ if (is_null($_REQUEST["order"]))
429
+ $this->_setDefaultSortOption($sortbyObj, $storeConfig);
430
+ break;
431
+ }
432
+ }
433
+
434
+ if (isset($sortbyObj->rule->params)) {
435
+ if (!empty(array_intersect($currentReqParams, $sortbyObj->rule->params))) {
436
+ $choiceOptions = $this->_getOptionsAddedByChoice($sortbyObj);
437
+
438
+ //
439
+ if (is_null($_REQUEST["order"]))
440
+ $this->_setDefaultSortOption($sortbyObj, $storeConfig);
441
+ break;
442
+ }
443
+ }
444
+ }
445
+
446
+ if (count($choiceOptions) && in_array($_REQUEST["order"], $choiceOptions)) {
447
+ $this->is_active = true;
448
+ }
449
+ }
450
+ }
451
+
452
+ return $this->is_active;
453
+ }
454
+
455
+ // If sort order is default, $_REQUEST["order"] will not exist
456
+ // This adds a default value in it
457
+ private function _setDefaultSortOption($sortbyObj, $STORE_CONFIG){
458
+ if(isset($sortbyObj->extend)){
459
+ foreach ($sortbyObj->extend as $optionKey => $optionValue) {
460
+ $_REQUEST['order'] = $optionKey;
461
+ break;
462
+ }
463
+ } else if(isset($sortbyObj->override)) {
464
+ $_REQUEST["order"] = $STORE_CONFIG->default_search_sort;
465
+ } else if(isset($_SESSION['catalog']) && isset($_SESSION['catalog']['sort_order'])){
466
+ // If prod list page, use the session value
467
+ // This case although seems useless
468
+ $_REQUEST["order"] = $_SESSION['catalog']['sort_order'];
469
+ }
470
+ }
471
+
472
+ /**
473
+ * @param $sortbyObj
474
+ * @return array
475
+ */
476
+ private function _getOptionsAddedByChoice($sortbyObj){
477
+ $options = array();
478
+
479
+ if(isset($sortbyObj->override)){
480
+ // Search case, override all system options with choice
481
+ $caiOptions = $sortbyObj->override;
482
+
483
+ foreach ($caiOptions as $key => $caiOption)
484
+ $options[] = $key;
485
+ } elseif(isset($sortbyObj->extend)) {
486
+ foreach ($sortbyObj->extend as $key=>$option)
487
+ $options[] = $key;
488
+ }
489
+
490
+ return $options;
491
+ }
492
+
493
+ /**
494
+ * Checks whether request is a navigation
495
+ *
496
+ * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute
497
+ * @return bool
498
+ */
499
+ public function isNavigation() {
500
+ if($this->_getRequest()->getControllerName() == "category") {
501
+ return true;
502
+ }
503
+ return false;
504
+ }
505
+
506
+ /**
507
+ * Checks whether request is a resultPage
508
+ *
509
+ * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute
510
+ * @return bool
511
+ */
512
+ public function isSearch() {
513
+ if($this->_getRequest()->getControllerName() == "result") {
514
+ return true;
515
+ }
516
+ return false;
517
+ }
518
+
519
+ /**
520
+ * Checks if specified attribute is indexable by search engine.
521
+ *
522
+ * @param Mage_Catalog_Model_Resource_Eav_Attribute $attribute
523
+ * @return bool
524
+ */
525
+ public function isAttributeIndexable($attribute)
526
+ {
527
+ if ($attribute->getBackendType() == 'varchar' && !$attribute->getBackendModel()) {
528
+ return true;
529
+ }
530
+
531
+ if ($attribute->getBackendType() == 'int'
532
+ && $attribute->getSourceModel() != 'eav/entity_attribute_source_boolean'
533
+ && ($attribute->getIsSearchable() || $attribute->getIsFilterable() || $attribute->getIsFilterableInSearch())
534
+ ) {
535
+ return true;
536
+ }
537
+
538
+ if ($attribute->getIsSearchable() || $attribute->getIsFilterable() || $attribute->getIsFilterableInSearch()) {
539
+ return true;
540
+ }
541
+
542
+ return false;
543
+ }
544
+
545
+ /**
546
+ * Checks if debug mode is enabled.
547
+ *
548
+ * @return bool
549
+ */
550
+ public function isDebugEnabled()
551
+ {
552
+ $config = $this->getEngineConfigData();
553
+
554
+ return array_key_exists('enable_debug_mode', $config) && $config['enable_debug_mode'];
555
+ }
556
+
557
+ /**
558
+ * Method that can be overriden for customing product data indexation.
559
+ *
560
+ * @param array $index
561
+ * @param string $separator
562
+ * @return array
563
+ */
564
+ public function prepareIndexData($index, $separator = null)
565
+ {
566
+ return $index;
567
+ }
568
+
569
+ /**
570
+ * Forces error display.
571
+ *
572
+ * @param string $error
573
+ */
574
+ public function showError($error)
575
+ {
576
+ echo Mage::app()->getLayout()->createBlock('core/messages')
577
+ ->addError($error)->getGroupedHtml();
578
+ }
579
+
580
+ /*
581
+ * returns the choiceai site name
582
+ *
583
+ * @return String
584
+ */
585
+ public function getSiteName(){
586
+ $siteKeyLabel = ChoiceAI_Searchcore_Helper_Constants::SITE_KEY;
587
+ $config = $this->getEngineConfigData($siteKeyLabel);
588
+ if(array_key_exists($siteKeyLabel, $config) && $config[$siteKeyLabel] != "")
589
+ return $config[$siteKeyLabel];
590
+ else {
591
+ $siteKey = Mage::getResourceModel('choiceai_searchcore/config')
592
+ ->getValue(Mage::app()->getWebsite()->getWebsiteId(),
593
+ $siteKeyLabel);
594
+ if(isset($siteKey) && $siteKey != ''){
595
+ Mage::helper('choiceai_searchcore')->saveConfig(Mage::app()->getWebsite(),
596
+ array($siteKeyLabel => $siteKey));
597
+ return $siteKey;
598
+ } else {
599
+ if(Mage::getIsDeveloperMode()) {
600
+ Mage::throwException("ChoiceAI site key is empty");
601
+ } else {
602
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR, 'ChoiceAI site key is not set');
603
+ return null;
604
+ }
605
+ }
606
+ }
607
+ }
608
+
609
+ /*
610
+ * returns the choiceai api Key
611
+ *
612
+ * @return String
613
+ */
614
+ public function getApiKey(){
615
+ $apiKeyLabel = ChoiceAI_Searchcore_Helper_Constants::API_KEY;
616
+ $config = $this->getEngineConfigData($apiKeyLabel);
617
+ if(array_key_exists($apiKeyLabel, $config) && $config[$apiKeyLabel] != "")
618
+ return $config[$apiKeyLabel];
619
+ else {
620
+ $apiKey = Mage::getResourceModel('choiceai_searchcore/config')
621
+ ->getValue(Mage::app()->getWebsite()->getWebsiteId(), $apiKeyLabel);
622
+ if(isset($apiKey) && $apiKey != ''){
623
+ Mage::helper('choiceai_searchcore')->saveConfig(Mage::app()->getWebsite(),
624
+ array($apiKeyLabel => $apiKey));
625
+ return $apiKey;
626
+ } else {
627
+ if(Mage::getIsDeveloperMode()) {
628
+ Mage::throwException("ChoiceAI api key is empty");
629
+ } else {
630
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR, 'ChoiceAI Api key is not set');
631
+ return null;
632
+ }
633
+ }
634
+ }
635
+ }
636
+
637
+ /**
638
+ * This method checks whether hosted search is active or not
639
+ * @return boolean
640
+ */
641
+ public function isHostedSearchActive()
642
+ {
643
+ $siteKey = null;
644
+ $apiKey = null;
645
+ try {
646
+ $siteKey = $this->getSiteName();
647
+ $apiKey = $this->getApiKey();
648
+ } catch(Exception $e) {
649
+ //ignoring the exception
650
+ }
651
+ $searchConf = $this->getEngineConfigData('search');
652
+ $hostedSearchConf = Mage::helper('choiceai_searchcore')->isConfigTrue(Mage::app()->getWebsite(),ChoiceAI_Searchcore_Helper_Constants::SEARCH_HOSTED_STATUS);
653
+ $searchModConf = Mage::helper('choiceai_searchcore')->isConfigTrue(Mage::app()->getWebsite(), ChoiceAI_Searchcore_Helper_Constants::SEARCH_MOD_STATUS);
654
+ $hostedIntStatus = $searchConf[ChoiceAI_Searchcore_Helper_Constants::SEARCH_HOSTED_INT_STATUS];
655
+ $hostedSearchRedirectUrl = $searchConf[ChoiceAI_Searchcore_Helper_Constants::SEARCH_HOSTED_REDIRECT_URL];
656
+ return !is_null($siteKey) && !is_null($apiKey) &&
657
+ $hostedSearchConf && !$searchModConf &&
658
+ $hostedIntStatus == ChoiceAI_Searchcore_Helper_Constants::SEARCH_HOSTED_INT_COMPLETE &&
659
+ sizeof($hostedSearchRedirectUrl) > 0;
660
+ }
661
+
662
+ /**
663
+ * Method to get the hosted redirection url
664
+ * @return mixed
665
+ */
666
+ public function getHostedRedirectUrl() {
667
+ $config = $this->getEngineConfigData(ChoiceAI_Searchcore_Helper_Constants::SEARCH_HOSTED_REDIRECT_URL);
668
+ return $config[ChoiceAI_Searchcore_Helper_Constants::SEARCH_HOSTED_REDIRECT_URL];
669
+ }
670
+ }
app/code/local/ChoiceAI/Search/Model/Catalog/Category.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Created by PhpStorm.
4
+ * User: harkirat
5
+ * Date: 12/5/17
6
+ * Time: 11:25 PM
7
+ */
8
+
9
+ class ChoiceAI_Search_Model_Catalog_Category extends Mage_Catalog_Model_Category
10
+ {
11
+ const IS_ACTIVE = 'choiceai_personalisation/settings/active';
12
+ const CONFIG_KEY = 'choiceai_personalisation/settings/config';
13
+
14
+ /**
15
+ * Retrieve Available Product Listing Sort By
16
+ * code as key, value - name
17
+ *
18
+ * @return array
19
+ */
20
+ public function getAvailableSortByOptions()
21
+ {
22
+ $overtakeFlag = false;
23
+
24
+ // Check if URL in takeover list
25
+ $STORE_CONFIG = json_decode(Mage::getStoreConfig(self::CONFIG_KEY));
26
+ $sortbyObjs = $STORE_CONFIG->sortby;
27
+
28
+ // Getting URL Path
29
+ $currentReqPath = explode("?", $_SERVER['REQUEST_URI'])[0];
30
+
31
+ // Getting param keys in array var $paramPairs
32
+ parse_str($_SERVER['QUERY_STRING'], $paramPairs);
33
+ // Getting query keys
34
+ $currentReqParams = array();
35
+ if (count($paramPairs)) {
36
+ foreach ($paramPairs as $key => $paramPair)
37
+ $currentReqParams[] = $key;
38
+ }
39
+
40
+ // Refining URL path
41
+ // My own local installation case: localhost/magento/
42
+ if (strpos($currentReqPath, "/magento/") !== false)
43
+ $currentReqPath = str_replace("/magento/", "/", $currentReqPath);
44
+
45
+ // Making www.store.com/index.php/abcd => www.store.com/abcd
46
+ if (strpos($currentReqPath, "/index.php/") !== false)
47
+ $currentReqPath = str_replace("/index.php/", "/", $currentReqPath);
48
+
49
+ $isPluginActive = Mage::getStoreConfig(self::IS_ACTIVE)=='1';
50
+ // $isPluginActive = true;
51
+
52
+ if($isPluginActive) {
53
+ foreach ($sortbyObjs as $sortbyObj) {
54
+ if (isset($sortbyObj->rule->paths)) {
55
+ if (in_array($currentReqPath, $sortbyObj->rule->paths)) {
56
+ $overtakeFlag = true;
57
+ }
58
+ }
59
+
60
+ if (isset($sortbyObj->rule->params)) {
61
+ if (!empty(array_intersect($currentReqParams, $sortbyObj->rule->params))) {
62
+ $overtakeFlag = true;
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ if($overtakeFlag)
69
+ return Mage::getSingleton('catalog/config')->getAttributeUsedForSortByArray();
70
+ else
71
+ return parent::getAvailableSortByOptions();
72
+
73
+ }
74
+ }
app/code/local/ChoiceAI/Search/Model/Catalog/Config.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Overrides default layer model to handle custom product collection filtering.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Model_Catalog_Config extends Mage_Catalog_Model_Config
10
+ {
11
+ const IS_ACTIVE = 'choiceai_personalisation/settings/active';
12
+ const CONFIG_KEY = 'choiceai_personalisation/settings/config';
13
+
14
+ public $options = NULL;
15
+
16
+ /**
17
+ * Retrieve Attributes Used for Sort by as array
18
+ * key = code, value = name
19
+ *
20
+ * Note by Harkirat: This function is called in both cases: product list and search.
21
+ *
22
+ * @return array
23
+ */
24
+ public function getAttributeUsedForSortByArray()
25
+ {
26
+ try {
27
+ if(is_null($this->options)) {
28
+ // Check if URL in takeover list
29
+ $STORE_CONFIG = json_decode(Mage::getStoreConfig(self::CONFIG_KEY));
30
+ $sortbyObjs = $STORE_CONFIG->sortby;
31
+
32
+ // Getting URL Path
33
+ $currentReqPath = explode("?", $_SERVER['REQUEST_URI'])[0];
34
+
35
+ // Getting param keys in array var $paramPairs
36
+ parse_str($_SERVER['QUERY_STRING'], $paramPairs);
37
+ // Getting query keys
38
+ $currentReqParams = array();
39
+ if (count($paramPairs)) {
40
+ foreach ($paramPairs as $key => $paramPair)
41
+ $currentReqParams[] = $key;
42
+ }
43
+
44
+ // Refining URL path
45
+ // My own local installation case: localhost/magento/
46
+ if (strpos($currentReqPath, "/magento/") !== false)
47
+ $currentReqPath = str_replace("/magento/", "/", $currentReqPath);
48
+
49
+ // Making www.store.com/index.php/abcd => www.store.com/abcd
50
+ if (strpos($currentReqPath, "/index.php/") !== false)
51
+ $currentReqPath = str_replace("/index.php/", "/", $currentReqPath);
52
+
53
+ $isPluginActive = Mage::getStoreConfig(self::IS_ACTIVE) == '1';
54
+ // $isPluginActive = true;
55
+
56
+ if ($isPluginActive) {
57
+ foreach ($sortbyObjs as $sortbyObj) {
58
+ if (isset($sortbyObj->rule)) {
59
+ if (isset($sortbyObj->rule->paths)) {
60
+ if (in_array($currentReqPath, $sortbyObj->rule->paths)) {
61
+ $this->options = $this->getOptions($sortbyObj);
62
+
63
+ if (empty($this->options)) {
64
+ return parent::getAttributeUsedForSortByArray();
65
+ }
66
+ return $this->options;
67
+ }
68
+ }
69
+
70
+ if (isset($sortbyObj->rule->params)) {
71
+ if (!empty(array_intersect($currentReqParams, $sortbyObj->rule->params))) {
72
+ $this->options = $this->getOptions($sortbyObj);
73
+
74
+ if (empty($this->options)) {
75
+ return parent::getAttributeUsedForSortByArray();
76
+ }
77
+ return $this->options;
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ } else{
84
+ return $this->options;
85
+ }
86
+
87
+ $this->options = parent::getAttributeUsedForSortByArray();
88
+ return $this->options;
89
+ } catch (Exception $e){
90
+ return parent::getAttributeUsedForSortByArray();
91
+ }
92
+ }
93
+
94
+ private function getOptions($sortbyObj){
95
+ $options = array();
96
+
97
+ if(isset($sortbyObj->override)){
98
+ // Search case, override all system options with choice
99
+ $caiOptions = $sortbyObj->override;
100
+
101
+ foreach ($caiOptions as $key => $caiOption)
102
+ $options[$key] = Mage::helper('catalog')->__($caiOption);
103
+ } else if(isset($sortbyObj->extend)) {
104
+ // Product list page, add system options first, then add/replace ours
105
+
106
+ foreach ($this->getAttributesUsedForSortBy() as $attribute) {
107
+ /* @var $attribute Mage_Eav_Model_Entity_Attribute_Abstract */
108
+ $options[$attribute->getAttributeCode()] = $attribute->getStoreLabel();
109
+ }
110
+
111
+ // Default options added above, now adding our option/s, which can either override or be a new option
112
+ foreach ($sortbyObj->extend as $key=>$option)
113
+ $options[$key] = Mage::helper('catalog')->__($option);
114
+
115
+ $_SESSION['plist_sort_by'] = $key;
116
+ }
117
+
118
+ return $options;
119
+ }
120
+ }
app/code/local/ChoiceAI/Search/Model/Catalog/Layer.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Overrides default layer model to handle custom product collection filtering.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Model_Catalog_Layer extends Mage_Catalog_Model_Layer
10
+ {
11
+ /**
12
+ * Returns product collection for current category.
13
+ *
14
+ * @return ChoiceAI_Search_Model_Resource_Catalog_Product_Collection
15
+ */
16
+ public function getProductCollection()
17
+ {
18
+ /** @var $category Mage_Catalog_Model_Category */
19
+ $category = $this->getCurrentCategory();
20
+ /** @var $collection ChoiceAI_Search_Model_Resource_Catalog_Product_Collection */
21
+ if (isset($this->_productCollections[$category->getId()])) {
22
+ $collection = $this->_productCollections[$category->getId()];
23
+ } else {
24
+ $collection = Mage::getResourceModel('choiceai_search/engine_choiceaisearch')
25
+ ->getResultCollection()
26
+ ->setStoreId($category->getStoreId())
27
+ ->addCategoryId($category->getId())
28
+ ->setQueryType('browse')
29
+ ->addFqFilter(array('store_id' => $category->getStoreId()));
30
+
31
+ $this->prepareProductCollection($collection);
32
+ $this->_productCollections[$category->getId()] = $collection;
33
+ }
34
+
35
+ return $collection;
36
+ }
37
+ }
app/code/local/ChoiceAI/Search/Model/Catalog/Layer/Filter/Attribute.php ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handles attribute filtering in layered navigation.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute extends Mage_Catalog_Model_Layer_Filter_Attribute
10
+ {
11
+ const MULTI_SELECT_FACET_SPLIT = '_';
12
+
13
+ /**
14
+ * Adds facet condition to product collection.
15
+ *
16
+ * @see ChoiceAI_Search_Model_Resource_Catalog_Product_Collection::addFacetCondition()
17
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute
18
+ */
19
+ public function addFacetCondition()
20
+ {
21
+ $this->getLayer()
22
+ ->getProductCollection()
23
+ ->addFacetCondition($this->_getFilterField());
24
+
25
+ return $this;
26
+ }
27
+
28
+ /**
29
+ * Retrieves request parameter and applies it to product collection.
30
+ *
31
+ * @param Zend_Controller_Request_Abstract $request
32
+ * @param Mage_Core_Block_Abstract $filterBlock
33
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute
34
+ */
35
+ public function apply(Zend_Controller_Request_Abstract $request, $filterBlock)
36
+ {
37
+ $filter = $request->getParam($this->_requestVar);
38
+ if (is_array($filter) || null === $filter || strlen($filter) == 0) {
39
+ return $this;
40
+ }
41
+ $filterValues = explode(self::MULTI_SELECT_FACET_SPLIT, $filter);
42
+ $this->applyFilterToCollection($this, $filterValues);
43
+ foreach($filterValues as $eachFilterValue) {
44
+ $this->getLayer()->getState()->addFilter($this->_createItem($eachFilterValue, $eachFilterValue));
45
+ }
46
+
47
+ $this->_items = null;
48
+
49
+ return $this;
50
+ }
51
+
52
+ /**
53
+ * Applies filter to product collection.
54
+ *
55
+ * @param $filter
56
+ * @param $value
57
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute
58
+ */
59
+ public function applyFilterToCollection($filter, $value)
60
+ {
61
+ if(!is_array($value)) {
62
+ return $this;
63
+ }
64
+ $attribute = $filter->getAttributeModel();
65
+ $param = Mage::helper('choiceai_search')->getSearchParam($attribute, $value);
66
+
67
+ $this->getLayer()
68
+ ->getProductCollection()
69
+ ->addSearchQfFilter($param);
70
+
71
+ return $this;
72
+ }
73
+
74
+ /**
75
+ * Returns facets data of current attribute.
76
+ *
77
+ * @return array
78
+ */
79
+ protected function _getFacets()
80
+ {
81
+ /** @var $productCollection ChoiceAI_Search_Model_Resource_Catalog_Product_Collection */
82
+ $productCollection = $this->getLayer()->getProductCollection();
83
+ $fieldName = $this->_getFilterField();
84
+ $facets = $productCollection->getFacetedData($fieldName);
85
+ return $facets;
86
+ }
87
+
88
+
89
+ public function getMaxPriceInt()
90
+ {
91
+ $priceStat = Mage::getSingleton('choiceai_search/catalog_layer')->getProductCollection()->getStats('price');
92
+ $productCollection = $this->getLayer()->getProductCollection();
93
+ return isset($priceStat["max"])?$priceStat["max"]:0;
94
+ }
95
+
96
+
97
+ /**
98
+ * Returns attribute field name.
99
+ *
100
+ * @return string
101
+ */
102
+ protected function _getFilterField()
103
+ {
104
+ /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */
105
+ $attribute = $this->getAttributeModel();
106
+ $fieldName = Mage::helper('choiceai_search')->getAttributeFieldName($attribute);
107
+
108
+ return $fieldName;
109
+ }
110
+
111
+ /**
112
+ * Retrieves current items data.
113
+ *
114
+ * @return array
115
+ */
116
+ protected function _getItemsData()
117
+ {
118
+ $filter = array_key_exists($this->_requestVar, $_REQUEST)?$_REQUEST[$this->_requestVar]: '';
119
+ $filterValues = explode(self::MULTI_SELECT_FACET_SPLIT, $filter);
120
+ /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */
121
+ $attribute = $this->getAttributeModel();
122
+ $this->_requestVar = $attribute->getAttributeCode();
123
+ $facets = $this->_getFacets();
124
+ $data = array();
125
+
126
+ if (array_sum($facets) > 0) {
127
+ foreach ($facets as $label => $count) {
128
+ $isSelected = in_array($label, $filterValues);
129
+ if (!$count && $this->_getIsFilterableAttribute($attribute) == self::OPTIONS_ONLY_WITH_RESULTS) {
130
+ continue;
131
+ }
132
+ $data[] = array(
133
+ 'label' => $label,
134
+ 'value' => $label,
135
+ 'count' => $count,
136
+ );
137
+ }
138
+ }
139
+
140
+ return $data;
141
+ }
142
+
143
+ /**
144
+ * Returns option label if attribute uses options.
145
+ *
146
+ * @param int $optionId
147
+ * @return bool|int|string
148
+ */
149
+ protected function _getOptionText($optionId)
150
+ {
151
+ if ($this->getAttributeModel()->getFrontendInput() == 'text') {
152
+ return $optionId; // not an option id
153
+ }
154
+
155
+ return parent::_getOptionText($optionId);
156
+ }
157
+
158
+ /**
159
+ * Checks if given filter is valid before being applied to product collection.
160
+ *
161
+ * @param string $filter
162
+ * @return bool
163
+ */
164
+ protected function _isValidFilter($filter)
165
+ {
166
+ return !empty($filter);
167
+ }
168
+ }
app/code/local/ChoiceAI/Search/Model/Catalog/Layer/Filter/Boolean.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handles boolean attribute filtering in layered navigation.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Model_Catalog_Layer_Filter_Boolean extends ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute
10
+ {
11
+ /**
12
+ * Returns facets data of current attribute.
13
+ *
14
+ * @return array
15
+ */
16
+ protected function _getFacets()
17
+ {
18
+ $facets = parent::_getFacets();
19
+ $result = array();
20
+ foreach ($facets as $value => $count) {
21
+ $key = 0; // false by default
22
+ if ($value === 'true' || $value === 'T' || $value === '1' || $value === 1 || $value === true) {
23
+ $key = 1;
24
+ }
25
+ $result[$key] = $count;
26
+ }
27
+
28
+ return $result;
29
+ }
30
+
31
+ /**
32
+ * Checks if given filter is valid before being applied to product collection.
33
+ *
34
+ * @param string $filter
35
+ * @return bool
36
+ */
37
+ protected function _isValidFilter($filter)
38
+ {
39
+ return $filter === '0' || $filter === '1' || false === $filter || true === $filter;
40
+ }
41
+ }
app/code/local/ChoiceAI/Search/Model/Catalog/Layer/Filter/Category.php ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handles category filtering in layered navigation.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Model_Catalog_Layer_Filter_Category extends Mage_Catalog_Model_Layer_Filter_Category
10
+ {
11
+ /**
12
+ * Adds category filter to product collection.
13
+ *
14
+ * @param Mage_Catalog_Model_Category $category
15
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Category
16
+ */
17
+ public function addCategoryFilter($category)
18
+ {
19
+ $value = array(
20
+ 'categories' => $category->getId()
21
+ );
22
+ $this->getLayer()->getProductCollection()
23
+ ->addFqFilter($value);
24
+
25
+ return $this;
26
+ }
27
+
28
+ /**
29
+ * Adds facet condition to product collection.
30
+ *
31
+ * @see ChoiceAI_Search_Model_Resource_Catalog_Product_Collection::addFacetCondition()
32
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Category
33
+ */
34
+ public function addFacetCondition()
35
+ {
36
+ /** @var $category Mage_Catalog_Model_Category */
37
+ $category = $this->getCategory();
38
+ $childrenCategories = $category->getChildrenCategories();
39
+
40
+ $useFlat = (bool) Mage::getStoreConfig('catalog/frontend/flat_catalog_category');
41
+ $categories = ($useFlat)
42
+ ? array_keys($childrenCategories)
43
+ : array_keys($childrenCategories->toArray());
44
+
45
+ $this->getLayer()->getProductCollection()->addFacetCondition('categories', $categories);
46
+
47
+ return $this;
48
+ }
49
+
50
+ /**
51
+ * Applies filter to product collection.
52
+ *
53
+ * @param $filter
54
+ * @param $value
55
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute
56
+ */
57
+ public function applyFilterToCollection($filter, $value)
58
+ {
59
+
60
+ $param = array("category" => array($value));
61
+ $this->getLayer()
62
+ ->getProductCollection()
63
+ ->addSearchQfFilter($param);
64
+
65
+ return $this;
66
+ }
67
+
68
+ /**
69
+ * Retrieves request parameter and applies it to product collection.
70
+ *
71
+ * @param Zend_Controller_Request_Abstract $request
72
+ * @param Mage_Core_Block_Abstract $filterBlock
73
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Category
74
+ */
75
+ public function apply(Zend_Controller_Request_Abstract $request, $filterBlock)
76
+ {
77
+ $filter = $request->getParam($this->getRequestVar());
78
+ if (is_null($filter) || $filter == "") {
79
+ return $this;
80
+ }
81
+ $this->applyFilterToCollection($this, $filter);
82
+ $this->getLayer()->getState()->addFilter($this->_createItem($filter, $filter));
83
+ $this->_items = null;
84
+ return $this;
85
+ }
86
+
87
+ /**
88
+ * Retrieves current items data.
89
+ *
90
+ * @return array
91
+ */
92
+ protected function _getItemsData()
93
+ {
94
+ $layer = $this->getLayer();
95
+ /** @var $productCollection ChoiceAI_Search_Model_Resource_Catalog_Product_Collection */
96
+ $productCollection = $layer->getProductCollection();
97
+ $facets = $productCollection->getFacetedData('category');
98
+ $data = array();
99
+ if (array_sum($facets) > 0) {
100
+ $options = array();
101
+ foreach ($facets as $label => $count) {
102
+ $options[] = array(
103
+ 'label' => $label,
104
+ 'value' => $label,
105
+ 'count' => $count,
106
+ );
107
+ }
108
+ // }
109
+ foreach ($options as $option) {
110
+ if (is_array($option['value']) || !Mage::helper('core/string')->strlen($option['value'])) {
111
+ continue;
112
+ }
113
+ $count = 0;
114
+ $label = $option['label'];
115
+ if (isset($facets[$option['value']])) {
116
+ $count = (int) $facets[$option['value']];
117
+ }
118
+ if (!$count && $this->_getIsFilterableAttribute($attribute) == self::OPTIONS_ONLY_WITH_RESULTS) {
119
+ continue;
120
+ }
121
+ $data[] = array(
122
+ 'label' => $label,
123
+ 'value' => $option['value'],
124
+ 'count' => (int) $count,
125
+ );
126
+ }
127
+
128
+ }
129
+
130
+ return $data;
131
+ }
132
+ }
app/code/local/ChoiceAI/Search/Model/Catalog/Layer/Filter/Decimal.php ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handles decimal attribute filtering in layered navigation.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Model_Catalog_Layer_Filter_Decimal extends Mage_Catalog_Model_Layer_Filter_Decimal
10
+ {
11
+ const CACHE_TAG = 'MAXVALUE';
12
+
13
+ /**
14
+ * Adds facet condition to product collection.
15
+ *
16
+ * @see ChoiceAI_Search_Model_Resource_Catalog_Product_Collection::addFacetCondition()
17
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Decimal
18
+ */
19
+ public function addFacetCondition()
20
+ {
21
+ $range = $this->getRange();
22
+ $maxValue = $this->getMaxValue();
23
+ if ($maxValue > 0) {
24
+ $facets = array();
25
+ $facetCount = (int) ceil($maxValue / $range);
26
+
27
+ for ($i = 0; $i < $facetCount + 1; $i++) {
28
+ $facets[] = array(
29
+ 'from' => $i * $range,
30
+ 'to' => ($i + 1) * $range,
31
+ 'include_upper' => !($i < $facetCount)
32
+ );
33
+ }
34
+
35
+ $fieldName = $this->_getFilterField();
36
+ $this->getLayer()->getProductCollection()->addFacetCondition($fieldName, $facets);
37
+ }
38
+
39
+ return $this;
40
+ }
41
+
42
+ /**
43
+ * Retrieves request parameter and applies it to product collection.
44
+ *
45
+ * @param Zend_Controller_Request_Abstract $request
46
+ * @param Mage_Core_Block_Abstract $filterBlock
47
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Decimal
48
+ */
49
+ public function apply(Zend_Controller_Request_Abstract $request, $filterBlock)
50
+ {
51
+ $filter = $request->getParam($this->getRequestVar());
52
+ if (!$filter) {
53
+ return $this;
54
+ }
55
+
56
+ $filter = explode(',', $filter);
57
+ if (count($filter) != 2) {
58
+ return $this;
59
+ }
60
+
61
+ list($index, $range) = $filter;
62
+
63
+ if ((int) $index && (int) $range) {
64
+ $this->setRange((int) $range);
65
+
66
+ $this->applyFilterToCollection($this, $range, $index);
67
+ $this->getLayer()->getState()->addFilter(
68
+ $this->_createItem($this->_renderItemLabel($range, $index), $filter)
69
+ );
70
+
71
+ $this->_items = array();
72
+ }
73
+
74
+ return $this;
75
+ }
76
+
77
+ /**
78
+ * Apply decimal filter range to product collection.
79
+ *
80
+ * @param ChoiceAI_Search_Model_Catalog_Layer_Filter_Decimal $filter
81
+ * @param int $range
82
+ * @param int $index
83
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Decimal
84
+ */
85
+ public function applyFilterToCollection($filter, $range, $index)
86
+ {
87
+ $value = array(
88
+ $this->_getFilterField() => array(
89
+ 'from' => ($range * ($index - 1)),
90
+ 'to' => $range * $index,
91
+ )
92
+ );
93
+ $filter->getLayer()->getProductCollection()->addFqFilter($value);
94
+
95
+ return $this;
96
+ }
97
+
98
+ public function getMaxValue()
99
+ {
100
+ $searchParams = $this->getLayer()->getProductCollection()->getExtendedSearchParams();
101
+ $uniquePart = strtoupper(md5(serialize($searchParams)));
102
+ $cacheKey = 'MAXVALUE_' . $this->getLayer()->getStateKey() . '_' . $uniquePart;
103
+
104
+ $cachedData = Mage::app()->loadCache($cacheKey);
105
+ if (!$cachedData) {
106
+ $stats = $this->getLayer()->getProductCollection()->getStats($this->_getFilterField());
107
+
108
+ $max = $stats[$this->_getFilterField()]['max'];
109
+ if (!is_numeric($max)) {
110
+ $max = parent::getMaxValue();
111
+ }
112
+
113
+ $cachedData = (float) $max;
114
+ $tags = $this->getLayer()->getStateTags();
115
+ $tags[] = self::CACHE_TAG;
116
+ Mage::app()->saveCache($cachedData, $cacheKey, $tags);
117
+ }
118
+
119
+ return $cachedData;
120
+ }
121
+
122
+ /**
123
+ * Returns decimal field name.
124
+ *
125
+ * @return string
126
+ */
127
+ protected function _getFilterField()
128
+ {
129
+ $fieldName = Mage::helper('choiceai_search')->getAttributeFieldName($this->getAttributeModel());
130
+
131
+ return $fieldName;
132
+ }
133
+
134
+ /**
135
+ * Retrieves current items data.
136
+ *
137
+ * @return array
138
+ */
139
+ protected function _getItemsData()
140
+ {
141
+ $range = $this->getRange();
142
+ $fieldName = $this->_getFilterField();
143
+ $facets = $this->getLayer()->getProductCollection()->getFacetedData($fieldName);
144
+
145
+ $data = array();
146
+ if (!empty($facets)) {
147
+ foreach ($facets as $key => $count) {
148
+ if ($count > 0) {
149
+ preg_match('/TO ([\d\.]+)\]$/', $key, $rangeKey);
150
+ $rangeKey = round($rangeKey[1] / $range);
151
+ $data[] = array(
152
+ 'label' => $this->_renderItemLabel($range, $rangeKey),
153
+ 'value' => $rangeKey . ',' . $range,
154
+ 'count' => $count,
155
+ );
156
+ }
157
+ }
158
+ }
159
+
160
+ return $data;
161
+ }
162
+
163
+ /**
164
+ * Renders decimal ranges.
165
+ *
166
+ * @param int $range
167
+ * @param float $value
168
+ * @return string
169
+ */
170
+ protected function _renderItemLabel($range, $value)
171
+ {
172
+ /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */
173
+ $attribute = $this->getAttributeModel();
174
+
175
+ if ($attribute->getFrontendInput() == 'price') {
176
+ return parent::_renderItemLabel($range, $value);
177
+ }
178
+
179
+ $from = ($value - 1) * $range;
180
+ $to = $value * $range;
181
+
182
+ if ($from != $to) {
183
+ $to -= 0.01;
184
+ }
185
+
186
+ $to = Zend_Locale_Format::toFloat($to, array('locale' => Mage::helper('choiceai_search')->getLocaleCode()));
187
+
188
+ return Mage::helper('catalog')->__('%s - %s', $from, $to);
189
+ }
190
+ }
app/code/local/ChoiceAI/Search/Model/Catalog/Layer/Filter/Price.php ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handles price filtering in layered navigation.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Model_Catalog_Layer_Filter_Price extends Mage_Catalog_Model_Layer_Filter_Price
10
+ {
11
+ const CACHE_TAG = 'MAXPRICE';
12
+
13
+ const DELIMITER = '-';
14
+
15
+ /**
16
+ * Returns cache tag.
17
+ *
18
+ * @return string
19
+ */
20
+ public function getCacheTag()
21
+ {
22
+ return self::CACHE_TAG;
23
+ }
24
+
25
+ /**
26
+ * Retrieves max price for ranges definition.
27
+ *
28
+ * @return float
29
+ */
30
+ public function getMaxPriceMod()
31
+ {
32
+ $priceStat = Mage::getSingleton('choiceai_search/catalog_layer')->getProductCollection()->getStats('price');
33
+ $productCollection = $this->getLayer()->getProductCollection();
34
+ return isset($priceStat["max"])?(int)$priceStat["max"]:0;
35
+ }
36
+
37
+
38
+
39
+ /**
40
+ * Retrieves min price for ranges definition.
41
+ *
42
+ * @return float
43
+ */
44
+ public function getMinPriceMod()
45
+ {
46
+ $priceStat = Mage::getSingleton('choiceai_search/catalog_layer')->getProductCollection()->getStats('price');
47
+ $productCollection = $this->getLayer()->getProductCollection();
48
+ return isset($priceStat["min"])?(int)$priceStat["min"]:0;
49
+ }
50
+
51
+ /**
52
+ * Returns price field according to current customer group and website.
53
+ *
54
+ * @return string
55
+ */
56
+ protected function _getFilterField()
57
+ {
58
+ $websiteId = Mage::app()->getStore()->getWebsiteId();
59
+ $customerGroupId = Mage::getSingleton('customer/session')->getCustomerGroupId();
60
+ $priceField = 'price' ;
61
+
62
+ return $priceField;
63
+ }
64
+
65
+ /**
66
+ * Retrieves current items data.
67
+ *
68
+ * @return array
69
+ */
70
+ protected function _getItemsData()
71
+ {
72
+ // if (Mage::app()->getStore()->getConfig(self::XML_PATH_RANGE_CALCULATION) == self::RANGE_CALCULATION_IMPROVED) {
73
+ // return $this->_getCalculatedItemsData();}
74
+ if ($this->getInterval()) {
75
+ return array();
76
+ }
77
+
78
+ $data = array();
79
+ $facets = $this->getLayer()->getProductCollection()->getFacetedData($this->_getFilterField());
80
+ if (!empty($facets)) {
81
+ foreach ($facets as $key => $count) {
82
+ if (!$count) {
83
+ unset($facets[$key]);
84
+ }
85
+ }
86
+ $i = 0;
87
+ foreach ($facets as $key => $count) {
88
+ $i++;
89
+ preg_match('/^\[(\d*) TO (\d*)\]$/', $key, $rangeKey);
90
+ $fromPrice = $rangeKey[1];
91
+ $toPrice = $rangeKey[2];
92
+ $data[] = array(
93
+ 'label' => $this->_renderRangeLabel($fromPrice, $toPrice),
94
+ 'value' => $fromPrice . self::DELIMITER . $toPrice,
95
+ 'count' => $count
96
+ );
97
+ }
98
+ }
99
+
100
+ return $data;
101
+ }
102
+
103
+
104
+ /**
105
+ * Adds facet condition to product collection.
106
+ *
107
+ * @see ChoiceAI_Search_Model_Resource_Catalog_Product_Collection::addFacetCondition()
108
+ * @return ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute
109
+ */
110
+ public function addFacetCondition()
111
+ {
112
+ $this->getLayer()
113
+ ->getProductCollection()
114
+ ->addFacetCondition($this->_getFilterField());
115
+
116
+ return $this;
117
+ }
118
+
119
+
120
+ public function apply(Zend_Controller_Request_Abstract $request, $filterBlock){
121
+
122
+ $filter = $request->getParam($this->_requestVar);
123
+ if(null == $filter){
124
+ return $this;
125
+ }
126
+ $filter =explode(self::DELIMITER, $filter);
127
+ if (!is_array($filter) || null === $filter || sizeof($filter)<2 ) {
128
+ return $this;
129
+ }
130
+ $this->applyFilterToCollection($this, $filter);
131
+ $this->_items = null;
132
+ return $this;
133
+ }
134
+
135
+
136
+ function applyFilterToCollection($filter,$filterValue){
137
+ $field = $this->_getFilterField();
138
+ $value = array(
139
+ $field => array(
140
+ 'include_upper' => 0
141
+ )
142
+ );
143
+
144
+ if($filterValue[0]< $filterValue[1]){
145
+ $value[$field]['from'] = $filterValue[0];
146
+ $value[$field]['to'] = $filterValue[1];
147
+ }else{
148
+ $value[$field]['from'] = $filterValue[1];
149
+ $value[$field]['to'] = $filterValue[0];
150
+ }
151
+ $this->getLayer()->getProductCollection()->addSearchQfFilter($value);
152
+ return $this;
153
+ }
154
+ }
app/code/local/ChoiceAI/Search/Model/Catalogsearch/Layer.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+
10
+ class ChoiceAI_Search_Model_Catalogsearch_Layer extends Mage_CatalogSearch_Model_Layer
11
+ {
12
+ public function getProductCollection()
13
+ {
14
+ $category = $this->getCurrentCategory();
15
+ if (isset($this->_productCollections[$category->getId()])) {
16
+ $collection = $this->_productCollections[$category->getId()];
17
+ } else {
18
+ /** @var $collection ChoiceAI_Search_Model_Resource_Catalog_Product_Collection */
19
+ $collection = Mage::getResourceModel('choiceai_search/engine_choiceaisearch')
20
+ //->getEngine()
21
+ ->getResultCollection()
22
+ ->setStoreId($category->getStoreId())
23
+ ->setQueryType('search')
24
+ ->addFqFilter(array('store_id' => $category->getStoreId()));
25
+ $this->prepareProductCollection($collection);
26
+ $this->_productCollections[$category->getId()] = $collection;
27
+ }
28
+
29
+ return $collection;
30
+ }
31
+ }
app/code/local/ChoiceAI/Search/Model/Catalogsearch/Layer/Filter/Attribute.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+
10
+ class ChoiceAI_Search_Model_Catalogsearch_Layer_Filter_Attribute extends ChoiceAI_Search_Model_Catalog_Layer_Filter_Attribute
11
+ {
12
+ protected function _getIsFilterableAttribute($attribute)
13
+ {
14
+ return $attribute->getIsFilterableInSearch();
15
+ }
16
+ }
app/code/local/ChoiceAI/Search/Model/Resource/Catalog/Product/Collection.php ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom catalog product collection model.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Search_Model_Resource_Catalog_Product_Collection extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
10
+ {
11
+ /**
12
+ * @var ChoiceAI_Search_Model_Resource_Engine_Abstract Search engine.
13
+ */
14
+ protected $_engine;
15
+
16
+ /**
17
+ * @var array Faceted data.
18
+ */
19
+ protected $_facetedData = array();
20
+
21
+ /**
22
+ * @var array Facets conditions.
23
+ */
24
+ protected $_facetsConditions = array();
25
+
26
+ /**
27
+ * @var array General default query.
28
+ */
29
+ protected $_generalDefaultQuery = array('*' => '*');
30
+
31
+ /**
32
+ * @var string Search query text.
33
+ */
34
+ protected $_searchQueryText = '';
35
+
36
+ /**
37
+ * @var array Search query filters.
38
+ */
39
+ protected $_searchQueryFilters = array();
40
+
41
+ protected $_searchCategoryFilters =array();
42
+
43
+ /**
44
+ * @var array Search query range filters.
45
+ */
46
+ protected $_searchQueryRangeFilters = array();
47
+
48
+ /**
49
+ * @var array Search entity ids.
50
+ */
51
+ protected $_searchedEntityIds = array();
52
+
53
+ /**
54
+ * @var array Sort by definition.
55
+ */
56
+ protected $_sortBy = array();
57
+
58
+ protected $qt = 'search';
59
+
60
+ protected $stats =array();
61
+
62
+ /**
63
+ * Adds facet condition to current collection.
64
+ *
65
+ * @param string $field
66
+ * @param mixed $condition
67
+ * @return ChoiceAI_Search_Model_Resource_Catalog_Product_Collection
68
+ */
69
+ public function addFacetCondition($field, $condition = null)
70
+ {
71
+ if (array_key_exists($field, $this->_facetsConditions)) {
72
+ if (!empty($this->_facetsConditions[$field])){
73
+ $this->_facetsConditions[$field] = array($this->_facetsConditions[$field]);
74
+ }
75
+ $this->_facetsConditions[$field][] = $condition;
76
+ } else {
77
+ $this->_facetsConditions[$field] = $condition;
78
+ }
79
+
80
+ return $this;
81
+ }
82
+
83
+ /**
84
+ * Stores filter query.
85
+ *
86
+ * @param array $params
87
+ * @return ChoiceAI_Search_Model_Resource_Catalog_Product_Collection
88
+ */
89
+ public function addFqFilter($params)
90
+ {
91
+ if (is_array($params)) {
92
+ foreach ($params as $field => $value) {
93
+ $this->_searchQueryFilters[$field] = $value;
94
+ }
95
+ }
96
+
97
+ return $this;
98
+ }
99
+
100
+ /**
101
+ * Stores filter query.
102
+ *
103
+ * @param array $params
104
+ * @return ChoiceAI_Search_Model_Resource_Catalog_Product_Collection
105
+ */
106
+ public function addCategoryId($id)
107
+ {
108
+ $this->_searchCategoryFilters = $id;
109
+
110
+ return $this;
111
+ }
112
+
113
+ /**
114
+ * setting the query type
115
+ */
116
+ public function setQueryType($qt = 'search'){
117
+ $this->qt = $qt;
118
+ return $this;
119
+ }
120
+
121
+ /**
122
+ * Stores range filter query.
123
+ *
124
+ * @param array $params
125
+ * @return ChoiceAI_Search_Model_Resource_Catalog_Product_Collection
126
+ */
127
+ public function addFqRangeFilter($params)
128
+ {
129
+ if (is_array($params)) {
130
+ foreach ($params as $field => $value) {
131
+ $this->_searchQueryRangeFilters[$field] = $value;
132
+ }
133
+ }
134
+
135
+ return $this;
136
+ }
137
+
138
+ /**
139
+ * Stores query text filter.
140
+ *
141
+ * @param $query
142
+ * @return ChoiceAI_Search_Model_Resource_Catalog_Product_Collection
143
+ */
144
+ public function addSearchFilter($query)
145
+ {
146
+ $this->_searchQueryText = $query;
147
+
148
+ return $this;
149
+ }
150
+
151
+ /**
152
+ * Stores search query filter.
153
+ *
154
+ * @param mixed $param
155
+ * @param null $value
156
+ * @return ChoiceAI_Search_Model_Resource_Catalog_Product_Collection
157
+ */
158
+ public function addSearchQfFilter($param, $value = null)
159
+ {
160
+ if (is_array($param)) {
161
+ foreach ($param as $field => $value) {
162
+ $this->addSearchQfFilter($field, $value);
163
+ }
164
+ } elseif (isset($value)) {
165
+ if (isset($this->_searchQueryFilters[$param]) && !is_array($this->_searchQueryFilters[$param])) {
166
+ $this->_searchQueryFilters[$param] = array($this->_searchQueryFilters[$param]);
167
+ $this->_searchQueryFilters[$param][] = $value;
168
+ } else {
169
+ $this->_searchQueryFilters[$param] = $value;
170
+ }
171
+ }
172
+
173
+ return $this;
174
+ }
175
+
176
+ /**
177
+ * Aggregates search query filters.
178
+ *
179
+ * @return array
180
+ */
181
+ public function getExtendedSearchParams()
182
+ {
183
+ $result = $this->_searchQueryFilters;
184
+ $result['query_text'] = $this->_searchQueryText;
185
+
186
+ return $result;
187
+ }
188
+
189
+ /**
190
+ * Returns faceted data.
191
+ *
192
+ * @param string $field
193
+ * @return array
194
+ */
195
+ public function getFacetedData($field)
196
+ {
197
+
198
+ if (array_key_exists($field, $this->_facetedData)) {
199
+ return $this->_facetedData[$field];
200
+ }
201
+
202
+ return array();
203
+ }
204
+
205
+ /**
206
+ * Returns collection size.
207
+ *
208
+ * @return int
209
+ */
210
+ public function getSize()
211
+ {
212
+ if (is_null($this->_totalRecords)) {
213
+ $query = $this->_getQuery();
214
+ $params = $this->_getParams();
215
+ $params['limit'] = 1;
216
+ //$this->_engine->getIdsByQuery($query, $params);
217
+ $this->_totalRecords = 1;
218
+ //$this->_totalRecords = $this->_engine->getLastNumFound();
219
+ }
220
+
221
+ return $this->_totalRecords;
222
+ }
223
+
224
+ /**
225
+ * Retrieves current collection stats.
226
+ * Used for max price.
227
+ *
228
+ * @param $fields
229
+ * @return mixed
230
+ */
231
+ public function getStats($field)
232
+ {
233
+ return isset($this->stats[$field])?$this->stats[$field]:array();
234
+ }
235
+
236
+ /**
237
+ * Defines current search engine.
238
+ *
239
+ * @param ChoiceAI_Search_Model_Resource_Engine_Abstract $engine
240
+ * @return ChoiceAI_Search_Model_Resource_Catalog_Product_Collection
241
+ */
242
+ public function setEngine(ChoiceAI_Search_Model_Resource_Engine_Abstract $engine)
243
+ {
244
+ $this->_engine = $engine;
245
+
246
+ return $this;
247
+ }
248
+
249
+ /**
250
+ * Stores sort order.
251
+ *
252
+ * @param string $attribute
253
+ * @param string $dir
254
+ * @return ChoiceAI_Search_Model_Resource_Catalog_Product_Collection
255
+ */
256
+ public function setOrder($attribute, $dir = self::SORT_ORDER_DESC)
257
+ {
258
+ $this->_sortBy[] = array($attribute => $dir);
259
+
260
+ return $this;
261
+ }
262
+
263
+ /**
264
+ * Handles collection filtering by ids retrieves from search engine.
265
+ * Will also stores faceted data and total records.
266
+ *
267
+ * @return Mage_Catalog_Model_Resource_Product_Collection
268
+ */
269
+ protected function _beforeLoad()
270
+ {
271
+ if ($this->_engine) {
272
+ $result = $this->_engine->getIdsByQuery($this->qt, $this->_getParams());
273
+ $this->_facetedData = isset($result['faceted_data']) ? $result['faceted_data'] : array();
274
+ $this->_totalRecords = isset($result['total_count']) ? $result['total_count'] : null;
275
+ $this->stats = isset($result["stats"])?$result["stats"] :array();
276
+ $this->results = isset($result["results"]) ? $result["results"] : array();
277
+ }
278
+ foreach($this->results as $result){
279
+ $product = new Mage_Catalog_Model_Product();
280
+ $result['id'] = $result['uniqueId'];
281
+ $product->addData($result);
282
+ $this->_items[$result['id']]=$product;
283
+ }
284
+
285
+ return parent::_beforeLoad();
286
+ }
287
+
288
+
289
+
290
+ /**
291
+ * Load collection data into object items
292
+ *
293
+ * @return Mage_Eav_Model_Entity_Collection_Abstract
294
+ */
295
+ public function load($printQuery = false, $logQuery = false)
296
+ {
297
+ if ($this->isLoaded()) {
298
+ return $this;
299
+ }
300
+ Varien_Profiler::start('__EAV_COLLECTION_BEFORE_LOAD__');
301
+ Mage::dispatchEvent('eav_collection_abstract_load_before', array('collection' => $this));
302
+ $this->_beforeLoad();
303
+ Varien_Profiler::stop('__EAV_COLLECTION_BEFORE_LOAD__');
304
+
305
+
306
+ Varien_Profiler::start('__EAV_COLLECTION_LOAD_ENT__');
307
+ // $this->_loadEntities($printQuery, $logQuery);
308
+ Varien_Profiler::stop('__EAV_COLLECTION_LOAD_ENT__');
309
+ Varien_Profiler::start('__EAV_COLLECTION_LOAD_ATTR__');
310
+ // $this->_loadAttributes($printQuery, $logQuery);
311
+ Varien_Profiler::stop('__EAV_COLLECTION_LOAD_ATTR__');
312
+
313
+ Varien_Profiler::start('__EAV_COLLECTION_ORIG_DATA__');
314
+ /*
315
+ foreach ($this->_items as $item) {
316
+ $item->setOrigData();
317
+ }*/
318
+ Varien_Profiler::stop('__EAV_COLLECTION_ORIG_DATA__');
319
+
320
+ $this->_setIsLoaded();
321
+ Varien_Profiler::start('__EAV_COLLECTION_AFTER_LOAD__');
322
+ $this->_afterLoad();
323
+ Varien_Profiler::stop('__EAV_COLLECTION_AFTER_LOAD__');
324
+ return $this;
325
+ }
326
+
327
+ /**
328
+ * Retrieves parameters.
329
+ *
330
+ * @return array
331
+ */
332
+ protected function _getParams()
333
+ {
334
+ $store = Mage::app()->getStore($this->getStoreId());
335
+ $params = array();
336
+ $params['locale_code'] = $store->getConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_LOCALE);
337
+ $params['filters'] = $this->_searchQueryFilters;
338
+ $params['category'] = $this->_searchCategoryFilters;
339
+ $params['range_filters'] = $this->_searchQueryRangeFilters;
340
+
341
+ if (!empty($this->_sortBy)) {
342
+ $params['sort_by'] = $this->_sortBy;
343
+ }
344
+
345
+ if ($this->_pageSize !== false) {
346
+ $page = ($this->_curPage > 0) ? (int) $this->_curPage : 1;
347
+ $rowCount = ($this->_pageSize > 0) ? (int) $this->_pageSize : 1;
348
+ $params['offset'] = $rowCount * ($page - 1);
349
+ $params['limit'] = $rowCount;
350
+ }
351
+
352
+ if (!empty($this->_facetsConditions)) {
353
+ $params['facets'] = $this->_facetsConditions;
354
+ }
355
+
356
+ return $params;
357
+ }
358
+
359
+ /**
360
+ * Returns stored text query.
361
+ *
362
+ * @return string
363
+ */
364
+ protected function _getQuery()
365
+ {
366
+ return $this->_searchQueryText;
367
+ }
368
+ }
app/code/local/ChoiceAI/Search/Model/Resource/Engine/Abstract.php ADDED
@@ -0,0 +1,453 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * search client.
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ abstract class ChoiceAI_Search_Model_Resource_Engine_Abstract
10
+ {
11
+ const DEFAULT_ROWS_LIMIT = 9999;
12
+
13
+ const UNIQUE_KEY = 'unique';
14
+
15
+ /**
16
+ * @var string List of advanced index fields prefix.
17
+ */
18
+ protected $_advancedIndexFieldsPrefix = '#';
19
+
20
+ /**
21
+ * @var array List of advanced dynamic index fields.
22
+ */
23
+ protected $_advancedDynamicIndexFields = array(
24
+ '#position_category_',
25
+ '#price_'
26
+ );
27
+
28
+ /**
29
+ * @var object Search engine client.
30
+ */
31
+ protected $_client;
32
+
33
+ /**
34
+ * @var array List of dates format.
35
+ */
36
+ protected $_dateFormats = array();
37
+
38
+ /**
39
+ * @var array List of default query parameters.
40
+ */
41
+ protected $_defaultQueryParams = array(
42
+ 'offset' => 0,
43
+ 'limit' => 100,
44
+ 'sort_by' => array(array('relevance' => 'desc')),
45
+ 'store_id' => null,
46
+ 'locale_code' => null,
47
+ 'fields' => array(),
48
+ 'params' => array(),
49
+ 'ignore_handler' => false,
50
+ 'filters' => array(),
51
+ );
52
+
53
+ /**
54
+ * @var array List of indexable attribute parameters.
55
+ */
56
+ protected $_indexableAttributeParams = array();
57
+
58
+ /**
59
+ * @var int Last number of results found.
60
+ */
61
+ protected $_lastNumFound;
62
+
63
+ /**
64
+ * @var array List of non fulltext fields.
65
+ */
66
+ protected $_notInFulltextField = array(
67
+ self::UNIQUE_KEY,
68
+ 'id',
69
+ 'store_id',
70
+ 'in_stock',
71
+ 'categories',
72
+ 'show_in_categories',
73
+ 'visibility'
74
+ );
75
+
76
+ /**
77
+ * @var bool Stores search engine availibility
78
+ */
79
+ protected $_test = null;
80
+
81
+ /**
82
+ * @var array List of used fields.
83
+ */
84
+ protected $_usedFields = array(
85
+ self::UNIQUE_KEY,
86
+ 'id',
87
+ 'sku',
88
+ 'price',
89
+ 'store_id',
90
+ 'categories',
91
+ 'show_in_categories',
92
+ 'visibility',
93
+ 'in_stock',
94
+ 'score'
95
+ );
96
+
97
+ /**
98
+ * Get Indexer instance
99
+ *
100
+ * @return Mage_Index_Model_Indexer
101
+ */
102
+ protected function _getIndexer()
103
+ {
104
+ return Mage::getSingleton('index/indexer');
105
+ }
106
+
107
+ /**
108
+ * Adds advanced index fields to index data.
109
+ *
110
+ * @param array $index
111
+ * @param int $storeId
112
+ * @param array $productIds
113
+ * @return array
114
+ */
115
+ public function addAdvancedIndex($index, $storeId, $productIds = null)
116
+ {
117
+ return 1;
118
+ }
119
+
120
+ /**
121
+ * Checks if advanced index is allowed for current search engine.
122
+ *
123
+ * @return bool
124
+ */
125
+ public function allowAdvancedIndex()
126
+ {
127
+ return false;
128
+
129
+ }
130
+
131
+
132
+ public function cleanIndex()
133
+ {
134
+ return $this;
135
+ }
136
+
137
+ /**
138
+ * Cleans cache.
139
+ *
140
+ * @return ChoiceAI_Search_Model_Resource_Engine_Abstract
141
+ */
142
+ public function cleanCache()
143
+ {
144
+ return $this->_getIndexer()->getProcessByCode('catalogsearch_fulltext')->cleanCache();
145
+
146
+ }
147
+
148
+
149
+
150
+
151
+ /**
152
+ * Returns product visibility ids for search.
153
+ *
154
+ * @see Mage_Catalog_Model_Product_Visibility
155
+ * @return mixed
156
+ */
157
+ public function getAllowedVisibility()
158
+ {
159
+ return Mage::getSingleton('catalog/product_visibility')->getVisibleInSearchIds();
160
+ }
161
+
162
+ /**
163
+ * Returns advanced index fields prefix.
164
+ *
165
+ * @return string
166
+ */
167
+ public function getFieldsPrefix()
168
+ {
169
+ return $this->_advancedIndexFieldsPrefix;
170
+ }
171
+
172
+ /**
173
+ * Retrieves product ids for specified query.
174
+ *
175
+ * @param string $query
176
+ * @param array $params
177
+ * @param string $type
178
+ * @return array
179
+ */
180
+ public function getIdsByQuery($query, $params = array(), $type = 'product')
181
+ {
182
+ $ids = array();
183
+ $params['fields'] = array('id');
184
+ $resultTmp = $this->search($query, $params, $type);
185
+ if (!empty($resultTmp['ids'])) {
186
+ foreach ($resultTmp['ids'] as $id) {
187
+ $ids[] = $id['uniqueId'];
188
+ }
189
+ }
190
+ $result = array(
191
+ 'ids' => $ids,
192
+ 'total_count' => (isset($resultTmp['total_count'])) ? $resultTmp['total_count'] : null,
193
+ 'faceted_data' => (isset($resultTmp['facets'])) ? $resultTmp['facets'] : array(),
194
+ 'results' => array_key_exists('result', $resultTmp)?$resultTmp["result"]: array(),
195
+ 'stats' => array_key_exists('stats', $resultTmp)?$resultTmp["stats"]: array()
196
+ );
197
+
198
+ return $result;
199
+ }
200
+
201
+ /**
202
+ * Returns last number of results found.
203
+ *
204
+ * @return int
205
+ */
206
+ public function getLastNumFound()
207
+ {
208
+ return $this->_lastNumFound;
209
+ }
210
+
211
+ /**
212
+ * Returns catalog product collection with current search engine set.
213
+ *
214
+ * @return ChoiceAI_Search_Model_Resource_Catalog_Product_Collection
215
+ */
216
+ public function getResultCollection()
217
+ {
218
+ return Mage::getResourceModel('choiceai_search/catalog_product_collection')->setEngine($this);
219
+ }
220
+
221
+
222
+ /**
223
+ * Alias of isLayeredNavigationAllowed.
224
+ *
225
+ * @return bool
226
+ */
227
+ public function isLeyeredNavigationAllowed()
228
+ {
229
+ return $this->isLayeredNavigationAllowed();
230
+ }
231
+
232
+ /**
233
+ * Checks if layered navigation is available for current search engine.
234
+ *
235
+ * @return bool
236
+ */
237
+ public function isLayeredNavigationAllowed()
238
+ {
239
+ return true;
240
+ }
241
+
242
+ /**
243
+ * Prepares index data.
244
+ * Should be overriden in child classes if needed.
245
+ *
246
+ * @param $index
247
+ * @param string $separator
248
+ * @return array
249
+ */
250
+ public function prepareEntityIndex($index, $separator = null)
251
+ {
252
+ return $this->_getHelper()->prepareIndexData($index, $separator);
253
+ }
254
+
255
+ /**
256
+ * Performs search query and facetting.
257
+ *
258
+ * @param string $query
259
+ * @param array $params
260
+ * @param string $type
261
+ * @return array
262
+ */
263
+ public function search($query, $params = array(), $type = 'product')
264
+ {
265
+ try {
266
+ Varien_Profiler::start('CHOICEAI_SEARCH');
267
+ $result = $this->_search($query, $params, $type);
268
+ Varien_Profiler::stop('CHOICEAI_SEARCH');
269
+
270
+ return $result;
271
+ } catch (Exception $e) {
272
+ Mage::logException($e);
273
+ if ($this->_getHelper()->isDebugEnabled()) {
274
+ $this->_getHelper()->showError($e->getMessage());
275
+ }
276
+ }
277
+
278
+ return array();
279
+ }
280
+
281
+ /**
282
+ * Checks search engine availability.
283
+ * Should be overriden by child classes.
284
+ *
285
+ * @return bool
286
+ */
287
+ public function test()
288
+ {
289
+ return true;
290
+ }
291
+
292
+ /**
293
+ * Transforms specified date to basic YYYY-MM-dd format.
294
+ *
295
+ * @param int $storeId
296
+ * @param string $date
297
+ * @return null|string
298
+ */
299
+ protected function _getDate($storeId, $date = null)
300
+ {
301
+ if (!isset($this->_dateFormats[$storeId])) {
302
+ $timezone = Mage::getStoreConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_TIMEZONE, $storeId);
303
+ $locale = Mage::getStoreConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_LOCALE, $storeId);
304
+ $locale = new Zend_Locale($locale);
305
+
306
+ $dateObj = new Zend_Date(null, null, $locale);
307
+ $dateObj->setTimezone($timezone);
308
+ $this->_dateFormats[$storeId] = array($dateObj, $locale->getTranslation(null, 'date', $locale));
309
+ }
310
+
311
+ if (is_empty_date($date)) {
312
+ return null;
313
+ }
314
+
315
+ list($dateObj, $localeDateFormat) = $this->_dateFormats[$storeId];
316
+ $dateObj->setDate($date, $localeDateFormat);
317
+
318
+ return $dateObj->toString('YYYY-MM-dd');
319
+ }
320
+
321
+ /**
322
+ * Returns search helper.
323
+ *
324
+ * @return ChoiceAI_Search_Helper_Data
325
+ */
326
+ protected function _getHelper()
327
+ {
328
+ return Mage::helper('choiceai_search');
329
+ }
330
+
331
+ /**
332
+ * Returns indexable attribute parameters.
333
+ *
334
+ * @return array
335
+ */
336
+ protected function _getIndexableAttributeParams()
337
+ {
338
+ if (null === $this->_indexableAttributeParams) {
339
+ $this->_indexableAttributeParams = array();
340
+ $attributes = $this->_getHelper()->getSearchableAttributes();
341
+ foreach ($attributes as $attribute) {
342
+ /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */
343
+ $this->_indexableAttributeParams[$attribute->getAttributeCode()] = array(
344
+ 'backend_type' => $attribute->getBackendType(),
345
+ 'frontend_input' => $attribute->getFrontendInput(),
346
+ 'search_weight' => $attribute->getSearchWeight(),
347
+ 'is_searchable' => $attribute->getIsSearchable()
348
+ );
349
+ }
350
+ }
351
+
352
+ return $this->_getIndexer()->getProcessByCode('catalogsearch_fulltext')->_getIndexableAttributeParams();
353
+ }
354
+
355
+ /**
356
+ * Returns store locale code.
357
+ *
358
+ * @param int $storeId
359
+ * @return string
360
+ */
361
+ protected function _getLocaleCode($storeId = null)
362
+ {
363
+ return $this->_getHelper()->getLocaleCode($storeId);
364
+ }
365
+
366
+ /**
367
+ * Transforms specified object to an array.
368
+ *
369
+ * @param $object
370
+ * @return array
371
+ */
372
+ protected function _objectToArray($object)
373
+ {
374
+ if (!is_object($object) && !is_array($object)){
375
+ return $object;
376
+ }
377
+ if (is_object($object)){
378
+ $object = get_object_vars($object);
379
+ }
380
+
381
+ return array_map(array($this, '_objectToArray'), $object);
382
+ }
383
+
384
+ /**
385
+ * @param array $docsData
386
+ * @param string $type
387
+ * @param string $localeCode
388
+ * @return array
389
+ */
390
+ protected function _prepareDocs($docsData, $type, $localeCode = null)
391
+ {
392
+ if (!is_array($docsData) || empty($docsData)) {
393
+ return array();
394
+ }
395
+
396
+ $docs = array();
397
+ foreach ($docsData as $entityId => $index) {
398
+ $index[self::UNIQUE_KEY] = $entityId . '|' . $index['store_id'];
399
+ $index['id'] = $entityId;
400
+ $index = $this->_prepareIndexData($index, $localeCode);
401
+ $docs[] = $this->_createDoc($entityId, $index, $type);
402
+ }
403
+
404
+ return $this->_getIndexer()->getProcessByCode('catalogsearch_fulltext')->_prepareDocs();
405
+ }
406
+
407
+ /**
408
+ * Prepares index data before indexation.
409
+ *
410
+ * @param array $data
411
+ * @param string $localeCode
412
+ * @return array
413
+ */
414
+ protected function _prepareIndexData($data, $localeCode = null)
415
+ {
416
+ if (!is_array($data) || empty($data)) {
417
+ return array();
418
+ }
419
+
420
+ foreach ($data as $key => $value) {
421
+ if (in_array($key, $this->_usedFields)) {
422
+ continue;
423
+ } elseif ($key == 'options') {
424
+ unset($data[$key]);
425
+ continue;
426
+ }
427
+ $field = $this->_getHelper()->getAttributeFieldName($key, $localeCode);
428
+ $field = str_replace($this->_advancedIndexFieldsPrefix, '', $field);
429
+ if ($field != $key) {
430
+ $data[$field] = $value;
431
+ unset($data[$key]);
432
+ }
433
+ }
434
+
435
+ return $this->_getIndexer()->getProcessByCode('catalogsearch_fulltext')->_prepareIndexData();
436
+ }
437
+
438
+ /**
439
+ * Prepares query before search.
440
+ *
441
+ * @param mixed $query
442
+ * @return string
443
+ */
444
+ protected function _prepareSearchConditions($query)
445
+ {
446
+ return $query;
447
+ }
448
+
449
+ public function saveEntityIndexes()
450
+ {
451
+ return $this;
452
+ }
453
+ }
app/code/local/ChoiceAI/Search/Model/Resource/Engine/Choiceaisearch.php ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * ChoiceAI engine.
5
+ *
6
+ * @package ChoiceAI_Search
7
+ * @copyright Copyright (c) MineWhat
8
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
9
+ */
10
+ class ChoiceAI_Search_Model_Resource_Engine_ChoiceAIsearch extends ChoiceAI_Search_Model_Resource_Engine_Abstract
11
+ {
12
+ /**
13
+ * Initializes search engine.
14
+ *
15
+ * @see
16
+ */
17
+ public function __construct()
18
+ {
19
+ $this->client = Mage::getResourceSingleton('choiceai_search/engine_choiceaisearch_client');
20
+ }
21
+
22
+ function _prepareFacetsQueryResponse($response = array()){
23
+ $result = array();
24
+ foreach ($response as $facetName=>$facetlist) {
25
+ if($facetlist["type"]=='facet_fields'){
26
+ $result[$facetName] = array();
27
+ $count = 0;
28
+ $facetKey ='';
29
+ foreach($facetlist['values'] as $value){
30
+ if($count++ % 2 == 0){
31
+ $facetKey = $value;
32
+ }else{
33
+ $result[$facetName][$facetKey]=$value;
34
+ }
35
+ }
36
+ }else if($facetlist["type"]=='facet_ranges'){
37
+ $result[$facetName] = array();
38
+ $count = 0;
39
+ $facetKey = '';
40
+ $gap = floatval($facetlist['values']['gap']);
41
+ foreach($facetlist['values']['counts'] as $value){
42
+ if($count++ % 2 == 0){
43
+ $facetKey = floatval($value);
44
+ }else{
45
+ $result[$facetName]['['.$facetKey.' TO '.($facetKey + $gap).']']=$value;
46
+ }
47
+ }
48
+ }
49
+ }
50
+ return $result;
51
+
52
+ }
53
+
54
+ /**
55
+ * prepares the facet condtion
56
+ */
57
+ public function _prepareFacetsConditions($facets = array()){
58
+
59
+ $stringFacets = array();
60
+ $rangeFacets = array();
61
+ if(is_array($facets)){
62
+ foreach($facets as $facetKey=>$facetValue){
63
+ if(is_array($facetValue) && $facetValue != null && is_array($facetValue) && sizeof($facetValue) > 0 ){
64
+ if(isset($facetValue['from']) && isset($facetValue["to"])){
65
+ $facetValues= array();
66
+ $eachFacetValue= $facetValue;
67
+ if(!isset($eachFacetValue['from']) || $eachFacetValue['from'] == "" ){
68
+ $eachFacetValue['from'] = '0';
69
+ }
70
+ if(!isset($eachFacetValue['to']) || $eachFacetValue['to'] == "" ){
71
+ $eachFacetValue['to'] = '*';
72
+ }
73
+ $facetValues['from'] = $eachFacetValue['from'];
74
+ $facetValues['to'] = $eachFacetValue['to'];
75
+ $stringFacets[$facetKey][] = $facetValues;
76
+ } else {
77
+ $stringFacets[$facetKey] = $facetValue;
78
+ }
79
+ }
80
+ }
81
+ }
82
+ $facets=array();
83
+ $facets["attribute"] = $stringFacets;
84
+ $facets["range"] = $rangeFacets;
85
+ return $facets;
86
+ }
87
+
88
+ function str_lreplace($search, $replace, $subject)
89
+ {
90
+ $pos = strrpos($subject, $search);
91
+
92
+ if($pos !== false) {
93
+ $subject = substr_replace($subject, $replace, $pos, strlen($search));
94
+ }
95
+ return $subject;
96
+ }
97
+
98
+ protected function _prepareResponse($data){
99
+
100
+ /* @var $response ChoiceAI_ResultSet */
101
+ if (!$data instanceof ChoiceAI_ResultSet || $data->getTotalHits()<=0) {
102
+ return array();
103
+ }
104
+
105
+ $result = array();
106
+
107
+ foreach ($data->getResults() as $doc) {
108
+ $result[] =$doc->getHit();
109
+ }
110
+ return $result;
111
+ }
112
+
113
+ /**
114
+ * Prepares sort fields.
115
+ *
116
+ * @param array $sortBy
117
+ * @return array
118
+ */
119
+ protected function _prepareSortFields($sortBy=array())
120
+ {
121
+ $sort =array();
122
+ if(!isset($sortBy) || sizeof($sortBy) == 0) {
123
+ $sortParameter = array_key_exists('order',$_GET)?$_GET['order']:null;
124
+ $sortBy = (!is_null($sortParameter))?
125
+ array(array($sortParameter => (isset($_GET['dir']) && $_GET['dir'] == 'desc')?'desc':'asc')): array();
126
+ $sessionSort = Mage::getSingleton('catalog/session')->getSortOrder();
127
+ $sessionDir = Mage::getSingleton('catalog/session')->getSortDirection();
128
+ $sortBy = (is_null($sortBy)|| sizeof($sortBy) == 0) && !is_null($sessionSort) ?
129
+ array(array($sessionSort => ($sessionDir === 'desc')?'desc':'asc')):$sortBy;
130
+ }
131
+
132
+ foreach($sortBy as $value){
133
+ foreach($value as $sortKey=>$sortValue){
134
+ if($sortKey != "position" && $sortKey != "relevance"){
135
+ if($sortValue == 'asc'){
136
+ $sort[$sortKey] = 1;
137
+
138
+ }else{
139
+
140
+ $sort[$sortKey] = -1;
141
+
142
+ }
143
+ }
144
+ }
145
+ }
146
+ return $sort;
147
+ }
148
+
149
+
150
+ public function getStats($data){
151
+ $stats = $data->getStats();
152
+ if(isset($stats) && is_array($stats)){
153
+ return $stats;
154
+ }
155
+ return array();
156
+ }
157
+
158
+ /**
159
+ * prepare limitN
160
+ * @param $params
161
+ * @return int|mixed
162
+ */
163
+ protected function _prepareLimit($params) {
164
+ $limitInRequest = array_key_exists('limit', $_GET)?$_GET['limit']:null;
165
+ $limitOnSession = Mage::getSingleton('catalog/session')->getLimitPage();
166
+ if($limitOnSession === "all" || $limitInRequest === "all") {
167
+ $limitOnSession = 100;
168
+ }
169
+ $limit = ($limitInRequest > 0)? (int) $limitInRequest:($limitOnSession > 0? $limitOnSession: ((isset($_GET['mode']) && $_GET['mode'] == 'list')?Mage::getStoreConfig('catalog/frontend/list_per_page'): Mage::getStoreConfig('catalog/frontend/grid_per_page')));
170
+ if(array_key_exists("limit", $params)) {
171
+ $limit = (int)$params["limit"];
172
+ }
173
+ return $limit;
174
+
175
+ }
176
+
177
+ /**
178
+ * Performs search and facetting.
179
+ *
180
+ * @param string $query
181
+ * @param array $params
182
+ * @param string $type
183
+ * @return array
184
+ */
185
+ protected function _search($qt, $params = array(), $type = 'product')
186
+ {
187
+ $multiselectValue = Mage::getConfig()->getNode('default/choiceai/general/multiselect_facet');
188
+ $multiselectValue = (!is_null($multiselectValue) &&
189
+ sizeof($multiselectValue) && $multiselectValue[0] == 'true')?true:false;
190
+ $limit = $this->_prepareLimit($params);
191
+ if(isset($_GET['p'])){
192
+ $page = ((int)$_GET['p'] > 0)?((int)$_GET['p'] - 1)* $limit:0;
193
+ }else{
194
+ $page = 0;
195
+ }
196
+
197
+ $facets = $this->_prepareFacetsConditions($params['filters']);
198
+ $searchParams = array();
199
+ $query = Mage::helper('catalogsearch')->getQueryText();
200
+
201
+ if(isset($query) && $query != ''){
202
+ $this->client = $this->client->setRuleset('search')->setQuery($query)->setFilters($facets['attribute']);
203
+ }else{
204
+ $this->client = $this->client->setRuleset('browse')->setCategoryId($params['category'])->setFilters($facets['attribute']);
205
+ }
206
+ $agent_tokens =explode(' ',$_SERVER['HTTP_USER_AGENT']);
207
+ $data = $this->client
208
+ ->setOffset($page)
209
+ ->setLimit($limit)
210
+ ->setOtherOptions(array('wt' => 'json', 'user_agent' => $agent_tokens[0],
211
+ 'stats' => 'price', 'indent' => 'on',
212
+ 'u' => (isset($_COOKIE['choiceai_userId'])) ? $_COOKIE['choiceai_userId'] : NULL,
213
+ 'facet.multiselect' => $multiselectValue?"true":"false"))
214
+ ->setDebug(false)
215
+ ->setSort($this->_prepareSortFields(array_key_exists('sort_by', $params)?$params['sort_by']:array()))
216
+ ->search();
217
+ if (!$data instanceof ChoiceAI_ResultSet) {
218
+ return array();
219
+ }
220
+
221
+ if($data->getSpellCheckQuery()) {
222
+ Mage::unregister('spellcheckQuery');
223
+ Mage::register('spellcheckQuery', $data->getSpellCheckQuery());
224
+ }
225
+
226
+
227
+ /* @var $data ChoiceAI_ResultSet */
228
+
229
+ $result = array(
230
+ 'total_count' => $data->getTotalHits(),
231
+ 'result'=> $this->_prepareResponse($data),
232
+ 'stats'=>$this->getStats($data)
233
+ );
234
+ $result['facets'] = $this->_prepareFacetsQueryResponse($data->getFacets());
235
+ Mage::unregister('start');
236
+ Mage::register('start', $page* Mage::getStoreConfig('catalog/frontend/grid_per_page'));
237
+ return $result;
238
+ }
239
+
240
+ }
241
+
242
+ ?>
app/code/local/ChoiceAI/Search/Model/Resource/Engine/Choiceaisearch/Client.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ * @package ChoiceAI_Search
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+
10
+ class ChoiceAI_Search_Model_Resource_Engine_ChoiceAIsearch_Client extends ChoiceAI_Client{
11
+
12
+ const CONFIG_API_KEY = 'choiceai_personalisation/settings/api_key';
13
+
14
+ public function __construct()
15
+ {
16
+ $config = $this->_getHelper()->getEngineConfigData();
17
+ $config['context'] = Mage::getStoreConfig(self::CONFIG_API_KEY);
18
+ parent::__construct($config);
19
+
20
+ }
21
+
22
+ protected function _getHelper()
23
+ {
24
+ return Mage::helper('choiceai_search/choiceaisearch');
25
+ }
26
+
27
+
28
+ }
29
+ ?>
app/code/local/ChoiceAI/Search/etc/config.xml ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <ChoiceAI_Search>
5
+ <version>0.0.9</version>
6
+ </ChoiceAI_Search>
7
+ </modules>
8
+ <global>
9
+ <models>
10
+ <choiceai_search>
11
+ <class>ChoiceAI_Search_Model</class>
12
+ <resourceModel>choiceai_search_resource</resourceModel>
13
+ </choiceai_search>
14
+ <choiceai_search_resource>
15
+ <class>ChoiceAI_Search_Model_Resource</class>
16
+ </choiceai_search_resource>
17
+ <catalog>
18
+ <rewrite>
19
+ <config>ChoiceAI_Search_Model_Catalog_Config</config>
20
+ <category>ChoiceAI_Search_Model_Catalog_Category</category>
21
+ </rewrite>
22
+ </catalog>
23
+ </models>
24
+ <helpers>
25
+ <choiceai_search>
26
+ <class>ChoiceAI_Search_Helper</class>
27
+ </choiceai_search>
28
+ <catalogsearch>
29
+ <rewrite>
30
+ <data>ChoiceAI_Search_Helper_Catalogsearch</data>
31
+ </rewrite>
32
+ </catalogsearch>
33
+ </helpers>
34
+ <blocks>
35
+ <choiceai_search>
36
+ <class>ChoiceAI_Search_Block</class>
37
+ </choiceai_search>
38
+ <catalog>
39
+ <rewrite>
40
+ <layer_view>ChoiceAI_Search_Block_Catalog_Layer_View</layer_view>
41
+ <product_list>ChoiceAI_Search_Block_Catalog_Product_List</product_list>
42
+ <product_list_toolbar>ChoiceAI_Search_Block_Catalog_Product_List_Toolbar</product_list_toolbar>
43
+ </rewrite>
44
+ </catalog>
45
+ <catalogsearch>
46
+ <rewrite>
47
+ <layer>ChoiceAI_Search_Block_Catalogsearch_Layer</layer>
48
+ <result>ChoiceAI_Search_Block_Catalogsearch_Result</result>
49
+ </rewrite>
50
+ </catalogsearch>
51
+ <enterprise_search>
52
+ <rewrite>
53
+ <catalogsearch_layer>ChoiceAI_Search_Block_Catalogsearch_Enterprise_Layer</catalogsearch_layer>
54
+ </rewrite>
55
+ </enterprise_search>
56
+ </blocks>
57
+ <resources>
58
+ <choiceai_search_setup>
59
+ <setup>
60
+ <module>ChoiceAI_Search</module>
61
+ <class>Mage_Core_Model_Resource_Setup</class>
62
+ </setup>
63
+ </choiceai_search_setup>
64
+ </resources>
65
+ </global>
66
+ <default>
67
+ <catalog>
68
+ <search>
69
+ <choiceai_ruleset>search</choiceai_ruleset>
70
+ <choiceai_timeout>300</choiceai_timeout>
71
+ </search>
72
+ </catalog>
73
+ <choiceai>
74
+ <general>
75
+ <multiselect_facet>true</multiselect_facet>
76
+ <autosuggest_status>false</autosuggest_status>
77
+ <autosuggest_skin>#ff8400</autosuggest_skin>
78
+ <autosuggest_template>1column</autosuggest_template>
79
+ <autosuggest_max_suggestion>12</autosuggest_max_suggestion>
80
+ <autosuggest_top_queries_status>false</autosuggest_top_queries_status>
81
+ <autosuggest_keyword_status>true</autosuggest_keyword_status>
82
+ <autosuggest_search_scope_status>true</autosuggest_search_scope_status>
83
+ <autosuggest_max_products>2</autosuggest_max_products>
84
+ <autosuggest_product_header>Popular Products</autosuggest_product_header>
85
+ <autosuggest_keyword_header></autosuggest_keyword_header>
86
+ <autosuggest_search_scope_header></autosuggest_search_scope_header>
87
+ <autosuggest_show_cart>false</autosuggest_show_cart>
88
+ <autosuggest_sidecontent>right</autosuggest_sidecontent>
89
+ <autosuggest_topquery_header></autosuggest_topquery_header>
90
+ <autosuggest_keyword_header></autosuggest_keyword_header>
91
+ <autosuggest_search_scope_header></autosuggest_search_scope_header>
92
+ <autosuggest_pop_product_header>Popular Products</autosuggest_pop_product_header>
93
+ <search_mod_status>false</search_mod_status>
94
+ <search_mod_power>search</search_mod_power>
95
+ <search_hosted_status>false</search_hosted_status>
96
+ <search_hosted_int_status>false</search_hosted_int_status>
97
+ <search_hosted_redirect_url></search_hosted_redirect_url>
98
+ </general>
99
+ </choiceai>
100
+ </default>
101
+ </config>
app/code/local/ChoiceAI/Searchcore/Helper/Confighelper.php ADDED
@@ -0,0 +1,472 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Searchcore_Helper_Confighelper extends ChoiceAI_Searchcore_Helper_Data
9
+ {
10
+
11
+ const SITE_KEY = "site_key";
12
+
13
+ const API_KEY = "api_key";
14
+
15
+ const SECRET_KEY = "secret_key";
16
+
17
+ const USERNAME = "username";
18
+
19
+ const NEED_FEATURE_FIELD_UPDATION = "need_feature_field_updation";
20
+
21
+ const IS_CRON_ENABLED = "cron_enabled";
22
+
23
+ const SUBJECT = 'subject';
24
+
25
+ const CONTENT = 'content';
26
+
27
+ const CC = 'cc';
28
+
29
+
30
+ /**
31
+ * All possible data type values supported choiceai
32
+ * @var array
33
+ */
34
+ public static $data_types = array("text", "longText", "link", "decimal", "number", "datetime");
35
+
36
+ public function validateAndSaveKeys($website, $requestBody)
37
+ {
38
+ $errors = $this->validateKeyParams($requestBody);
39
+ if (sizeof($errors) > 0) {
40
+ return $errors;
41
+ }
42
+ $requestParams = json_decode($requestBody, true);
43
+ if (!$requestParams) {
44
+ $errors['message'] = 'Invalid Request';
45
+ return $errors;
46
+ }
47
+ $response = Mage::getModel("choiceai_searchcore/api_task_validatekeys")
48
+ ->setData(ChoiceAI_Searchcore_Model_Api_Task_Validatekeys::SECRET_KEY, $requestParams[self::SECRET_KEY])
49
+ ->setData(ChoiceAI_Searchcore_Model_Api_Task_Validatekeys::SITE_KEY, $requestParams[self::SITE_KEY])
50
+ ->prepare($website)
51
+ ->process();
52
+ if (!$response->isSuccess()) {
53
+ return $response->getErrors();
54
+ }
55
+
56
+ $existingSecretKey = Mage::getResourceModel('choiceai_searchcore/config')
57
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Constants::SECRET_KEY);
58
+ $keyAlreadyExists = !is_null($existingSecretKey);
59
+ if ($keyAlreadyExists) {
60
+ $this->flushConfigs($website);
61
+ }
62
+
63
+ Mage::getResourceModel('choiceai_searchcore/config')
64
+ ->setValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Constants::SECRET_KEY,
65
+ $requestParams[ChoiceAI_Searchcore_Helper_Constants::SECRET_KEY]);
66
+ Mage::getResourceModel('choiceai_searchcore/config')
67
+ ->setValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Constants::SITE_KEY,
68
+ $requestParams[ChoiceAI_Searchcore_Helper_Constants::SITE_KEY]);
69
+ $response = $response->getResponse();
70
+ Mage::getResourceModel('choiceai_searchcore/config')
71
+ ->setValue($website->getWebsiteId(),
72
+ ChoiceAI_Searchcore_Helper_Constants::API_KEY,
73
+ $response[ChoiceAI_Searchcore_Model_Api_Task_Validatekeys::API_KEY]);
74
+ Mage::getResourceModel('choiceai_searchcore/config')
75
+ ->setValue($website->getWebsiteId(),
76
+ ChoiceAI_Searchcore_Helper_Constants::USERNAME,
77
+ $response[ChoiceAI_Searchcore_Model_Api_Task_Validatekeys::USERNAME]);
78
+ $this->saveConfig(Mage::app()->getWebsite(),
79
+ array(ChoiceAI_Searchcore_Helper_Constants::API_KEY => $response[ChoiceAI_Searchcore_Model_Api_Task_Validatekeys::API_KEY],
80
+ ChoiceAI_Searchcore_Helper_Constants::SITE_KEY => $requestParams[ChoiceAI_Searchcore_Helper_Constants::SITE_KEY]));
81
+ return $errors;
82
+ }
83
+
84
+ public function flushConfigs($website)
85
+ {
86
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::DEBUG, 'Flushing all the configs');
87
+ $configs = $this->getEngineConfigData('', $website, true);
88
+ foreach ($configs as $config => $value) {
89
+ Mage::getConfig()->deleteConfig(ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_CONFIG_PREFIX .
90
+ ChoiceAI_Searchcore_Helper_Constants::CONFIG_SEPARATOR .
91
+ $config,
92
+ 'websites',
93
+ (int)$website->getWebsiteId());
94
+ }
95
+ Mage::getResourceModel('choiceai_searchcore/config')->deleteAll($website->getWebsiteId());
96
+
97
+ }
98
+
99
+ public function validateKeyParams($requestBody)
100
+ {
101
+ $errors = array();
102
+ $requestParams = json_decode($requestBody, true);
103
+ if (!$requestParams) {
104
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR, 'Invalid request with requestBody' . $requestBody);
105
+ $errors['message'] = 'Invalid Request';
106
+ return $errors;
107
+ }
108
+ if (!array_key_exists(ChoiceAI_Searchcore_Helper_Constants::SECRET_KEY, $requestParams)) {
109
+ $errors[ChoiceAI_Searchcore_Helper_Constants::SECRET_KEY] = "Has Empty Data";
110
+ }
111
+ if (!array_key_exists(ChoiceAI_Searchcore_Helper_Constants::SITE_KEY, $requestParams)) {
112
+ $errors[ChoiceAI_Searchcore_Helper_Constants::SITE_KEY] = "Has Empty Data";
113
+ }
114
+ return $errors;
115
+ }
116
+
117
+ public function getFeatureFields()
118
+ {
119
+ return ChoiceAI_Searchcore_Model_Field::$feature_fields;
120
+ }
121
+
122
+ public function getAllAttributes($fieldNameAsKey = false)
123
+ {
124
+ $attributes = Mage::getSingleton('eav/config')
125
+ ->getEntityType(Mage_Catalog_Model_Product::ENTITY)->getAttributeCollection();
126
+ $fields = array();
127
+ foreach ($attributes as $attribute) {
128
+ $attributeType = $attribute->getFrontendInput();
129
+ $fieldType = $attributeType == 'media_image' ? ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_IMAGE :
130
+ ($attributeType == 'price' ? ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_NUMBER :
131
+ ($attributeType == 'date' ? ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_DATE :
132
+ ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_STRING));
133
+ $fieldType = ($attribute->getName() == "created_at") ? ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_DATE : $fieldType;
134
+ $fieldType = ($attribute->getName() == "updated_at") ? ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_DATE : $fieldType;
135
+ if ($fieldNameAsKey) {
136
+ $fields[$attribute->getName()] = array(ChoiceAI_Searchcore_Helper_Constants::FIELD_NAME => $attribute->getName(),
137
+ ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE => $fieldType);
138
+ } else {
139
+ $fields[] = array(ChoiceAI_Searchcore_Helper_Constants::FIELD_NAME => $attribute->getName(),
140
+ ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE => $fieldType);
141
+ }
142
+ }
143
+ if ($fieldNameAsKey) {
144
+ $fields['final_price'] = array(ChoiceAI_Searchcore_Helper_Constants::FIELD_NAME => "final_price",
145
+ ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE => ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_NUMBER);
146
+ $fields['type_id'] = array(ChoiceAI_Searchcore_Helper_Constants::FIELD_NAME => "type_id",
147
+ ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE => ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_STRING);
148
+ } else {
149
+ $fields[] = array(ChoiceAI_Searchcore_Helper_Constants::FIELD_NAME => "final_price",
150
+ ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE => ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_NUMBER);
151
+ $fields[] = array(ChoiceAI_Searchcore_Helper_Constants::FIELD_NAME => "type_id",
152
+ ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE => ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_STRING);
153
+ }
154
+ return $fields;
155
+ }
156
+
157
+ private function getFieldMapping($fields)
158
+ {
159
+ $fieldMapping = array();
160
+ foreach ($fields as $field) {
161
+ $fieldMapping[$field->getFieldName()] = $field;
162
+ }
163
+ return $fieldMapping;
164
+ }
165
+
166
+ /**
167
+ * @param $fields
168
+ * @return array
169
+ */
170
+ private function validate($fields)
171
+ {
172
+ $errors = array();
173
+ if (!is_array($fields)) {
174
+ $errors["message"] = "Expecting theInput data should be an array, Given " . gettype($fields);
175
+ return $errors;
176
+ }
177
+ $existingAttributes = $this->getAllAttributes(true);
178
+ $featureFields = Mage::getModel('choiceai_searchcore/field')->getFeaturedFields();
179
+ foreach ($fields as $field) {
180
+ if (!array_key_exists(ChoiceAI_Searchcore_Model_Field::field_name, $field)) {
181
+ $errors["extra"] = "Not Present for all the fields";
182
+ continue;
183
+ } else if (is_null($field[ChoiceAI_Searchcore_Model_Field::field_name]) ||
184
+ $field[ChoiceAI_Searchcore_Model_Field::field_name] == ""
185
+ ) {
186
+ $errors["extra"] = "field Name is empty for some fields";
187
+ continue;
188
+ }
189
+ if (!array_key_exists(ChoiceAI_Searchcore_Model_Field::datatype, $field)) {
190
+ $errors[$field[ChoiceAI_Searchcore_Model_Field::field_name]] = "Not Present for all the fields";
191
+ } else if (!in_array($field[ChoiceAI_Searchcore_Model_Field::datatype], ChoiceAI_Searchcore_Model_Field::$data_types)) {
192
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR, 'Invalid feature field ' .
193
+ $field[ChoiceAI_Searchcore_Model_Field::datatype]);
194
+ $errors[$field[ChoiceAI_Searchcore_Model_Field::field_name]] = "Invalid datatype specified";
195
+ }
196
+
197
+ if (array_key_exists($field[ChoiceAI_Searchcore_Model_Field::field_name], $existingAttributes)) {
198
+ if (!Mage::getSingleton('choiceai_searchcore/field')->validateDatatype($field[ChoiceAI_Searchcore_Model_Field::datatype], $existingAttributes[$field[ChoiceAI_Searchcore_Model_Field::field_name]][ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE])) {
199
+ $errors[$field[ChoiceAI_Searchcore_Model_Field::field_name]] = "Field cannot be mapped to " . $field[ChoiceAI_Searchcore_Model_Field::datatype];
200
+ }
201
+ }
202
+
203
+ if (array_key_exists(ChoiceAI_Searchcore_Model_Field::featured_field, $field)) {
204
+ if (!array_key_exists($field[ChoiceAI_Searchcore_Model_Field::featured_field], $featureFields)) {
205
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR, 'Invalid feature field ' .
206
+ $field[ChoiceAI_Searchcore_Model_Field::featured_field]);
207
+ $errors[$field[ChoiceAI_Searchcore_Model_Field::field_name]] = "Invalid feature field specified";
208
+ } else if (!Mage::getSingleton('choiceai_searchcore/field')->validateDatatype($featureFields[$field[ChoiceAI_Searchcore_Model_Field::featured_field]]["datatype"], $existingAttributes[$field[ChoiceAI_Searchcore_Model_Field::field_name]][ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE])) {
209
+ $errors[$field[ChoiceAI_Searchcore_Model_Field::field_name]] = "Field cannot be mapped to " . $field[ChoiceAI_Searchcore_Model_Field::datatype];
210
+ }
211
+ }
212
+ }
213
+ return $errors;
214
+ }
215
+
216
+ public function deleteFields($fields, $website)
217
+ {
218
+ $errors = $this->validate($fields);
219
+ if (sizeof($errors) != 0) {
220
+ return $errors;
221
+ }
222
+ $collection = $this->buildFieldCollection($fields, $website);
223
+ return Mage::getModel("choiceai_searchcore/field")->saveFields($collection);
224
+ }
225
+
226
+ /**
227
+ * @param $fields
228
+ * @param $website
229
+ * @return array
230
+ */
231
+ public function saveFields($fields, $website)
232
+ {
233
+ $errors = $this->validate($fields);
234
+ if (sizeof($errors) != 0) {
235
+ return $errors;
236
+ }
237
+ $collection = $this->buildFieldCollectionToAdd($fields, $website);
238
+ $response = Mage::getModel("choiceai_searchcore/field")->saveFields($collection);
239
+ if (!is_array($response) && $response === true) {
240
+ Mage::getSingleton('choiceai_searchcore/field')->rebuildConfigCache($website);
241
+ $this->triggerUpdateFeatureField($website);
242
+ }
243
+ }
244
+
245
+
246
+ public function triggerUpdateFeatureField(Mage_Core_Model_Website $website)
247
+ {
248
+ Mage::getResourceModel('choiceai_searchcore/config')
249
+ ->setValue($website->getWebsiteId(),
250
+ ChoiceAI_Searchcore_Helper_Constants::NEED_FEATURE_FIELD_UPDATION,
251
+ ChoiceAI_Searchcore_Helper_Constants::NEED_FEATURE_FIELD_UPDATION_TRUE);
252
+ $this->triggerFeedUpload($website);
253
+ }
254
+
255
+ /**
256
+ * Method to trigger feed upload
257
+ * @param Mage_Core_Model_Website $website
258
+ * @return void
259
+ */
260
+ public function triggerFeedUpload(Mage_Core_Model_Website $website)
261
+ {
262
+ Mage::getModel('choiceai_searchcore/api_task_triggerfeedupload')
263
+ ->prepare($website)
264
+ ->process();
265
+ }
266
+
267
+
268
+ private function getFeatureFieldToFieldMapping($fields)
269
+ {
270
+ $featureFieldToFieldMapping = array();
271
+ foreach ($fields as $field) {
272
+ if ($field instanceof ChoiceAI_Searchcore_Model_Field &&
273
+ $field->hasData(ChoiceAI_Searchcore_Model_Field::featured_field) &&
274
+ !is_null($field->getData(ChoiceAI_Searchcore_Model_Field::featured_field))
275
+ ) {
276
+ $featureFieldToFieldMapping[$field[ChoiceAI_Searchcore_Model_Field::featured_field]] = $field;
277
+ }
278
+ }
279
+ return $featureFieldToFieldMapping;
280
+ }
281
+
282
+ private function buildFieldCollection($fields, $website)
283
+ {
284
+ $collection = array();
285
+ $fieldMapping = $this->getFieldMapping($this->getFields($fields, $website));
286
+ foreach ($fields as $field) {
287
+ if (!array_key_exists(ChoiceAI_Searchcore_Model_Field::field_name, $field)) {
288
+ continue;
289
+ }
290
+ if (array_key_exists($field[ChoiceAI_Searchcore_Model_Field::field_name], $fieldMapping)) {
291
+ $collection[]["delete"] = $fieldMapping[$field[ChoiceAI_Searchcore_Model_Field::field_name]];
292
+ }
293
+ }
294
+ return $collection;
295
+ }
296
+
297
+ private function buildFieldCollectionToAdd($fields, $website)
298
+ {
299
+ $collection = array();
300
+ $fieldMapping = $this->getFieldMapping($this->getFields($fields, $website));
301
+ $featureFieldToFieldMapping = $this->getFeatureFieldToFieldMapping($fieldMapping);
302
+
303
+ foreach ($fields as $field) {
304
+ if (!array_key_exists(ChoiceAI_Searchcore_Model_Field::field_name, $field)) {
305
+ continue;
306
+ }
307
+ /*
308
+ All possible test cases
309
+ 1) if field name is present and it was a feature field
310
+ 1.a) if request feature field is equal to selected feature field, dont do anything
311
+ 1.b) if request feature field is not equal to selected feature field, dont do anything
312
+ 1.c) if request field is not a feature field,
313
+ remove the field name entry from the feature field row, save as different row.
314
+
315
+ 2) if field name is present and it was not a feature field
316
+ 2.a) if request field is a feature field,
317
+ remove the field name entry as a normal field and save as feature field
318
+ 2.b) if request field is not a feature field,
319
+ update the existing field
320
+
321
+ 3) if field name not present,
322
+ 3.a) if it has feature field, delete it from db and insert the new field
323
+ 3.b) save as a new field
324
+ */
325
+
326
+ // case 1
327
+ if (array_key_exists($field[ChoiceAI_Searchcore_Model_Field::field_name], $fieldMapping) &&
328
+ $fieldMapping[$field[ChoiceAI_Searchcore_Model_Field::field_name]]->hasData(ChoiceAI_Searchcore_Model_Field::featured_field) &&
329
+ !is_null($fieldMapping[$field[ChoiceAI_Searchcore_Model_Field::field_name]]->getData(ChoiceAI_Searchcore_Model_Field::featured_field))
330
+ ) {
331
+ //case 1 a)
332
+ if (array_key_exists(ChoiceAI_Searchcore_Model_Field::featured_field, $field) &&
333
+ $field[ChoiceAI_Searchcore_Model_Field::featured_field] ==
334
+ $fieldMapping[$field[ChoiceAI_Searchcore_Model_Field::field_name]][ChoiceAI_Searchcore_Model_Field::featured_field]
335
+ ) {
336
+ continue;
337
+ } // case 1 b)
338
+ else if (array_key_exists(ChoiceAI_Searchcore_Model_Field::featured_field, $field)) {
339
+ $collection[]["delete"] = $featureFieldToFieldMapping[$field[ChoiceAI_Searchcore_Model_Field::featured_field]];
340
+ $collection[]["delete"] = $fieldMapping[$field[ChoiceAI_Searchcore_Model_Field::field_name]];
341
+ $fieldModel = Mage::getModel("choiceai_searchcore/field");
342
+ $fieldModel->setFeaturedField($field[ChoiceAI_Searchcore_Model_Field::featured_field]);
343
+ } //case 1 c)
344
+ else {
345
+ $collection[]["delete"] = $fieldMapping[$field[ChoiceAI_Searchcore_Model_Field::field_name]];
346
+ $fieldModel = Mage::getModel("choiceai_searchcore/field");
347
+
348
+ }
349
+ } else if (array_key_exists($field[ChoiceAI_Searchcore_Model_Field::field_name], $fieldMapping)) {
350
+ //case 2 a)
351
+ if (array_key_exists(ChoiceAI_Searchcore_Model_Field::featured_field, $field)) {
352
+ $collection[]["delete"] = $fieldMapping[$field[ChoiceAI_Searchcore_Model_Field::field_name]];
353
+ $fieldModel = Mage::getModel("choiceai_searchcore/field");
354
+ $fieldModel->setFeaturedField($field[ChoiceAI_Searchcore_Model_Field::featured_field]);
355
+ } // case 2 b)
356
+ else {
357
+ $fieldModel = $fieldMapping[$field[ChoiceAI_Searchcore_Model_Field::field_name]];
358
+ }
359
+ } else {
360
+ $fieldModel = Mage::getModel("choiceai_searchcore/field");
361
+ if (array_key_exists(ChoiceAI_Searchcore_Model_Field::featured_field, $field)) {
362
+ $fieldModel->setFeaturedField($field[ChoiceAI_Searchcore_Model_Field::featured_field]);
363
+ // case 3 a)
364
+ if (array_key_exists($field[ChoiceAI_Searchcore_Model_Field::featured_field], $featureFieldToFieldMapping)) {
365
+ $collection[]["delete"] = $featureFieldToFieldMapping[$field[ChoiceAI_Searchcore_Model_Field::featured_field]];
366
+ }
367
+ }
368
+
369
+ }
370
+ $fieldModel->setFieldName($field[ChoiceAI_Searchcore_Model_Field::field_name]);
371
+ $fieldModel->setDatatype($field[ChoiceAI_Searchcore_Model_Field::datatype]);
372
+ $fieldModel->setAutosuggest(0);
373
+ $fieldModel->setWebsiteId($website->getWebsiteId());
374
+ $fieldModel->setDisplayed(1);
375
+ $collection[]["add"] = $fieldModel;
376
+ }
377
+ return $collection;
378
+ }
379
+
380
+ /**
381
+ * Method to getFields, if
382
+ *
383
+ * @param $fields
384
+ * @return mixed
385
+ */
386
+ private function getFields($fields, $website)
387
+ {
388
+ $inField = array();
389
+ foreach ($fields as $field) {
390
+ if ($field[ChoiceAI_Searchcore_Model_Field::field_name] == "") {
391
+ continue;
392
+ }
393
+ $inField[] = "'" . $field[ChoiceAI_Searchcore_Model_Field::field_name] . "'";
394
+ }
395
+ $collection = Mage::getResourceModel("choiceai_searchcore/field_collection");
396
+
397
+ $collection->getSelect()
398
+ ->where('(' . ChoiceAI_Searchcore_Model_Field::field_name . ' in (' . implode(",", $inField) . ')' . " OR " .
399
+ ChoiceAI_Searchcore_Model_Field::featured_field . " IS NOT NULL) AND " .
400
+ ChoiceAI_Searchcore_Model_Field::website_id . " = " . $website->getWebsiteId());
401
+ return $collection->load();
402
+ }
403
+
404
+
405
+ /**
406
+ * Method to update feature fields to choiceai
407
+ *
408
+ * @return bool| array
409
+ */
410
+ public function updateFeatureFields(Mage_Core_Model_Website $website)
411
+ {
412
+ $response = Mage::getModel("choiceai_searchcore/api_task_updatefeaturefields")
413
+ ->prepare($website)
414
+ ->process();
415
+ if (!$response->isSuccess()) {
416
+ Mage::log(Zend_Log::ERR,
417
+ "Update feature fields failed because of theses errors " . json_encode($response->getErrors()));
418
+ return $response->getErrors();
419
+ }
420
+ return true;
421
+ }
422
+
423
+ public function getNumberOfDocsInChoiceAI(Mage_Core_Model_Website $website)
424
+ {
425
+ $response = Mage::getModel('choiceai_searchcore/api_task_feeddetails')
426
+ ->prepare($website)
427
+ ->process();
428
+ if ($response->isSuccess()) {
429
+ $response = $response->getResponse();
430
+ $feedInfo = $response[ChoiceAI_Searchcore_Model_Api_Task_Feeddetails::FEEDINFO];
431
+ return $feedInfo[ChoiceAI_Searchcore_Model_Api_Task_Feeddetails::NUMDOCS];
432
+ }
433
+ return 0;
434
+ }
435
+
436
+ /**
437
+ * @param Mage_Core_Model_Website $website
438
+ * @return void
439
+ */
440
+ public function triggerAutoggestIndexing(Mage_Core_Model_Website $website)
441
+ {
442
+ if (Mage::helper('core')->isModuleEnabled('ChoiceAI_Searchcore') &&
443
+ $this->isConfigTrue($website, ChoiceAI_Searchcore_Helper_Constants::AUTOSUGGEST_STATUS)
444
+ ) {
445
+ //trigger Autosuggest
446
+ $response = Mage::getModel('choiceai_searchcore/api_task_autosuggestindex')
447
+ ->prepare($website)
448
+ ->process();
449
+ }
450
+ }
451
+
452
+ public function getCategoryExclusion(Mage_Core_Model_Website $website)
453
+ {
454
+ $conf = Mage::helper('choiceai_searchcore')->getEngineConfigData(ChoiceAI_Searchcore_Helper_Constants::EXCLUDE_CATEGORY, $website, true);
455
+ $categoryExclusionConf = json_decode($conf[ChoiceAI_Searchcore_Helper_Constants::EXCLUDE_CATEGORY], true);
456
+ if (!is_array($categoryExclusionConf)) {
457
+ return array();
458
+ }
459
+ $categoryToBeExcluded = array();
460
+ foreach ($categoryExclusionConf as $eachExclusion) {
461
+ $categoryToBeExcluded[] = (string)$eachExclusion;
462
+ }
463
+ return $categoryToBeExcluded;
464
+ }
465
+
466
+ public function getConfigData($name)
467
+ {
468
+ return (string)Mage::getConfig()->getNode("default/" . ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_CONFIG_PREFIX . "/" . $name);
469
+ }
470
+ }
471
+
472
+ ?>
app/code/local/ChoiceAI/Searchcore/Helper/Constants.php ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+
9
+ class ChoiceAI_Searchcore_Helper_Constants extends Mage_Core_Helper_Abstract {
10
+
11
+ const SITE_KEY = "site_key";
12
+
13
+ const API_KEY = "api_key";
14
+
15
+ const SECRET_KEY = "secret_key";
16
+
17
+ const USERNAME = "username";
18
+
19
+ const NEED_FEATURE_FIELD_UPDATION = "need_feature_field_updation";
20
+
21
+ const NEED_FEATURE_FIELD_UPDATION_FALSE = '0';
22
+
23
+ const NEED_FEATURE_FIELD_UPDATION_TRUE = '1';
24
+
25
+ const IS_CRON_ENABLED = "cron_enabled";
26
+
27
+ const SUBJECT = 'subject';
28
+
29
+ const CONTENT = 'content';
30
+
31
+ const CC = 'cc';
32
+
33
+ const FILTER = 'filter';
34
+
35
+ const FILTER_RANGE_DELIMITER = "|`";
36
+
37
+ const FEATURE_FIELD_PRICE = 'price';
38
+
39
+ const FEATURE_FIELD_IMAGE_URL = 'imageUrl';
40
+
41
+ const FEATURE_FIELD_PRODUCT_URL = 'productUrl';
42
+
43
+ const FEATURE_FIELD_CATEGORY = 'category';
44
+
45
+ const FEATURE_FIELD_BRAND = 'brand';
46
+
47
+ const FEATURE_FIELD_TITLE = 'title';
48
+
49
+ const AUTOSUGGEST_STATUS = 'autosuggest_status';
50
+
51
+ const AUTOSUGGEST_SKIN = 'autosuggest_skin';
52
+
53
+ const AUTOSUGGEST_TEMPLATE = 'autosuggest_template';
54
+
55
+ const AUTOSUGGEST_MAX_SUGGESTION = 'autosuggest_max_suggestion';
56
+
57
+ const AUTOSUGGEST_TOP_QUERIES_STATUS = 'autosuggest_top_queries_status';
58
+
59
+ const AUTOSUGGEST_KEYWORD_STATUS = 'autosuggest_keyword_status';
60
+
61
+ const AUTOSUGGEST_SEARCH_SCOPE_STATUS = 'autosuggest_search_scope_status';
62
+
63
+ const AUTOSUGGEST_MAX_PRODUCTS = 'autosuggest_max_products';
64
+
65
+ const AUTOSUGGEST_POP_PRODUCT_HEADER = 'autosuggest_pop_product_header';
66
+
67
+ const AUTOSUGGEST_KEYWORD_HEADER = 'autosuggest_keyword_header';
68
+
69
+ const AUTOSUGGEST_TOPQUERY_HEADER = 'autosuggest_topquery_header';
70
+
71
+ const AUTOSUGGEST_SEARCH_SCOPE_HEADER = 'autosuggest_search_scope_header';
72
+
73
+ const AUTOSUGGEST_SHOW_CART = 'autosuggest_show_cart';
74
+
75
+ const AUTOSUGGEST_TEMPLATE_1COLUMN = '1column';
76
+
77
+ const AUTOSUGGEST_TEMPLATE_2COLUMN = '2column';
78
+
79
+ const AUTOSUGGEST_TEMPLATE_2COLUMN_LEFT = '2column-left';
80
+
81
+ const AUTOSUGGEST_TEMPLATE_2COLUMN_RIGHT = '2column-right';
82
+
83
+ const AUTOSUGGEST_TEMPLATE_1COLUMN_ADD_TO_CART = '1column-addToCart';
84
+
85
+ const AUTOSUGGEST_SIDECONTENT = 'autosuggest_sidecontent';
86
+
87
+ const AUTOSUGGEST_SIDECONTENT_RIGHT = 'right';
88
+
89
+ const AUTOSUGGEST_SIDECONTENT_LEFT = 'left';
90
+
91
+ const AUTOSUGGEST_INQUERY = "inFields";
92
+
93
+ const AUTOSUGGEST_KEYWORDSUGGESTION = "keywordSuggestions";
94
+
95
+ const AUTOSUGGEST_TOP_QUERY = "topQueries";
96
+
97
+ const AUTOSUGGEST_POP_PRODUCTS = "popularProducts";
98
+
99
+ const AUTOSUGGEST_MAIN_TEMPLATE = 'mainTpl';
100
+
101
+ const AUTOSUGGET_SIDE_TEMPLATE = 'sideTpl';
102
+
103
+ static $AUTOSUGGEST_SIDECONTENTS = array(self::AUTOSUGGEST_SIDECONTENT_RIGHT, self::AUTOSUGGEST_SIDECONTENT_LEFT);
104
+
105
+ static $AUTOSUGGEST_TEMPLATES = array(self::AUTOSUGGEST_TEMPLATE_1COLUMN, self::AUTOSUGGEST_TEMPLATE_2COLUMN);
106
+
107
+ const SEARCH_MOD_STATUS = 'search_mod_status';
108
+
109
+ const SEARCH_MOD_POWER = 'search_mod_power';
110
+
111
+ const SEARCH_HOSTED_STATUS = 'search_hosted_status';
112
+
113
+ const SEARCH_HOSTED_INT_STATUS = 'search_hosted_int_status';
114
+
115
+ const SEARCH_HOSTED_INT_COMPLETE = 'complete';
116
+
117
+ const SEARCH_HOSTED_INT_PROCESSING = 'processing';
118
+
119
+ const SEARCH_HOSTED_REDIRECT_URL = 'search_hosted_redirect_url';
120
+
121
+ const HOSTED_SEARCH_STATUS = 'hosted_search_status';
122
+
123
+ const CHOICEAI_CONFIG_PREFIX = 'choiceai/general';
124
+
125
+ const CONFIG_SEPARATOR = '/';
126
+
127
+ const SEARCH_POWER_LABEL = 'search';
128
+
129
+ const NAVIGATION_POWER_LABEL = 'navigation';
130
+
131
+ const ALL_POWER_LABEL = 'all';
132
+
133
+ const TRUE = "true";
134
+
135
+ const FALSE = "false";
136
+
137
+ const FIELD_NAME = 'field_name';
138
+
139
+ const FIELD_TYPE = 'field_type';
140
+
141
+ const FIELD_TYPE_STRING = 'string';
142
+
143
+ const FIELD_TYPE_IMAGE = 'image';
144
+
145
+ const FIELD_TYPE_NUMBER = 'number';
146
+
147
+ const FIELD_TYPE_DATE = 'date';
148
+
149
+ const CHOICEAI_DATATYPE_TEXT = "text";
150
+
151
+ const CHOICEAI_DATATYPE_LONGTEXT = "longText";
152
+
153
+ const CHOICEAI_DATATYPE_LINK = "link";
154
+
155
+ const CHOICEAI_DATATYPE_NUMBER = "number";
156
+
157
+ const CHOICEAI_DATATYPE_DECIMAL = "decimal";
158
+
159
+ const CHOICEAI_DATATYPE_DATE = "date";
160
+
161
+ const CHOICEAI_DATATYPE_BOOL = "bool";
162
+
163
+ const CHOICEAI_DATATYPE_SKU = "sku";
164
+
165
+ const FIELD_CONF = 'field_conf';
166
+
167
+ const INCLUDE_OUT_OF_STOCK = 'include_out_of_stock';
168
+
169
+ const INCLUDE_CHILD_PRODUCT = 'include_child_product';
170
+
171
+ const INCLUDE_ENABLED_CHILD_PRODUCT = 'include_only_enabled_child_product';
172
+
173
+ const INCLUDE_OUT_OF_STOCK_CHILD_PRODUCT = 'include_out_of_stock_child_product';
174
+
175
+ const INCLUDE_OUT_OF_STOCK_FROM_NON_CACHE = "include_out_of_stock_from_non_cache";
176
+
177
+ const INCLUDE_TAXONOMY_NODES = "include_taxonomy_nodes";
178
+
179
+ const INCLUDE_TAXONOMY_MAPPING = "include_taxonomy_mapping";
180
+
181
+ const FEED_STATUS_UPLOADING = 'UPLOADING';
182
+
183
+ const FEED_STATUS_UPLOADED_SUCCESSFULLY = 'UPLOADED SUCCESSFUL';
184
+
185
+ const FEED_STATUS_UPLOADED_FAILED = 'FAILED';
186
+
187
+ const EXCLUDE_CATEGORY = 'exclude_category';
188
+
189
+ const AUTH_TOKEN = 'auth_token';
190
+
191
+ const AUTH_REQUEST_PARAM = 'auth';
192
+
193
+ const LAST_UPLOAD_TIME = 'lastUpload';
194
+
195
+ }
app/code/local/ChoiceAI/Searchcore/Helper/Data.php ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Helper_Data extends Mage_Core_Helper_Abstract {
10
+
11
+ const LOG_FILE = "choiceai_searchcore.log";
12
+
13
+ /**
14
+ * array field which stores the config
15
+ *
16
+ * @var array
17
+ */
18
+ public $engineConfigData = NULL;
19
+
20
+ /**
21
+ * Method to log
22
+ *
23
+ * @param int $level
24
+ * @param string $message
25
+ */
26
+ public function log($level, $message) {
27
+ Mage::log($message, $level, static::LOG_FILE, true);
28
+ }
29
+
30
+ /**
31
+ * Returns search engine config data.
32
+ *
33
+ * @param string $prefix
34
+ * @param mixed $store
35
+ * @return array
36
+ */
37
+ public function getEngineConfigData($prefix = '', Mage_Core_Model_Website $website = null, $original = false)
38
+ {
39
+ if(is_null($website)) {
40
+ $website = Mage::app()->getWebsite();
41
+ }
42
+ $originalConfig = array();
43
+ if($original) {
44
+ $originalConfig = $this->getOriginalValue($prefix, $website);
45
+ }
46
+ if(is_null($this->engineConfigData)) {
47
+ $this->engineConfigData = Mage::getConfig()
48
+ ->getNode(ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_CONFIG_PREFIX, 'websites',
49
+ (int)$website->getWebsiteId());
50
+ }
51
+
52
+ if (!$this->engineConfigData) {
53
+ return false;
54
+ }
55
+ if ($this->engineConfigData->hasChildren()) {
56
+ $value = array();
57
+ foreach ($this->engineConfigData->asArray() as $k=>$v) {
58
+ if ($prefix != '' && preg_match("#^{$prefix}(.*)#", $k, $matches)) {
59
+ $value[$k] = $v;
60
+ }
61
+ }
62
+ } else {
63
+ $value = (string)$this->engineConfigData;
64
+ }
65
+ return array_merge($value,$originalConfig);
66
+
67
+ }
68
+
69
+ public function getOriginalValue($prefix = '', Mage_Core_Model_Website $website) {
70
+ $configDataCollection = Mage::getModel('core/config_data')
71
+ ->getCollection()
72
+ ->addScopeFilter('websites', (int)$website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_CONFIG_PREFIX)
73
+ ->load();
74
+ $value =array();
75
+ foreach($configDataCollection as $data) {
76
+ $path = $data->getPath();
77
+ if (substr($path, 0, strlen(ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_CONFIG_PREFIX)) == ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_CONFIG_PREFIX) {
78
+ $path = substr($path, strlen(ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_CONFIG_PREFIX) +1);
79
+ }
80
+ if ($prefix != '' && preg_match("#^{$prefix}(.*)#", $path, $matches)) {
81
+ $value[$path] = $data->getValue();
82
+ }
83
+ }
84
+ return $value;
85
+ }
86
+
87
+
88
+ /**
89
+ * Method to validate the config save allowed
90
+ * @param Mage_Core_Model_Website $website
91
+ * @param $configName
92
+ * @param $origData
93
+ * @return string | null
94
+ */
95
+ public function isConfigSaveAllowed(Mage_Core_Model_Website $website, $configName, $value, $origData = true) {
96
+ if(is_null($value) || is_array($value) || is_object($value)){
97
+ return "Invalid Value given";
98
+ }
99
+ if($configName == ChoiceAI_Searchcore_Helper_Constants::SEARCH_HOSTED_STATUS && $value == ChoiceAI_Searchcore_Helper_Constants::TRUE && $this->isConfigTrue($website, ChoiceAI_Searchcore_Helper_Constants::SEARCH_MOD_STATUS, $origData)) {
100
+ return "Module search is on";
101
+ }
102
+ if($configName == ChoiceAI_Searchcore_Helper_Constants::SEARCH_MOD_STATUS && $value == ChoiceAI_Searchcore_Helper_Constants::TRUE && $this->isConfigTrue($website, ChoiceAI_Searchcore_Helper_Constants::SEARCH_HOSTED_STATUS, $origData)) {
103
+ return "Hosted search is on";
104
+ }
105
+
106
+ return null;
107
+ }
108
+
109
+
110
+ /**
111
+ * @param Mage_Core_Model_Website $website
112
+ * @param $data
113
+ * @return void
114
+ */
115
+ public function saveConfig(Mage_Core_Model_Website $website, $data) {
116
+ foreach($data as $key => $value) {
117
+ if(!is_null($this->isConfigSaveAllowed($website, $key, $value, true)))
118
+ continue;
119
+ Mage::getConfig()
120
+ ->saveConfig(ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_CONFIG_PREFIX .
121
+ ChoiceAI_Searchcore_Helper_Constants::CONFIG_SEPARATOR .
122
+ $key,
123
+ (string)$value,
124
+ 'websites',
125
+ (int)$website->getWebsiteId());
126
+ }
127
+ }
128
+
129
+ public function isConfigTrue(Mage_Core_Model_Website $website, $configName, $origData = false) {
130
+ $configData = $this->getEngineConfigData($configName, $website, $origData);
131
+ return array_key_exists($configName, $configData) &&
132
+ $configData[$configName] == ChoiceAI_Searchcore_Helper_Constants::TRUE;
133
+ }
134
+
135
+ /*
136
+ * returns the choiceai site name
137
+ * @return String
138
+ */
139
+ public function getSiteName(){
140
+ $siteKeyLabel = ChoiceAI_Searchcore_Helper_Constants::SITE_KEY;
141
+ $config = $this->getEngineConfigData($siteKeyLabel);
142
+ if(array_key_exists($siteKeyLabel, $config) && $config[$siteKeyLabel] != "")
143
+ return $config[$siteKeyLabel];
144
+ else {
145
+ $siteKey = Mage::getResourceModel('choiceai_searchcore/config')
146
+ ->getValue(Mage::app()->getWebsite()->getWebsiteId(),
147
+ $siteKeyLabel);
148
+ if(isset($siteKey) && $siteKey != ''){
149
+ $this->saveConfig(Mage::app()->getWebsite(),
150
+ array($siteKeyLabel => $siteKey));
151
+ return $siteKey;
152
+ } else {
153
+ if(Mage::getIsDeveloperMode()) {
154
+ Mage::throwException("ChoiceAI site key is empty");
155
+ } else {
156
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR, 'ChoiceAI site key is not set');
157
+ return null;
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ /*
164
+ * returns the choiceai api Key
165
+ * @return String
166
+ */
167
+ public function getApiKey(){
168
+ $apiKeyLabel = ChoiceAI_Searchcore_Helper_Constants::API_KEY;
169
+ $config = $this->getEngineConfigData($apiKeyLabel);
170
+ if(array_key_exists($apiKeyLabel, $config) && $config[$apiKeyLabel] != "")
171
+ return $config[$apiKeyLabel];
172
+ else {
173
+ $apiKey = Mage::getResourceModel('choiceai_searchcore/config')
174
+ ->getValue(Mage::app()->getWebsite()->getWebsiteId(), $apiKeyLabel);
175
+ if(isset($apiKey) && $apiKey != ''){
176
+ $this->saveConfig(Mage::app()->getWebsite(),
177
+ array($apiKeyLabel => $apiKey));
178
+ return $apiKey;
179
+ } else {
180
+ if(Mage::getIsDeveloperMode()) {
181
+ Mage::throwException("ChoiceAI api key is empty");
182
+ } else {
183
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR, 'ChoiceAI Api key is not set');
184
+ return null;
185
+ }
186
+ }
187
+ }
188
+ }
189
+
190
+ /*
191
+ * decides which module should be given more priority based on the version
192
+ * @return boolean
193
+ */
194
+ public function isExecutable() {
195
+ if(Mage::helper('core')->isModuleEnabled('ChoiceAI_Recscore')){
196
+ $otherModuleVersion = floatval(Mage::getConfig()->getModuleConfig("ChoiceAI_Recscore")->version);
197
+ $currentModuleVersion = floatval(Mage::getConfig()->getModuleConfig("ChoiceAI_Searchcore")->version);
198
+ if($this->version_compare($otherModuleVersion, $currentModuleVersion) > 0) {
199
+ return false;
200
+ } else if($this->version_compare($otherModuleVersion, $currentModuleVersion) == 0) {
201
+ return false;
202
+ }
203
+
204
+ }
205
+ return true;
206
+ }
207
+
208
+ //Compare two sets of versions, where major/minor/etc. releases are separated by dots.
209
+ //Returns 0 if both are equal, 1 if A > B, and -1 if B < A.
210
+ public function version_compare($a, $b)
211
+ {
212
+ $a = explode(".", rtrim($a, ".0")); //Split version into pieces and remove trailing .0
213
+ $b = explode(".", rtrim($b, ".0")); //Split version into pieces and remove trailing .0
214
+ foreach ($a as $depth => $aVal)
215
+ { //Iterate over each piece of A
216
+ if (isset($b[$depth]))
217
+ { //If B matches A to this depth, compare the values
218
+ if ($aVal > $b[$depth]) return 1; //Return A > B
219
+ else if ($aVal < $b[$depth]) return -1; //Return B > A
220
+ //An equal result is inconclusive at this point
221
+ }
222
+ else
223
+ { //If B does not match A to this depth, then A comes after B in sort order
224
+ return 1; //so return A > B
225
+ }
226
+ }
227
+ //At this point, we know that to the depth that A and B extend to, they are equivalent.
228
+ //Either the loop ended because A is shorter than B, or both are equal.
229
+ return (count($a) < count($b)) ? -1 : 0;
230
+ }
231
+
232
+ }
233
+ ?>
app/code/local/ChoiceAI/Searchcore/Helper/Feedhelper.php ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+
10
+ class ChoiceAI_Searchcore_Helper_Feedhelper extends ChoiceAI_Searchcore_Helper_Data {
11
+
12
+ var $categoryMap;
13
+
14
+ var $catlevel1List;
15
+
16
+ var $attributeToTypeMap;
17
+
18
+ var $_rootCategoryIds = array();
19
+
20
+ var $_filters;
21
+
22
+ protected function array_match($needle, $haystack) {
23
+ if(!is_array($needle)) {
24
+ return in_array($needle, $haystack);
25
+ }
26
+
27
+ foreach($needle as $eachNeedle) {
28
+ if(in_array($eachNeedle, $haystack)) {
29
+ return true;
30
+ }
31
+ }
32
+ return false;
33
+ }
34
+
35
+ public function getAllFilterableAttributes(Mage_Core_Model_Website $website) {
36
+
37
+ $filterableAttributes = array();
38
+ $stores = $website->getStores();
39
+ $this->tempCategoriesScanned = array();
40
+ foreach($stores as $store) {
41
+ Mage::app()->setCurrentStore($store);
42
+ $categoryId = $store->getRootCategoryId();
43
+ $category = Mage::getModel('catalog/category')->load($categoryId);
44
+ $this->tempCategoriesScanned[] = $categoryId;
45
+ $filterableAttributes = array_merge($filterableAttributes, $this->getFilterableAttributesForCategory($category));
46
+ }
47
+ return array_unique($filterableAttributes);
48
+ }
49
+
50
+ public function getFilterableAttributesForCategory($category) {
51
+ if(array_key_exists($category->getId(), $this->tempCategoriesScanned)) {
52
+ return array();
53
+ } else {
54
+ $this->tempCategoriesScanned[] = $category->getId();
55
+ }
56
+ $filterableAttributes = array();
57
+ $layer = Mage::getModel("catalog/layer");
58
+ $layer->setCurrentCategory($category);
59
+ $attributes = $layer->getFilterableAttributes();
60
+ foreach ($attributes as $attribute) {
61
+ $filterableAttributes[] = $attribute->getAttributeCode();
62
+ }
63
+ $childrenCategoryIds = $category->getAllChildren();
64
+ $childrenCategories = Mage::getModel('catalog/category')->getCollection()->addIdFilter($childrenCategoryIds)->load();
65
+ if(!is_null($childrenCategories)) {
66
+ foreach ($childrenCategories as $childrenCategory) {
67
+ $filterableAttributes = array_merge($filterableAttributes, $this->getFilterableAttributesForCategory($childrenCategory));
68
+ }
69
+ }
70
+ return array_unique($filterableAttributes);
71
+ }
72
+
73
+ /**
74
+ * function to get Category from the category id,
75
+ * This checks it present in the global array 'categoryMap', if it is not there fetches from db
76
+ * So that once it gets one category, it doesn't make db call again for the same category
77
+ *
78
+ * @param string $category_id
79
+ * @return Mage_Catalog_Model_Category
80
+ */
81
+ public function getCategory($category_id = ""){
82
+ if(!isset($this->categoryMap[$category_id])){
83
+ $category = Mage::getModel('catalog/category')->load($category_id);
84
+ $this->categoryMap[$category_id] = $category;
85
+ $parentCategories = $category->getParentCategories();
86
+ foreach($parentCategories as $parentCategory) {
87
+ $parentCategory = Mage::getModel('catalog/category')->load($parentCategory->getId());
88
+ $this->categoryMap[$parentCategory->getId()] = $parentCategory;
89
+ }
90
+ return $this->categoryMap[$category_id];
91
+ }
92
+ return $this->categoryMap[$category_id];
93
+ }
94
+
95
+ public function getRootCategoryIds(Mage_Core_Model_Website $website) {
96
+ if(!array_key_exists($website->getWebsiteId(), $this->_rootCategoryIds)) {
97
+ foreach($website->getStores() as $store) {
98
+ $this->_rootCategoryIds[$website->getWebsiteId()][] = $store->getRootCategoryId();
99
+ }
100
+ }
101
+ return $this->_rootCategoryIds[$website->getWebsiteId()];
102
+ }
103
+
104
+ public function getCategoryOnLevel($category_ids, $level) {
105
+ if(!is_array($category_ids)) {
106
+ return array();
107
+ }
108
+ $categoryValues = array();
109
+ foreach($category_ids as $category_id) {
110
+ $category = $this->getCategory($category_id);
111
+ $parentIds = $category->getParentIds();
112
+ if(!is_null($category) && $category->getLevel() == $level) {
113
+ $categoryValues = array_merge($categoryValues, array($category->getName()));
114
+ } else if ($category instanceof Mage_Catalog_Model_Category &&
115
+ is_array($parentIds) &&
116
+ (sizeof($parentIds) >0)) {
117
+ $categoryValues = array_merge($categoryValues, $this->getCategoryOnLevel($parentIds, $level));
118
+ }
119
+ }
120
+ return $categoryValues;
121
+ }
122
+
123
+ /**
124
+ * method to get all the attributes
125
+ **/
126
+ public function getAttributeMapping(){
127
+ if(isset($this->attributeToTypeMap)){
128
+ return $this->attributeToTypeMap;
129
+ } else {
130
+ $attributes = Mage::getSingleton('eav/config')
131
+ ->getEntityType(Mage_Catalog_Model_Product::ENTITY)->getAttributeCollection();
132
+ foreach($attributes as $attribute){
133
+ $this->attributeToTypeMap[$attribute->getAttributeCode()] = $attribute->getFrontendInput();
134
+ }
135
+ return $this->attributeToTypeMap;
136
+ }
137
+ }
138
+
139
+ public function isAttributePresent($attributeName) {
140
+ $fieldMap = $this->getAttributeMapping();
141
+ return array_key_exists( $attributeName, $fieldMap);
142
+ }
143
+
144
+ /**
145
+ * method to get field type of the field
146
+ * @param $attributeName
147
+ * @return string
148
+ */
149
+ public function getFieldType($attributeName){
150
+ $fieldMap = $this->getAttributeMapping();
151
+ if(array_key_exists( $attributeName, $fieldMap)){
152
+ return $fieldMap[$attributeName];
153
+ } else {
154
+ return "text";
155
+ }
156
+ }
157
+
158
+ function endsWith($haystack, $needle) {
159
+ // search forward starting from end minus needle length characters
160
+ return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && strpos($haystack, $needle, $temp) !== FALSE);
161
+ }
162
+
163
+ /*
164
+ * function to check whether the field is a multiSelect/select or not,
165
+ * This is optimized method, where it doesn't make a database call to get fieldType
166
+ * where it fetches from the local variable, which holds the information of field to fieldType mapping
167
+ * @param string $attributeName
168
+ * @return bool
169
+ */
170
+ public function isMultiSelect($attributeName = ""){
171
+ if(!$this->excludeMultiSelectList($attributeName)) {
172
+ return false;
173
+ }
174
+ if( $this->isMultiSelectDatatype($attributeName)||
175
+ $attributeName == ChoiceAI_Searchcore_Model_Resource_Field::CATEGORY_IDS ||
176
+ $attributeName == ChoiceAI_Searchcore_Model_Resource_Field::CATEGORY_IDS_NAME ||
177
+ $attributeName == ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_1_NAME ||
178
+ $attributeName == ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_2_NAME ||
179
+ $attributeName == ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_3_NAME ||
180
+ $this->endsWith($attributeName, 'Associated')){
181
+ return true;
182
+ }
183
+ return false;
184
+ }
185
+
186
+ public function excludeMultiSelectList($attributeName = "") {
187
+ if($attributeName == "status" || $attributeName == "visibility" || $attributeName == "entity_id" ){
188
+ return false;
189
+ }
190
+ return true;
191
+ }
192
+
193
+
194
+ public function isMultiSelectDatatype($attributeName = "") {
195
+ if(!$this->excludeMultiSelectList($attributeName)) {
196
+ return false;
197
+ }
198
+
199
+ if($this->getFieldType($attributeName) == "select" ||
200
+ $this->getFieldType($attributeName) == "multiselect") {
201
+ return true;
202
+ }
203
+ return false;
204
+ }
205
+
206
+ public function isImage($attributeName = "") {
207
+ if($this->getFieldType($attributeName) == "media_image") {
208
+ return true;
209
+ }
210
+ return false;
211
+ }
212
+
213
+ /**
214
+ * Get all root categories used by all stores.
215
+ * Note that root categories defined but not used, are not included.
216
+ *
217
+ * @return Mage_Catalog_Model_Category[]
218
+ */
219
+ public function getAllRootCategories()
220
+ {
221
+ $categories = array();
222
+
223
+ /** @var $stores Mage_Searchcore_Model_Store[] */
224
+ $stores = Mage::app()->getStores();
225
+
226
+ foreach ($stores as $store) {
227
+ $id = $store->getRootCategoryId();
228
+ if (!isset($categories[$id])) {
229
+ $categories[$id] = Mage::getModel('catalog/category')->load($id);
230
+ }
231
+ }
232
+
233
+ return $categories;
234
+ }
235
+
236
+ public function getUniqueId($product, $item=null) {
237
+ $type= null;
238
+ if($product->hasData('type_id')) {
239
+ $type = $product->getData('type_id');
240
+ }
241
+
242
+ switch($type){
243
+ case 'configurable':
244
+ $productId = $product->getData('entity_id');
245
+ break;
246
+ case 'grouped':
247
+ $productId = $product->getData('entity_id');
248
+ break;
249
+ case 'bundle':
250
+ $productId = $product->getData('entity_id');
251
+ break;
252
+ case 'simple':
253
+ if ($item != null && $item instanceof Mage_Sales_Model_Order) {
254
+ if($item->getParentItem() != null) {
255
+ $productId = $item->getParentItem()->getProductId();
256
+ return $productId;
257
+ }
258
+ }
259
+ $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId());
260
+ if(!isset($parentIds) || sizeof($parentIds) == 0) {
261
+ $parentIds = Mage::getModel('catalog/product_type_grouped')->getParentIdsByChild($product->getId());
262
+ if(isset($parentIds) && sizeof($parentIds) > 0) {
263
+ return $parentIds[0];
264
+ }
265
+ } else {
266
+ return $parentIds[0];
267
+ }
268
+ $productId = $product->getData('entity_id');
269
+ break;
270
+ default:
271
+ $productId = $product->getData('entity_id');
272
+ }
273
+ return $productId;
274
+ }
275
+
276
+ /**
277
+ * Method to get the filters that need to be excluded in the website
278
+ * @param Mage_Core_Model_Website $website
279
+ * @return array
280
+ */
281
+ public function getFilters(Mage_Core_Model_Website $website) {
282
+ if(!isset($this->_filters)) {
283
+ $this->_filters = Mage::getResourceModel('choiceai_searchcore/config')->getFilters($website);
284
+ }
285
+ return $this->_filters;
286
+ }
287
+
288
+ }
app/code/local/ChoiceAI/Searchcore/Model/Api/Request.php ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class to make the request to the ChoiceAI api
5
+ *
6
+ * @category ChoiceAI
7
+ * @package ChoiceAI_Searchcore
8
+ * @copyright Copyright (c) MineWhat
9
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
10
+ */
11
+ class ChoiceAI_Searchcore_Model_Api_Request extends Varien_Object {
12
+
13
+ /**
14
+ * end url where the request is firing
15
+ * @var
16
+ */
17
+ protected $url = "";
18
+
19
+ /**
20
+ * http method
21
+ * @var
22
+ */
23
+ protected $method = Zend_Http_Client::GET;
24
+
25
+ /*
26
+ * Boolean to check whether the data should be sent as raw data or not
27
+ */
28
+ protected $rawData = false;
29
+
30
+ /**
31
+ * http response type
32
+ * @var
33
+ */
34
+ protected $response = "";
35
+
36
+ /**
37
+ * headers needed to sent
38
+ * @var
39
+ */
40
+ protected $headers = array();
41
+
42
+ protected $jsonResponse = true;
43
+
44
+ /**
45
+ * Connection timeout to the api calls made to choiceai
46
+ */
47
+ protected $timeout = 30;
48
+
49
+ public function isJsonResponse() {
50
+ return $this->jsonResponse;
51
+ }
52
+
53
+ public function setJsonResponse($value) {
54
+ if(is_bool($value) && $value == false) {
55
+ $this->jsonResponse = false;
56
+ }
57
+ return $this;
58
+ }
59
+
60
+ public function getHeaders() {
61
+ return $this->headers;
62
+ }
63
+
64
+ public function setHeaders(array $headers) {
65
+ $this->headers = $headers;
66
+ return $this;
67
+ }
68
+
69
+ public function getTimeout() {
70
+ return $this->timeout;
71
+ }
72
+
73
+ public function setTimeout($timeout) {
74
+ if(is_int($timeout) && $timeout >= 0) {
75
+ $this->timeout = $timeout;
76
+ }
77
+ return $this;
78
+ }
79
+
80
+ public function setHeader(string $header,string $value) {
81
+ $this->headers[$header] = $value;
82
+ return $this;
83
+ }
84
+
85
+ /**
86
+ * Method to get the url
87
+ *
88
+ * @return mixed
89
+ */
90
+ protected function getUrl() {
91
+ return $this->url;
92
+ }
93
+
94
+ /**
95
+ * setter method to set url variable
96
+ *
97
+ * @param $url
98
+ * @return $this
99
+ */
100
+ public function setUrl($url) {
101
+ $this->url = $url;
102
+ return $this;
103
+ }
104
+
105
+ /**
106
+ * Method to get the method
107
+ *
108
+ * @return mixed
109
+ */
110
+ protected function getMethod() {
111
+ return $this->method;
112
+ }
113
+
114
+ /**
115
+ * setter method to set method variable
116
+ *
117
+ * @param $method
118
+ * @return void
119
+ */
120
+ public function setMethod($method) {
121
+ $this->method = $method;
122
+ return $this;
123
+ }
124
+
125
+ /**
126
+ * Method to check whether parameters to be sent as raw parameter
127
+ *
128
+ * @return bool
129
+ */
130
+ protected function isRawData() {
131
+ return $this->rawData;
132
+ }
133
+
134
+ /**
135
+ * setter method to set rawdata variable
136
+ *
137
+ * @param bool $rawData
138
+ * @return $this
139
+ */
140
+ public function setRawData($rawData= true) {
141
+ $this->rawData = $rawData;
142
+ return $this;
143
+ }
144
+
145
+
146
+ /**
147
+ * return Zend Rest Client
148
+ *
149
+ * @return Zend_Http_Client
150
+ */
151
+ protected function getRestClient(){
152
+
153
+ $request = new Zend_Http_Client();
154
+ $request->setUri($this->getUrl())
155
+ ->setHeaders(array("Accept" => "application/json") + $this->getHeaders())
156
+ ->setMethod($this->getMethod())
157
+ ->setConfig(
158
+ array(
159
+ 'timeout' => $this->getTimeout()
160
+ )
161
+ );
162
+ if($this->isRawData()) {
163
+ $params = json_encode($this->getData());
164
+ $request->setRawData($params, 'application/json');
165
+ } else if($this->getMethod() == Zend_Http_Client::GET) {
166
+ $request->setParameterGet($this->getData());
167
+ } else {
168
+ $request->setParameterPost($this->getData());
169
+ }
170
+ return $request;
171
+ }
172
+
173
+
174
+ /**
175
+ * Method which will make the api call
176
+ *
177
+ * @return false|ChoiceAI_Searchcore_Model_Api_Response
178
+ */
179
+ public function execute(){
180
+ try {
181
+ $request = $this->getRestClient();
182
+ $raw_response = $request->request();
183
+ } catch (Zend_Http_Client_Exception $e) {
184
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR,
185
+ sprintf($this->getUrl() ." failed because HTTP error: %s", $e->getMessage()));
186
+ return Mage::getModel('choiceai_searchcore/api_response')
187
+ ->setErrorMessage(ChoiceAI_Searchcore_Model_Api_Response::SERVER_ERR);
188
+ }
189
+ return Mage::getModel("choiceai_searchcore/api_response")
190
+ ->setJsonResponse($this->isJsonResponse())
191
+ ->setResponse($raw_response, $this->getUrl());
192
+ }
193
+
194
+ /**
195
+ * Method to return string
196
+ *
197
+ * @return string
198
+ */
199
+ public function __toString() {
200
+
201
+ $parameters = $this->getData();
202
+ if (count($parameters) > 0) {
203
+ $parameters_as_string = json_encode($parameters);
204
+ }
205
+ return "Request to url " . $this->getUrl() . " with method " . $this->getMethod()
206
+ . (count($parameters) > 0?(" with parameters " . $parameters_as_string):"");
207
+ }
208
+
209
+
210
+ }
211
+
212
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Api/Response.php ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Api_Response extends Varien_Object {
10
+
11
+ const SERVER_ERR = 'Unable to reach choiceai server, Please contact support';
12
+
13
+ const SERVER_RESPONSE_ERR = 'Invalid response from ChoiceAI, Please contact support';
14
+
15
+ /**
16
+ * Variable to maintain the response successful or not
17
+ * @var
18
+ */
19
+ protected $success;
20
+
21
+ /**
22
+ * Variable to maintain the response successful or not
23
+ * @var
24
+ */
25
+ protected $errors = array();
26
+
27
+ protected $jsonResponse = true;
28
+
29
+ /**
30
+ * Variable to store the response from the api
31
+ * @var
32
+ */
33
+ protected $response;
34
+
35
+ public function isJsonResponse() {
36
+
37
+ return $this->jsonResponse;
38
+ }
39
+
40
+ public function setJsonResponse($value) {
41
+ if(is_bool($value) && $value == false) {
42
+ $this->jsonResponse = false;
43
+ }
44
+ return $this;
45
+ }
46
+
47
+ public function _construct() {
48
+ $this->success = false;
49
+ $this->message = "Empty response";
50
+ $this->response = array();
51
+ }
52
+
53
+ public function setSuccess($success) {
54
+ if(is_bool($success)) {
55
+ $this->success = $success;
56
+ }
57
+ return $this;
58
+ }
59
+
60
+ /**
61
+ * Method to check exact error message
62
+ *
63
+ * @return bool
64
+ */
65
+ public function isSuccess() {
66
+ return $this->success;
67
+ }
68
+
69
+ public function setErrors($errors = array()) {
70
+ $this->errors = $errors;
71
+ return $this;
72
+ }
73
+
74
+ public function getErrors() {
75
+ return $this->errors;
76
+ }
77
+
78
+ public function setErrorMessage($message) {
79
+ $this->errors['message'] = $message;
80
+ return $this;
81
+ }
82
+
83
+ public function setError(string $key, string $value) {
84
+ $this->errors[$key] = $value;
85
+ return $this;
86
+ }
87
+
88
+ /**
89
+ * Method to get Message
90
+ *
91
+ * @return string
92
+ */
93
+ public function getMessage() {
94
+ if(array_key_exists('message', $this->errors)) {
95
+ return $this->errors['message'];
96
+ }
97
+ return null;
98
+ }
99
+
100
+ /**
101
+ * Method to set the message
102
+ *
103
+ * @param $message
104
+ * @return $this
105
+ */
106
+ public function setMessage($message) {
107
+ $this->errors['message'] = $message;
108
+ return $this;
109
+ }
110
+
111
+ /**
112
+ * Method to return the response
113
+ *
114
+ * @return array
115
+ */
116
+ public function getResponse() {
117
+ return $this->response;
118
+ }
119
+
120
+ /**
121
+ * Method to set the response
122
+ *
123
+ * @param Zend_Http_Response $response
124
+ * @param $url
125
+ * @return $this
126
+ */
127
+ public function setResponse(Zend_Http_Response $response, $url) {
128
+ if($response->isSuccessful()) {
129
+ $this->success = true;
130
+ $this->setMessage("success");
131
+ $body = $response->getBody();
132
+ if(!$this->isJsonResponse()) {
133
+ #Mage::helper('choiceai_searchcore')->log(Zend_Log::DEBUG, "response from the " . $url . " is successful");
134
+ $this->setData("body", $body);
135
+ return $this;
136
+ }
137
+ $this->response = json_decode($body, true);
138
+ #Mage::helper('choiceai_searchcore')->log(Zend_Log::DEBUG, "response from the " . $url . " is " . $body);
139
+ if($this->response == false || !is_array($this->response) || sizeof($this->response) == 0) {
140
+ $this->success = false;
141
+ $this->setMessage("Invalid Authorization credentials");
142
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR, $url . " api failed cos ". $this->getMessage());
143
+ return $this;
144
+ }
145
+ } else {
146
+
147
+ $this->success = false;
148
+ switch ($response->getStatus()) {
149
+ case 500:
150
+ $message = "ChoiceAI API server error, Please contact support \n" . $response->getBody();
151
+ $this->setMessage("ChoiceAI API server error, Please contact support \n");
152
+ break;
153
+ default:
154
+ $message = "ChoiceAI Unexpected error, Please contact support";
155
+ $this->setMessage($message);
156
+ }
157
+ Mage::helper('choiceai_searchcore')
158
+ ->log(Zend_Log::ERR, $url . " api failed cos ". $response->getStatus() . ":" . $message);
159
+ }
160
+ return $this;
161
+ }
162
+
163
+
164
+ }
165
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Api/Task.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ abstract class ChoiceAI_Searchcore_Model_Api_Task extends Varien_Object {
10
+
11
+ static $PLATFORM_API_BASE_URL = "https://accounts.choiceaiapi.com/admin/";
12
+
13
+ static $RECOMMENDATION_SETTINGS_URL = "https://starwreck.choiceai.com/";
14
+
15
+ static $TRACKER_URL = "https://tracker.choiceaiapi.com/";
16
+
17
+ const TIMEOUT = 30;
18
+
19
+ static $url = "";
20
+
21
+ const method = Zend_Http_Client::GET;
22
+
23
+ protected $preparationSuccessful;
24
+
25
+ protected $errors;
26
+
27
+ protected $headers = array();
28
+
29
+ protected $isRawData = false;
30
+
31
+ const jsonResponse = true;
32
+
33
+ public function __construct() {
34
+ $this->preparationSuccessful = false;
35
+ $this->errors = array();
36
+ static::$PLATFORM_API_BASE_URL = Mage::helper('choiceai_searchcore/confighelper')->getConfigData('platform_url');
37
+ static::$RECOMMENDATION_SETTINGS_URL = Mage::helper('choiceai_searchcore/confighelper')->getConfigData('service_url');
38
+ static::$TRACKER_URL = Mage::helper('choiceai_searchcore/confighelper')->getConfigData('tracker_url');
39
+ }
40
+
41
+ /**
42
+ * Method to check whether parameters to be sent as raw parameter
43
+ *
44
+ * @return bool
45
+ */
46
+ protected function isRawData() {
47
+ return $this->isRawData;
48
+ }
49
+
50
+ abstract public function prepare(Mage_Core_Model_Website $website);
51
+
52
+ abstract protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response);
53
+
54
+ /**
55
+ * Method which will make the api call
56
+ *
57
+ * @return false|ChoiceAI_Searchcore_Model_Api_Response
58
+ */
59
+ public function process() {
60
+ if(!$this->preparationSuccessful) {
61
+ Mage::helper("choiceai_searchcore")
62
+ ->log(Zend_Log::ERR,
63
+ sizeof($this->errors == 0)?"prepare method not called":json_encode($this->errors));
64
+ return Mage::getModel("choiceai_searchcore/api_response")
65
+ ->setErrors(sizeof($this->errors) == 0?array("message" => "prepare method not called"):$this->errors);
66
+ }
67
+ $request = Mage::getModel("choiceai_searchcore/api_request")
68
+ ->setUrl(static::$url)
69
+ ->setMethod(static::method)
70
+ ->setHeaders($this->headers)
71
+ ->setTimeout(static::TIMEOUT)
72
+ ->setJsonResponse(static::jsonResponse);
73
+ if($this->isRawData()) {
74
+ $request->setRawData(true);
75
+ }
76
+ if($this->getData()) {
77
+ $request->addData($this->getData());
78
+ }
79
+
80
+ return $this->postProcess($request->execute());
81
+ }
82
+
83
+ }
84
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Analyticsimpression.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Searchcore_Model_Api_Task_Analyticsimpression extends ChoiceAI_Searchcore_Model_Api_Task
9
+ {
10
+
11
+ const method = Zend_Http_Client::GET;
12
+
13
+ public function prepare(Mage_Core_Model_Website $website) {
14
+ $this->preparationSuccessful = true;
15
+ $this->prepareUrl($website);
16
+ $this->prepareHeaders($website);
17
+ return $this;
18
+ }
19
+
20
+ protected function prepareUrl(Mage_Core_Model_Website $website) {
21
+ $siteKey = Mage::getResourceModel("choiceai_searchcore/config")
22
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SITE_KEY);
23
+ if(is_null($siteKey)) {
24
+ $this->preparationSuccessful = false;
25
+ $this->errors["message"] = "Site key not set";
26
+ return;
27
+ }
28
+
29
+ static::$url = static::$RECOMMENDATION_SETTINGS_URL . "dashboard/analytics/integrationDetails/" . $siteKey;
30
+ }
31
+
32
+ protected function prepareHeaders(Mage_Core_Model_Website $website) {
33
+ $username = Mage::getResourceModel("choiceai_searchcore/config")
34
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::USERNAME);
35
+ if(is_null($username)) {
36
+ $this->preparationSuccessful = false;
37
+ $this->errors["message"] = "Secret key not set";
38
+ return;
39
+ }
40
+
41
+ $this->headers["authorization"] = "Basic " . base64_encode($username . ':$uauth');
42
+ }
43
+
44
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
45
+ return $response;
46
+ }
47
+
48
+ }
49
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Autosuggestindex.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Api_Task_Autosuggestindex extends ChoiceAI_Searchcore_Model_Api_Task {
10
+
11
+ const method = Zend_Http_Client::POST;
12
+
13
+ const STATUS = 'status';
14
+
15
+ const MESSAGE = 'message';
16
+
17
+ public function prepare(Mage_Core_Model_Website $website) {
18
+ $this->preparationSuccessful = true;
19
+ $this->prepareUrl($website);
20
+ $this->prepareHeaders($website);
21
+ return $this;
22
+ }
23
+
24
+ protected function prepareUrl(Mage_Core_Model_Website $website) {
25
+ $siteKey = Mage::getResourceModel("choiceai_searchcore/config")
26
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SITE_KEY);
27
+ if(is_null($siteKey)) {
28
+ $this->preparationSuccessful = false;
29
+ $this->errors["message"] = "Site key not set";
30
+ return;
31
+ }
32
+
33
+ static::$url = static::$PLATFORM_API_BASE_URL . $siteKey . "/build-autosuggest";
34
+ }
35
+
36
+ protected function prepareHeaders(Mage_Core_Model_Website $website) {
37
+ $apiKey = Mage::getResourceModel("choiceai_searchcore/config")
38
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::API_KEY);
39
+ $secretKey = Mage::getResourceModel("choiceai_searchcore/config")
40
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SECRET_KEY);
41
+ if(is_null($secretKey) || is_null($apiKey)) {
42
+ $this->preparationSuccessful = false;
43
+ $this->errors["message"] = "Site key not set";
44
+ return;
45
+ }
46
+ $this->headers["Authorization"] = base64_encode($apiKey.":" .$secretKey);
47
+ }
48
+
49
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
50
+ return $response;
51
+ }
52
+ }
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Feeddetails.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Api_Task_Feeddetails extends ChoiceAI_Searchcore_Model_Api_Task {
10
+
11
+ const method = Zend_Http_Client::GET;
12
+
13
+ const STATUS = 'status';
14
+
15
+ const MESSAGE = 'message';
16
+
17
+ const FEEDINFO = 'feedInfo';
18
+
19
+ const NUMDOCS = 'numDocs';
20
+
21
+ public function prepare(Mage_Core_Model_Website $website) {
22
+ $this->preparationSuccessful = true;
23
+ $this->prepareUrl($website);
24
+ $this->prepareHeaders($website);
25
+ return $this;
26
+ }
27
+
28
+ protected function prepareUrl(Mage_Core_Model_Website $website) {
29
+ $siteKey = Mage::getResourceModel("choiceai_searchcore/config")
30
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SITE_KEY);
31
+ if(is_null($siteKey)) {
32
+ $this->preparationSuccessful = false;
33
+ $this->errors["message"] = "Site key not set";
34
+ return;
35
+ }
36
+
37
+ static::$url = static::$PLATFORM_API_BASE_URL . $siteKey . "/feed-info";
38
+ }
39
+
40
+ protected function prepareHeaders(Mage_Core_Model_Website $website) {
41
+ $apiKey = Mage::getResourceModel("choiceai_searchcore/config")
42
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::API_KEY);
43
+ $secretKey = Mage::getResourceModel("choiceai_searchcore/config")
44
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SECRET_KEY);
45
+ if(is_null($secretKey) || is_null($apiKey)) {
46
+ $this->preparationSuccessful = false;
47
+ $this->errors["message"] = "Site key not set";
48
+ return;
49
+ }
50
+ $this->headers["Authorization"] = base64_encode($apiKey.":" .$secretKey);
51
+ }
52
+
53
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
54
+ if(!$response->isSuccess()) {
55
+ return $response;
56
+ }
57
+ $responseObj = $response->getResponse();
58
+ if(!array_key_exists(self::STATUS, $responseObj) || !array_key_exists(self::FEEDINFO, $responseObj)) {
59
+ $response->setSuccess(false);
60
+ $response->setMessage('Invalid response from choiceai');
61
+ return $response;
62
+ }
63
+ if($responseObj[self::STATUS] != 200 || !array_key_exists(self::NUMDOCS, $responseObj[self::FEEDINFO])) {
64
+ $response->setSuccess(false);
65
+ $response->setMessage("status code :" .$responseObj[self::STATUS].",".
66
+ (array_key_exists(self::MESSAGE, $responseObj)?$responseObj[self::MESSAGE]:""));
67
+ return $response;
68
+ }
69
+ return $response;
70
+ }
71
+ }
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Searchimpression.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Api_Task_Searchimpression extends ChoiceAI_Searchcore_Model_Api_Task
10
+ {
11
+
12
+ const method = Zend_Http_Client::GET;
13
+
14
+ public function prepare(Mage_Core_Model_Website $website) {
15
+ $this->preparationSuccessful = true;
16
+ $this->prepareUrl($website);
17
+ $this->prepareHeaders($website);
18
+ return $this;
19
+ }
20
+
21
+ protected function prepareUrl(Mage_Core_Model_Website $website) {
22
+ $siteKey = Mage::getResourceModel("choiceai_searchcore/config")
23
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SITE_KEY);
24
+ if(is_null($siteKey)) {
25
+ $this->preparationSuccessful = false;
26
+ $this->errors["message"] = "Site key not set";
27
+ return;
28
+ }
29
+
30
+ static::$url = static::$RECOMMENDATION_SETTINGS_URL . "dashboard/analytics/hits/" . $siteKey;
31
+ }
32
+
33
+ protected function prepareHeaders(Mage_Core_Model_Website $website) {
34
+ $username = Mage::getResourceModel("choiceai_searchcore/config")
35
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::USERNAME);
36
+ if(is_null($username)) {
37
+ $this->preparationSuccessful = false;
38
+ $this->errors["message"] = "Secret key not set";
39
+ return;
40
+ }
41
+
42
+ $this->headers["authorization"] = "Basic " . base64_encode($username . ':$uauth');
43
+ }
44
+
45
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
46
+ $respObj = $response->getResponse();
47
+ if(array_key_exists("FunnelResponse", $respObj)) {
48
+ if(array_key_exists("Funnels",$respObj["FunnelResponse"])) {
49
+ return $response;
50
+ }
51
+ }
52
+ $response->setSuccess(false);
53
+ $response->setErrorMessage("Unexpected response from ChoiceAI server, Contact Support");
54
+ return $response;
55
+ }
56
+ }
57
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Searchsetup.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Api_Task_Searchsetup extends ChoiceAI_Searchcore_Model_Api_Task {
10
+
11
+ const method = Zend_Http_Client::POST;
12
+
13
+ const STATUS = 'status';
14
+
15
+ const MESSAGE = 'message';
16
+
17
+ public function prepare(Mage_Core_Model_Website $website) {
18
+ $this->preparationSuccessful = true;
19
+ $this->prepareUrl($website);
20
+ $this->prepareHeaders($website);
21
+ return $this;
22
+ }
23
+
24
+ protected function prepareUrl(Mage_Core_Model_Website $website) {
25
+ $siteKey = Mage::getResourceModel("choiceai_searchcore/config")
26
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SITE_KEY);
27
+ if(is_null($siteKey)) {
28
+ $this->preparationSuccessful = false;
29
+ $this->errors["message"] = "Site key not set";
30
+ return;
31
+ }
32
+
33
+ static::$url = static::$PLATFORM_API_BASE_URL . $siteKey . "/complete-search";
34
+ }
35
+
36
+ protected function prepareHeaders(Mage_Core_Model_Website $website) {
37
+ $apiKey = Mage::getResourceModel("choiceai_searchcore/config")
38
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::API_KEY);
39
+ $secretKey = Mage::getResourceModel("choiceai_searchcore/config")
40
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SECRET_KEY);
41
+ if(is_null($secretKey) || is_null($apiKey)) {
42
+ $this->preparationSuccessful = false;
43
+ $this->errors["message"] = "Site key not set";
44
+ return;
45
+ }
46
+ $this->headers["Authorization"] = base64_encode($apiKey.":" .$secretKey);
47
+ }
48
+
49
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
50
+ return $response;
51
+ }
52
+ }
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Supportmail.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category ChoiceAI
4
+ * @package ChoiceAI_Searchcore
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Searchcore_Model_Api_Task_Supportmail extends ChoiceAI_Searchcore_Model_Api_Task {
9
+
10
+ const method = Zend_Http_Client::POST;
11
+ protected $isRawData = true;
12
+
13
+
14
+ public function prepare(Mage_Core_Model_Website $website) {
15
+ $this->preparationSuccessful = true;
16
+ $this->prepareUrl($website);
17
+ $this->prepareHeaders($website);
18
+ return $this;
19
+ }
20
+
21
+ protected function prepareUrl(Mage_Core_Model_Website $website) {
22
+ $siteKey = Mage::getResourceModel("choiceai_searchcore/config")
23
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SITE_KEY);
24
+ if(is_null($siteKey)) {
25
+ $this->preparationSuccessful = false;
26
+ $this->errors["message"] = "Site key not set";
27
+ return;
28
+ }
29
+
30
+ static::$url = static::$RECOMMENDATION_SETTINGS_URL . "dashboard/mail/support";
31
+ }
32
+
33
+ protected function prepareHeaders(Mage_Core_Model_Website $website) {
34
+ $username = Mage::getResourceModel("choiceai_searchcore/config")
35
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::USERNAME);
36
+ if(is_null($username)) {
37
+ $this->preparationSuccessful = false;
38
+ $this->errors["message"] = "Secret key not set";
39
+ return;
40
+ }
41
+
42
+ $this->headers["authorization"] = "Basic " . base64_encode($username . ':$uauth');
43
+ }
44
+
45
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
46
+ return $response;
47
+ }
48
+ }
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Trackcart.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Api_Task_Trackcart extends ChoiceAI_Searchcore_Model_Api_Task {
10
+
11
+ const method = Zend_Http_Client::POST;
12
+
13
+ const jsonResponse = false;
14
+
15
+ const TIMEOUT = 5;
16
+
17
+ public function prepare(Mage_Core_Model_Website $website) {
18
+ $this->prepareUrl($website);
19
+ $this->isRawData = true;
20
+ return $this;
21
+ }
22
+
23
+ protected function prepareUrl(Mage_Core_Model_Website $website)
24
+ {
25
+ $siteKey = Mage::getResourceModel("choiceai_searchcore/config")
26
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SITE_KEY);
27
+ if (is_null($siteKey)) {
28
+ $this->errors["message"] = "Site key not set";
29
+ return;
30
+ }
31
+
32
+ $uid = array_key_exists('choiceai_userId', $_COOKIE) ? $_COOKIE['choiceai_userId'] : null;
33
+ if (!isset($uid) || is_null($uid)) {
34
+ $this->errors["message"] = "UID Missing";
35
+ return;
36
+ }
37
+
38
+ static::$url = static::$TRACKER_URL . "v1.0/$siteKey/track/cart/$uid";
39
+ $this->preparationSuccessful = true;
40
+ }
41
+
42
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
43
+ return $response;
44
+ }
45
+ }
46
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Trackorder.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Api_Task_Trackorder extends ChoiceAI_Searchcore_Model_Api_Task {
10
+
11
+ const method = Zend_Http_Client::POST;
12
+
13
+ const jsonResponse = false;
14
+
15
+ const TIMEOUT = 5;
16
+
17
+ public function prepare(Mage_Core_Model_Website $website) {
18
+ $this->prepareUrl($website);
19
+ $this->isRawData = true;
20
+ return $this;
21
+ }
22
+
23
+ protected function prepareUrl(Mage_Core_Model_Website $website)
24
+ {
25
+ $siteKey = Mage::getResourceModel("choiceai_searchcore/config")
26
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SITE_KEY);
27
+ if (is_null($siteKey)) {
28
+ $this->errors["message"] = "Site key not set";
29
+ return;
30
+ }
31
+
32
+ $uid = array_key_exists('choiceai_userId', $_COOKIE) ? $_COOKIE['choiceai_userId'] : null;
33
+ if (!isset($uid) || is_null($uid)) {
34
+ $this->errors["message"] = "UID Missing";
35
+ return;
36
+ }
37
+
38
+ static::$url = static::$TRACKER_URL . "v1.0/$siteKey/track/order/$uid";
39
+ $this->preparationSuccessful = true;
40
+ }
41
+
42
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
43
+ return $response;
44
+ }
45
+ }
46
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Triggerfeedupload.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * class to validate the secret key and site key with choiceai
5
+ *
6
+ * @category ChoiceAI
7
+ * @package ChoiceAI_Searchcore
8
+ * @copyright Copyright (c) MineWhat
9
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
10
+ */
11
+ class ChoiceAI_Searchcore_Model_Api_Task_Triggerfeedupload extends ChoiceAI_Searchcore_Model_Api_Task {
12
+
13
+ const method = Zend_Http_Client::POST;
14
+
15
+ const TIMEOUT = 5;
16
+
17
+ public function prepare(Mage_Core_Model_Website $website) {
18
+ $this->preparationSuccessful = true;
19
+ $this->prepareUrl();
20
+ $this->prepareParams($website);
21
+ return $this;
22
+ }
23
+
24
+ protected function prepareUrl() {
25
+ static::$url = Mage::getBaseUrl()."searchcore/config/productsync";
26
+ return $this;
27
+ }
28
+
29
+ protected function prepareParams(Mage_Core_Model_Website $website) {
30
+ $this->setData("site", $website->getName());
31
+ $this->setData("auth", Mage::getSingleton('choiceai_searchcore/auth')->getAuthKey());
32
+ return $this;
33
+ }
34
+
35
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
36
+ $response->setSuccess(true);
37
+ $response->setErrors(array());
38
+ return $response;
39
+ }
40
+ }
41
+
42
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Updatefeaturefields.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Api_Task_Updatefeaturefields extends ChoiceAI_Searchcore_Model_Api_Task {
10
+
11
+ const method = Zend_Http_Client::POST;
12
+
13
+ const STATUS = 'status';
14
+
15
+ const MESSAGE = 'message';
16
+
17
+ public function prepare(Mage_Core_Model_Website $website) {
18
+ $this->preparationSuccessful = true;
19
+ $this->prepareUrl($website);
20
+ $this->prepareHeaders($website);
21
+ $this->prepareData($website);
22
+ $this->isRawData = true;
23
+ return $this;
24
+ }
25
+
26
+ protected function prepareUrl(Mage_Core_Model_Website $website) {
27
+ $siteKey = Mage::getResourceModel("choiceai_searchcore/config")
28
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SITE_KEY);
29
+ if(is_null($siteKey)) {
30
+ $this->preparationSuccessful = false;
31
+ $this->errors["message"] = "Site key not set";
32
+ return;
33
+ }
34
+
35
+ static::$url = static::$PLATFORM_API_BASE_URL . $siteKey . "/field-mapping";
36
+ }
37
+
38
+ protected function prepareHeaders(Mage_Core_Model_Website $website) {
39
+ $apiKey = Mage::getResourceModel("choiceai_searchcore/config")
40
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::API_KEY);
41
+ $secretKey = Mage::getResourceModel("choiceai_searchcore/config")
42
+ ->getValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Confighelper::SECRET_KEY);
43
+ if(is_null($secretKey) || is_null($apiKey)) {
44
+ $this->preparationSuccessful = false;
45
+ $this->errors["message"] = "Site key not set";
46
+ return;
47
+ }
48
+ $this->headers["Authorization"] = base64_encode($apiKey.":" .$secretKey);
49
+ }
50
+
51
+ protected function prepareData($website) {
52
+ $featureFields = Mage::getResourceModel("choiceai_searchcore/field_collection")->getFeatureFields($website);
53
+ $featureFieldMap = array();
54
+ foreach($featureFields as $field) {
55
+ if($field[ChoiceAI_Searchcore_Model_Field::featured_field] == ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_IMAGE_URL) {
56
+ $featureFieldMap[$field[ChoiceAI_Searchcore_Model_Field::featured_field]] = "choiceai_NA";
57
+ continue;
58
+ }
59
+ $featureFieldMap[$field[ChoiceAI_Searchcore_Model_Field::featured_field]] =
60
+ $field[ChoiceAI_Searchcore_Model_Field::field_name];
61
+ }
62
+ $this->setData("fieldMapping", $featureFieldMap);
63
+ }
64
+
65
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
66
+ if(!$response->isSuccess()) {
67
+ return $response;
68
+ }
69
+ $responseObj = $response->getResponse();
70
+ if(!array_key_exists(self::STATUS, $responseObj)) {
71
+ $response->setSuccess(false);
72
+ $response->setMessage('Invalid response from choiceai');
73
+ return $response;
74
+ }
75
+ if($responseObj[self::STATUS] != 200) {
76
+ $response->setSuccess(false);
77
+ $response->setMessage("status code :" .$responseObj[self::STATUS].",".
78
+ (array_key_exists(self::MESSAGE, $responseObj)?$responseObj[self::MESSAGE]:""));
79
+ return $response;
80
+ }
81
+ return $response;
82
+ }
83
+ }
app/code/local/ChoiceAI/Searchcore/Model/Api/Task/Validatekeys.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * class to validate the secret key and site key with choiceai
5
+ *
6
+ * @category ChoiceAI
7
+ * @package ChoiceAI_Searchcore
8
+ * @copyright Copyright (c) MineWhat
9
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
10
+ */
11
+ class ChoiceAI_Searchcore_Model_Api_Task_Validatekeys extends ChoiceAI_Searchcore_Model_Api_Task {
12
+
13
+ const method = Zend_Http_Client::POST;
14
+
15
+ const SECRET_KEY = "secretKey";
16
+
17
+ const SITE_KEY = "siteKey";
18
+
19
+ const API_KEY = 'apiKey';
20
+
21
+ const USERNAME = 'username';
22
+
23
+ public function prepare(Mage_Core_Model_Website $website) {
24
+ $this->prepareUrl();
25
+ $this->prepareHeaders($website);
26
+ $this->prepareParams();
27
+ return $this;
28
+ }
29
+
30
+ protected function prepareUrl() {
31
+ static::$url = static::$RECOMMENDATION_SETTINGS_URL . "dashboard/authenticateMagento";
32
+ return $this;
33
+ }
34
+
35
+ protected function prepareHeaders() {
36
+ return $this;
37
+ }
38
+
39
+ protected function prepareParams() {
40
+ $params = $this->getData();
41
+ if(!array_key_exists(static::SECRET_KEY, $params)) {
42
+ $this->preparationSuccessful = false;
43
+ $this->errors[ChoiceAI_Searchcore_Helper_Confighelper::SECRET_KEY] = "secret key expected";
44
+ }
45
+ if(!array_key_exists(static::SITE_KEY, $params)) {
46
+ $this->preparationSuccessful = false;
47
+ $this->errors[ChoiceAI_Searchcore_Helper_Confighelper::SITE_KEY] = "site key expected";
48
+ }
49
+ if(sizeof($this->getData()) > 2) {
50
+ $this->preparationSuccessful = false;
51
+ $this->errors["message"] = "Extra Parameters Present";
52
+ }
53
+ if(sizeof($this->errors) == 0) {
54
+ $this->preparationSuccessful = true;
55
+ }
56
+ $this->isRawData = true;
57
+ return $this;
58
+ }
59
+
60
+ protected function postProcess(ChoiceAI_Searchcore_Model_Api_Response $response) {
61
+ if(!$response->isSuccess()) {
62
+ return $response;
63
+ }
64
+ $responseObj = $response->getResponse();
65
+ if(!array_key_exists(self::API_KEY, $responseObj) || !array_key_exists(self::USERNAME, $responseObj)) {
66
+ $response->setSuccess(false);
67
+ $response->setMessage('Invalid Combination, Please Refer Docs');
68
+ }
69
+ return $response;
70
+ }
71
+ }
72
+
73
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Config.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * This class maintains all the configuration w.r.t ChoiceAI with site basis
5
+ *
6
+ * @category ChoiceAI
7
+ * @package ChoiceAI_Searchcore
8
+ * @copyright Copyright (c) MineWhat
9
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
10
+ */
11
+ class ChoiceAI_Searchcore_Model_Config extends Mage_Core_Model_Abstract {
12
+
13
+ const KEY = "choiceai_key";
14
+
15
+ const VALUE = 'value';
16
+
17
+ const WEBSITE_ID = 'website_id';
18
+
19
+ const FEED_LOCK_TIME = 'feed_lock_time';
20
+
21
+ const FEED_LOCK = 'feed_lock';
22
+
23
+ const FEED_LOCK_TRUE = '1';
24
+
25
+ const FEED_LOCK_FALSE = '0';
26
+
27
+ const FEED_STATUS = 'feed_status';
28
+
29
+ const MAX_FEED_LOCK_TIME = 6;
30
+
31
+ const LAST_UPLOAD_TIME = 'lastUpload';
32
+
33
+ const FILTER_DELIMITER = "|`";
34
+
35
+ const FILTER = 'filter';
36
+
37
+ /**
38
+ *
39
+ * @return void
40
+ */
41
+ protected function _construct()
42
+ {
43
+ $this->_init('choiceai_searchcore/config');
44
+ }
45
+ }
46
+
47
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Field.php ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * This class maintains the config of the fields that are needed by choiceai
5
+ *
6
+ * @category ChoiceAI
7
+ * @package ChoiceAI_Searchcore
8
+ * @copyright Copyright (c) MineWhat
9
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
10
+ */
11
+ class ChoiceAI_Searchcore_Model_Field extends Mage_Core_Model_Abstract
12
+ {
13
+
14
+ /**
15
+ * field name column in db
16
+ */
17
+ const field_name = "field_name";
18
+
19
+ /**
20
+ * datatype column name in db
21
+ */
22
+ const datatype = "datatype";
23
+
24
+ /**
25
+ * autosuggest column name in db
26
+ */
27
+ const autosuggest = "autosuggest";
28
+
29
+ /**
30
+ * featured_field column name in db
31
+ */
32
+ const featured_field = "featured_field";
33
+
34
+ /**
35
+ * displayable column name in db
36
+ */
37
+ const dislayable = "displayed";
38
+
39
+ const multivalued = 'multivalued';
40
+
41
+ /**
42
+ * website id column name in db
43
+ */
44
+ const website_id = "website_id";
45
+
46
+ const status = 'status';
47
+
48
+ /**
49
+ * All possible data type values supported choiceai
50
+ * @var array
51
+ */
52
+ public static $data_types = array(ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_TEXT, ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_LONGTEXT,
53
+ ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_LINK, ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_NUMBER,
54
+ ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_DECIMAL, ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_DATE);
55
+
56
+
57
+ public static $displayableFeatureFields = array('title', 'price',
58
+ 'brand', 'color', 'size', 'imageUrl', 'productUrl');
59
+
60
+ public static $featurefields = array();
61
+
62
+ /**
63
+ *
64
+ * @return void
65
+ */
66
+ protected function _construct()
67
+ {
68
+ $this->_init('choiceai_searchcore/field');
69
+ ChoiceAI_Searchcore_Model_Field::$featurefields = $this->getFeaturedFields();
70
+
71
+ }
72
+
73
+
74
+ /**
75
+ * Save fields
76
+ *
77
+ * @return void
78
+ */
79
+ public function saveFields($collection)
80
+ {
81
+ $this->_getResource()->beginTransaction();
82
+ try {
83
+ foreach ($collection as $data) {
84
+ if (sizeof($data) > 0) {
85
+ if (array_key_exists("add", $data)) {
86
+ $data["add"]->save();
87
+ } else if (array_key_exists("delete", $data)) {
88
+ $data["delete"]->delete();
89
+ }
90
+ }
91
+ }
92
+
93
+ $this->_getResource()->commit();
94
+ } catch (Exception $e) {
95
+ $this->_getResource()->rollBack();
96
+ Mage::helper("choiceai_searchcore")->log(Zend_Log::ERR, "Saving fields failed because " . $e->getMessage());
97
+ return array('OTHERS' => $e->getMessage());
98
+ }
99
+ return true;
100
+
101
+ }
102
+
103
+ /*
104
+ * method to get the featured fields
105
+ */
106
+ public function getFeaturedFields()
107
+ {
108
+ $featuredFields = array();
109
+ $featuredFields["uniqueId"] = $this->getField("text", "false", "false");
110
+ $featuredFields["sellingPrice"] = $this->getField("decimal", "false", "false");
111
+ $featuredFields["discount"] = $this->getField("decimal", "false", "false");
112
+ $featuredFields["rating"] = $this->getField("decimal", "false", "false");
113
+ $featuredFields["brandId"] = $this->getField("text", "false", "false");
114
+ $featuredFields[ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_1_NAME] =
115
+ $this->getField("text", "false", "false");
116
+ $featuredFields[ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_2_NAME] =
117
+ $this->getField("text", "false", "false");
118
+ $featuredFields[ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_3_NAME] =
119
+ $this->getField("text", "false", "false");
120
+ $featuredFields[ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_4_NAME] =
121
+ $this->getField("text", "false", "false");
122
+ $featuredFields[ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_1] =
123
+ $this->getField("text", "true", "false");
124
+ $featuredFields[ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_2] =
125
+ $this->getField("text", "true", "false");
126
+ $featuredFields[ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_3] =
127
+ $this->getField("text", "true", "false");
128
+ $featuredFields[ChoiceAI_Searchcore_Model_Resource_Field::CAT_LEVEL_4] =
129
+ $this->getField("text", "true", "false");
130
+ $featuredFields["category"] = $this->getField("text", "true", "true");
131
+ $featuredFields["subCategory"] = $this->getField("text", "true", "true");
132
+ $featuredFields["color"] = $this->getField("text", "true", "false");
133
+ $featuredFields["size"] = $this->getField("text", "true", "false");
134
+ $featuredFields["availability"] = $this->getField("bool", "false", "false");
135
+ $featuredFields["description"] = $this->getField("longText", "false", "false");
136
+ $featuredFields["imageUrl"] = $this->getField("link", "true", "false");
137
+ $featuredFields["productUrl"] = $this->getField("link", "false", "false");
138
+ $featuredFields["brand"] = $this->getField("text", "false", "true");
139
+ $featuredFields["price"] = $this->getField("decimal", "false", "false");
140
+ $featuredFields["title"] = $this->getField("text", "false", "true");
141
+ $featuredFields["gender"] = $this->getField("text", "false", "false");
142
+ $featuredFields["choiceaiVisibility"] = $this->getField("text", "false", "false");
143
+ return $featuredFields;
144
+ }
145
+
146
+ public function getField($dataType, $multiValued, $autosuggest)
147
+ {
148
+ return array(self::status => 1, self::datatype => $dataType,
149
+ self::multivalued => ($multiValued == "true") ? 1 : 0,
150
+ self::autosuggest => ($autosuggest == "true") ? 1 : 0);
151
+
152
+ }
153
+
154
+ public function rebuildConfigCache(Mage_Core_Model_Website $website) {
155
+ $this->setBrandFieldName($website);
156
+ $this->setCategoryFieldName($website);
157
+ $this->setImageUrlFieldName($website);
158
+ $this->setPriceFieldName($website);
159
+ $this->setProductUrlFieldName($website);
160
+ $this->setTitleFieldName($website);
161
+ }
162
+
163
+ public function getPriceFieldName()
164
+ {
165
+ $priceFieldConfig =
166
+ Mage::helper('choiceai_searchcore')->getEngineConfigData(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRICE);
167
+ if (array_key_exists(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRICE, $priceFieldConfig)) {
168
+ return $priceFieldConfig[ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRICE];
169
+ }
170
+ $this->rebuildConfigCache(Mage::app()->getWebsite());
171
+ $priceField = $this->_getResource()->getFieldByFeatureField(Mage::app()->getWebsite()->getWebsiteId(),
172
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRICE);
173
+ return $priceField;
174
+ }
175
+
176
+ public function setPriceFieldName(Mage_Core_Model_Website $website) {
177
+ $priceName = $this->getResource()->getFieldByFeatureField($website->getWebsiteId(),
178
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRICE);
179
+ Mage::helper('choiceai_searchcore')->saveConfig($website,
180
+ array(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRICE => $priceName));
181
+ }
182
+
183
+ public function getImageUrlFieldName()
184
+ {
185
+ $imageUrlFieldName = $this->_getResource()->getFieldByFeatureField(Mage::app()->getWebsite()->getWebsiteId(),
186
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_IMAGE_URL);
187
+ return $imageUrlFieldName;
188
+ }
189
+
190
+ public function setImageUrlFieldName(Mage_Core_Model_Website $website)
191
+ {
192
+ $imageField = $this->getResource()->getFieldByFeatureField($website->getWebsiteId(),
193
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_IMAGE_URL);
194
+ Mage::helper('choiceai_searchcore')->saveConfig($website,
195
+ array(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_IMAGE_URL => $imageField));
196
+ }
197
+
198
+ public function getProductUrlFieldName()
199
+ {
200
+ $fieldConfig =
201
+ Mage::helper('choiceai_searchcore')
202
+ ->getEngineConfigData(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRODUCT_URL);
203
+ if(array_key_exists(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRODUCT_URL, $fieldConfig)) {
204
+ return $fieldConfig[ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRODUCT_URL];
205
+ }
206
+ $this->rebuildConfigCache(Mage::app()->getWebsite());
207
+ $productUrl = $this->_getResource()->getFieldByFeatureField(Mage::app()->getWebsite()->getWebsiteId(),
208
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRODUCT_URL);
209
+ return $productUrl;
210
+
211
+ }
212
+
213
+ public function setProductUrlFieldName(Mage_Core_Model_Website $website)
214
+ {
215
+ $productUrlField = $this->getResource()->getFieldByFeatureField($website->getWebsiteId(),
216
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRODUCT_URL);
217
+ Mage::helper('choiceai_searchcore')->saveConfig($website,
218
+ array(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_PRODUCT_URL => $productUrlField));
219
+ }
220
+
221
+ public function getCategoryFieldName()
222
+ {
223
+ $fieldConfig =
224
+ Mage::helper('choiceai_searchcore')
225
+ ->getEngineConfigData(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_CATEGORY);
226
+ if(array_key_exists(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_CATEGORY, $fieldConfig)) {
227
+ return $fieldConfig[ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_CATEGORY];
228
+ }
229
+ $this->rebuildConfigCache(Mage::app()->getWebsite());
230
+ $categoryField = $this->_getResource()->getFieldByFeatureField(Mage::app()->getWebsite()->getWebsiteId(),
231
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_CATEGORY);
232
+ return $categoryField;
233
+ }
234
+
235
+ public function setCategoryFieldName(Mage_Core_Model_Website $website)
236
+ {
237
+ $categortField = $this->getResource()->getFieldByFeatureField($website->getWebsiteId(),
238
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_CATEGORY);
239
+ Mage::helper('choiceai_searchcore')->saveConfig($website,
240
+ array(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_CATEGORY => $categortField));
241
+ }
242
+
243
+ public function getBrandFieldName()
244
+ {
245
+ $fieldConfig =
246
+ Mage::helper('choiceai_searchcore')
247
+ ->getEngineConfigData(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_BRAND);
248
+ if(array_key_exists(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_BRAND, $fieldConfig)) {
249
+ return $fieldConfig[ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_BRAND];
250
+ }
251
+ $this->rebuildConfigCache(Mage::app()->getWebsite());
252
+ $brandField = $this->_getResource()->getFieldByFeatureField(Mage::app()->getWebsite()->getWebsiteId(),
253
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_BRAND);
254
+ return $brandField;
255
+ }
256
+
257
+ public function setBrandFieldName(Mage_Core_Model_Website $website)
258
+ {
259
+ $brandField = $this->getResource()->getFieldByFeatureField($website->getWebsiteId(),
260
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_BRAND);
261
+ Mage::helper('choiceai_searchcore')->saveConfig($website,
262
+ array(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_BRAND => $brandField));
263
+ }
264
+
265
+ public function getTitleFieldName()
266
+ {
267
+ $fieldConfig =
268
+ Mage::helper('choiceai_searchcore')
269
+ ->getEngineConfigData(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_TITLE);
270
+ if(array_key_exists(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_TITLE, $fieldConfig)) {
271
+ return $fieldConfig[ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_TITLE];
272
+ }
273
+ $this->rebuildConfigCache(Mage::app()->getWebsite());
274
+ $titleField = $this->_getResource()->getFieldByFeatureField(Mage::app()->getWebsite()->getWebsiteId(),
275
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_TITLE);
276
+ return $titleField;
277
+ }
278
+
279
+ public function setTitleFieldName(Mage_Core_Model_Website $website)
280
+ {
281
+ $titleField = $this->getResource()->getFieldByFeatureField($website->getWebsiteId(),
282
+ ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_TITLE);
283
+ Mage::helper('choiceai_searchcore')->saveConfig($website,
284
+ array(ChoiceAI_Searchcore_Helper_Constants::FEATURE_FIELD_TITLE => $titleField));
285
+ }
286
+
287
+ public function getImageFields($website)
288
+ {
289
+ $conf = Mage::helper('choiceai_searchcore')->getEngineConfigData(ChoiceAI_Searchcore_Helper_Constants::FIELD_CONF, $website, true);
290
+ $fieldConf = json_decode($conf[ChoiceAI_Searchcore_Helper_Constants::FIELD_CONF], true);
291
+ if (!is_array($fieldConf)) {
292
+ return array();
293
+ }
294
+ $imageFields = array();
295
+ foreach ($fieldConf as $field => $conf) {
296
+ if (!is_array($conf) || !array_key_exists('image_full', $conf)) {
297
+ continue;
298
+ }
299
+ $imageFields[$field] = Mage::helper('choiceai_searchcore')->isConfigTrue($website, 'image_full') ? true : false;
300
+ }
301
+ return $imageFields;
302
+ }
303
+
304
+ public function getCopyFields($website)
305
+ {
306
+ $conf = Mage::helper('choiceai_searchcore')->getEngineConfigData(ChoiceAI_Searchcore_Helper_Constants::FIELD_CONF, $website, true);
307
+
308
+ $fieldConf = json_decode($conf[ChoiceAI_Searchcore_Helper_Constants::FIELD_CONF], true);
309
+ if (!is_array($fieldConf)) {
310
+ return array();
311
+ }
312
+ $imageFields = array();
313
+ foreach ($fieldConf as $field => $conf) {
314
+ if (!is_array($conf) || !array_key_exists('copy_field', $conf)) {
315
+ continue;
316
+ }
317
+ $imageFields[$field] = $conf['copy_field'];
318
+ }
319
+ return $imageFields;
320
+ }
321
+
322
+ public function validateDatatype($choiceaiDatatype, $magentoDatatype)
323
+ {
324
+ if ($choiceaiDatatype == ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_TEXT || $choiceaiDatatype == ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_LONGTEXT ||
325
+ $choiceaiDatatype == ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_LINK
326
+ ) {
327
+ return true;
328
+ }
329
+ if ($choiceaiDatatype == ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_NUMBER && $magentoDatatype == ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_NUMBER) {
330
+ return true;
331
+ }
332
+ if ($choiceaiDatatype == ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_DECIMAL && $magentoDatatype == ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_NUMBER) {
333
+ return true;
334
+ }
335
+ if ($choiceaiDatatype == ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_DATE && $magentoDatatype == ChoiceAI_Searchcore_Helper_Constants::FIELD_TYPE_DATE) {
336
+ return true;
337
+ }
338
+ return false;
339
+ }
340
+ }
341
+
342
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Observer.php ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Observer {
10
+
11
+ /**
12
+ * Observer method to track the add to cart
13
+ * @return $this
14
+ */
15
+ public function trackAddToCart(Varien_Event_Observer $observer) {
16
+ if(!Mage::helper('choiceai_searchcore')->isExecutable()) {
17
+ return;
18
+ }
19
+ $product = $observer->getEvent()->getProduct();
20
+ if(!$product instanceof Mage_Catalog_Model_Product) {
21
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR, 'CART_TRACKER:product is not a valid type');
22
+ return $this;
23
+ }
24
+ $uniqueId = Mage::helper('choiceai_searchcore/feedhelper')->getUniqueId($product);
25
+ $response = Mage::getModel('choiceai_searchcore/api_task_trackcart')
26
+ ->setData('data', array('pid' => $uniqueId,
27
+ 'visit_type' => 'repeat'))
28
+ ->setData('ip', isset($_SERVER['HTTP_X_FORWARDED_FOR'])?$_SERVER['HTTP_X_FORWARDED_FOR']:$_SERVER['REMOTE_ADDR'])
29
+ ->setData('agent', $_SERVER['HTTP_USER_AGENT'])
30
+ ->prepare(Mage::app()->getWebsite())
31
+ ->process();
32
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::DEBUG, "CART_TRACKER: request with uniqueId ".$uniqueId);
33
+ if(!$response->isSuccess()) {
34
+ Mage::helper('choiceai_searchcore')
35
+ ->log(Zend_Log::ERR, 'CART_TRACKER:request failed because ' .json_encode($response->getErrors()));
36
+ }
37
+ return $this;
38
+ }
39
+
40
+ /**
41
+ * Observer method to track orders
42
+ * @return $this
43
+ */
44
+ public function trackOrder(Varien_Event_Observer $observer) {
45
+ if(!Mage::helper('choiceai_searchcore')->isExecutable()) {
46
+ return;
47
+ }
48
+ $payment = $observer->getEvent()->getPayment();
49
+ /* @var Mage_Sales_Model_Order_Payment */
50
+
51
+ if(!$payment instanceof Mage_Sales_Model_Order_Payment) {
52
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::ERR, 'ORDER_TRACKER:payment is not a valid type');
53
+ return $this;
54
+ }
55
+ $items = $payment->getOrder()->getAllVisibleItems();
56
+
57
+ if(!is_array($items)) {
58
+ return $this;
59
+ }
60
+
61
+ foreach($items as $item) {
62
+ if($item instanceof Mage_Sales_Model_Order) {
63
+ Mage::helper('choiceai_searchcore')
64
+ ->log(Zend_Log::ERR, 'ORDER_TRACKER:request failed because item is of instancetype ' . get_class($item));
65
+ continue;
66
+ }
67
+ $product =$item->getProduct();
68
+ if(!$product instanceof Mage_Catalog_Model_Product) {
69
+ return $this;
70
+ }
71
+ $uniqueId = Mage::helper('choiceai_searchcore/feedhelper')->getUniqueId($product, $item);
72
+ $response = Mage::getModel('choiceai_searchcore/api_task_trackorder')
73
+ ->setData('data',
74
+ array('visit_type' => 'repeat',
75
+ 'pid' => $uniqueId,
76
+ 'qty' => $item->getQtyOrdered(),
77
+ 'price' => $item->getPriceInclTax()))
78
+ ->setData('ip', isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'])
79
+ ->setData('agent', $_SERVER['HTTP_USER_AGENT'])
80
+ ->prepare(Mage::app()->getWebsite())
81
+ ->process();
82
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::DEBUG, "ORDER_TRACKER: request with uniqueId ".$uniqueId);
83
+
84
+ if(!$response->isSuccess()) {
85
+ Mage::helper('choiceai_searchcore')
86
+ ->log(Zend_Log::ERR, 'ORDER_TRACKER:request failed because ' . json_encode($response->getErrors()));
87
+ }
88
+ Mage::getSingleton('choiceai_searchcore/sync')->addProduct($product);
89
+ }
90
+ return $this;
91
+ }
92
+
93
+ /**
94
+ * Method to sync the product catalog through cron
95
+ * @param Varien_Event_Observer $observer
96
+ * @return $this
97
+ */
98
+ public function syncFull($observer)
99
+ {
100
+ if(!Mage::helper('choiceai_searchcore')->isExecutable()) {
101
+ return;
102
+ }
103
+ $websiteCollection = Mage::getModel('core/website')->getCollection()->load();
104
+ if(!$websiteCollection instanceof Varien_Data_Collection) {
105
+ return $this;
106
+ }
107
+ foreach ($websiteCollection as $website) {
108
+ if($website instanceof Mage_Core_Model_Website) {
109
+ return $this;
110
+ }
111
+ Mage::getResourceModel('choiceai_searchcore/config')
112
+ ->setValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Constants::IS_CRON_ENABLED, 1);
113
+ Mage::getSingleton('choiceai_searchcore/feed_feedmanager')->process(true, $website);
114
+ }
115
+ return $this;
116
+ }
117
+
118
+ /*
119
+ * Method to sync the product incremental catalog through cron
120
+ * @param Varien_Event_Observer $observer
121
+ * @return $this
122
+ */
123
+ public function syncIncremental($observer)
124
+ {
125
+ if(!Mage::helper('choiceai_searchcore')->isExecutable()) {
126
+ return;
127
+ }
128
+ $websiteCollection = Mage::getModel('core/website')->getCollection()->load();
129
+ if(!$websiteCollection instanceof Varien_Data_Collection) {
130
+ return $this;
131
+ }
132
+ foreach ($websiteCollection as $website) {
133
+ if($website instanceof Mage_Core_Model_Website) {
134
+ return $this;
135
+ }
136
+ Mage::getResourceModel('choiceai_searchcore/config')
137
+ ->setValue($website->getWebsiteId(), ChoiceAI_Searchcore_Helper_Constants::IS_CRON_ENABLED, 1);
138
+ Mage::getSingleton('choiceai_searchcore/feed_feedmanager')->process(false, $website);
139
+ }
140
+ return $this;
141
+ }
142
+
143
+ /**
144
+ * Method to track deleted product
145
+ * @param Varien_Event_Observer $observer
146
+ * @return void
147
+ */
148
+ public function trackDelete(Varien_Event_Observer $observer) {
149
+ if(!Mage::helper('choiceai_searchcore')->isExecutable()) {
150
+ return $this;
151
+ }
152
+ $product = $observer->getEvent()->getDataObject();
153
+ if(!$product instanceof Mage_Catalog_Model_Product) {
154
+ return $this;
155
+ }
156
+ $parentIds = Mage::getModel('catalog/product_type_grouped')->getParentIdsByChild($product->getId());
157
+ if(!$parentIds)
158
+ $parentIds = Mage::getModel('catalog/product_type_configurable')->getParentIdsByChild($product->getId());
159
+
160
+ if(!is_array($parentIds)) {
161
+ return $this;
162
+ }
163
+
164
+ foreach($parentIds as $parentId) {
165
+ $parentProduct = Mage::getModel('catalog/product')->load($parentId);
166
+ if($parentProduct instanceof Mage_Catalog_Model_Product) {
167
+ return $this;
168
+ }
169
+ Mage::getSingleton('choiceai_searchcore/sync')->addProduct($parentProduct);
170
+ }
171
+ Mage::getSingleton('choiceai_searchcore/sync')->deleteProduct($product);
172
+ return $this;
173
+ }
174
+
175
+ /**
176
+ * Method to track deleted product
177
+ * @param Varien_Event_Observer $observer
178
+ * @return void
179
+ */
180
+
181
+ public function catalogInventorySave(Varien_Event_Observer $observer) {
182
+ if(!Mage::helper('choiceai_searchcore')->isExecutable()) {
183
+ return;
184
+ }
185
+ $_item = $observer->getEvent()->getItem();
186
+ if(!$_item instanceof Mage_Catalog_Order_Item) {
187
+ return $this;
188
+ }
189
+ $product = $_item->getProduct();
190
+ if(!$product instanceof Mage_Catalog_Model_Product) {
191
+ return $this;
192
+ }
193
+ Mage::getSingleton('choiceai_searchcore/sync')->addProduct($product);
194
+ return $this;
195
+ }
196
+
197
+ public function saleOrderCancel(Varien_Event_Observer $observer) {
198
+ return $this;
199
+ }
200
+ }
201
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Resource/Attribute.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category ChoiceAI
4
+ * @package ChoiceAI_Searchcore
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Searchcore_Model_Resource_Attribute {
9
+
10
+ protected $attributeMap = array();
11
+ public function getAttributeValue($attributeCode, $value, $product){
12
+ if(!isset($this->attributeMap[$value])){
13
+ if(!($product instanceof Mage_Catalog_Model_Product) || Mage::getResourceModel('catalog/product')->getAttribute($attributeCode) == null){
14
+ return null;
15
+ }
16
+ $options = Mage::getResourceModel('catalog/product')->getAttribute($attributeCode)
17
+ ->getSource()->getAllOptions();
18
+ foreach($options as $option){
19
+ $this->attributeMap[$option["value"]] = $option["label"];
20
+ }
21
+ }
22
+ return array_key_exists($value, $this->attributeMap)?$this->attributeMap[$value]:null;
23
+ }
24
+
25
+ }
26
+
27
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Resource/Config.php ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Resource_Config extends Mage_Core_Model_Mysql4_Abstract
10
+ {
11
+
12
+ /**
13
+ * ChoiceAI Config table Name
14
+ *
15
+ * @var string
16
+ */
17
+ protected $_choiceaiConfigTable;
18
+
19
+ // date format
20
+ const DATE_FORMAT = 'Y-m-d H:i:s';
21
+
22
+ /**
23
+ * @return void
24
+ */
25
+ protected function _construct()
26
+ {
27
+ $this->_init('choiceai_searchcore/config', 'id');
28
+ $this->_choiceaiConfigTable = $this->getTable('choiceai_searchcore/config');
29
+ }
30
+
31
+ public function getValues($websiteId, $key) {
32
+ if(!isset($key) || is_array($key) ){
33
+ return array();
34
+ }
35
+ $adapter = $this->_getReadAdapter();
36
+ $select = $adapter->select()
37
+ ->from($this->_choiceaiConfigTable, ChoiceAI_Searchcore_Model_Config::VALUE)
38
+ ->where(ChoiceAI_Searchcore_Model_Config::WEBSITE_ID.' = ?', (int)$websiteId)
39
+ ->where(ChoiceAI_Searchcore_Model_Config::KEY.' = ?', $key);
40
+ $rows = $adapter->fetchAll($select);
41
+ $values = array();
42
+ foreach($rows as $row) {
43
+ if(array_key_exists(ChoiceAI_Searchcore_Model_Config::VALUE, $row)) {
44
+ $values[] = $row[ChoiceAI_Searchcore_Model_Config::VALUE];
45
+ }
46
+ }
47
+ return $values;
48
+ }
49
+
50
+ /**
51
+ * @param $website_id
52
+ * @param $key
53
+ * @return null|string
54
+ */
55
+ public function getValue($website_id, $key)
56
+ {
57
+ $adapter = $this->_getReadAdapter();
58
+ if(is_array($key)) {
59
+ $keyValuePair = array();
60
+ foreach ($key as $eachKey) {
61
+ $keyValuePair[$eachKey] = $this->getValue($website_id, $eachKey);
62
+ }
63
+ return $keyValuePair;
64
+ }
65
+ $select = $adapter->select()
66
+ ->from($this->_choiceaiConfigTable, 'value')
67
+ ->where('`'.ChoiceAI_Searchcore_Model_Config::WEBSITE_ID.'` = ?', (int)$website_id)
68
+ ->where('`'.ChoiceAI_Searchcore_Model_Config::KEY.'` = ?', $key);
69
+ $result = $adapter->fetchOne($select);
70
+ if($result === false) {
71
+ return null;
72
+ }
73
+ return $result;
74
+ }
75
+
76
+ /**
77
+ * @param int $website_id
78
+ * @param string $key
79
+ * @param string $value
80
+ * @return void
81
+ */
82
+ public function setValue($website_id, $key, $value = null)
83
+ {
84
+ if(is_array($key)) {
85
+ foreach($key as $eachKey => $eachValue) {
86
+ $this->setValue($website_id, $eachKey, $eachValue);
87
+ }
88
+ return;
89
+ }
90
+ if (!isset($value) || $value == "" || !isset($key) || $key == "") {
91
+ return;
92
+ }
93
+
94
+ $config = Mage::getModel('choiceai_searchcore/config')->getCollection()
95
+ ->addFieldToFilter(ChoiceAI_Searchcore_Model_Config::KEY, $key)
96
+ ->addFieldToFilter(ChoiceAI_Searchcore_Model_Config::WEBSITE_ID, (int)$website_id)
97
+ ->getFirstItem();
98
+
99
+ $config->setWebsiteId($website_id)
100
+ ->setChoiceAIKey($key)
101
+ ->setValue($value)
102
+ ->save();
103
+ }
104
+
105
+ public function updateValues($websiteId, $key, $values = array()) {
106
+ $this->deleteKey($websiteId, $key);
107
+ $this->beginTransaction();
108
+ foreach($values as $eachValue) {
109
+ Mage::getModel('choiceai_searchcore/config')
110
+ ->setWebsiteId($websiteId)
111
+ ->setChoiceAIKey($key)
112
+ ->setValue($eachValue)
113
+ ->save();
114
+ }
115
+ $this->commit();
116
+ }
117
+
118
+ public function deleteKey($websiteId, $key) {
119
+ $write = Mage::getSingleton("core/resource")->getConnection("core_write");
120
+ $query = "DELETE FROM choiceai_recommendation_conf WHERE " . ChoiceAI_Searchcore_Model_Config::KEY . " = :key"
121
+ . " and " . ChoiceAI_Searchcore_Model_Config::WEBSITE_ID . " = :website_id";
122
+ $binds = array(
123
+ ChoiceAI_Searchcore_Model_Config::KEY => $key,
124
+ ChoiceAI_Searchcore_Model_Config::WEBSITE_ID => $websiteId
125
+ );
126
+ $write->query($query, $binds);
127
+
128
+ }
129
+
130
+ public function lockSite($website_id) {
131
+ $this->setValue($website_id, array(
132
+ ChoiceAI_Searchcore_Model_Config::FEED_LOCK => ChoiceAI_Searchcore_Model_Config::FEED_LOCK_TRUE,
133
+ ChoiceAI_Searchcore_Model_Config::FEED_LOCK_TIME => date(self::DATE_FORMAT)));
134
+
135
+ }
136
+
137
+
138
+ public function unLockSite($website_id) {
139
+ $this->setValue($website_id, ChoiceAI_Searchcore_Model_Config::FEED_LOCK,
140
+ ChoiceAI_Searchcore_Model_Config::FEED_LOCK_FALSE);
141
+ }
142
+
143
+ /**
144
+ * Method will check whether there is a feed lock or not
145
+ * @param $website_id
146
+ * @return bool
147
+ */
148
+ public function isLock($website_id) {
149
+ //fetch the values for feedlock, feed lock time from db
150
+ $feedLockDetails = $this->getValue($website_id,
151
+ array(ChoiceAI_Searchcore_Model_Config::FEED_LOCK, ChoiceAI_Searchcore_Model_Config::FEED_LOCK_TIME));
152
+ //fetch feed lock from @var feedLockDetails
153
+ $feedLock = array_key_exists(ChoiceAI_Searchcore_Model_Config::FEED_LOCK, $feedLockDetails)?
154
+ $feedLockDetails[ChoiceAI_Searchcore_Model_Config::FEED_LOCK]:null;
155
+ if(is_null($feedLock) || $feedLock == ChoiceAI_Searchcore_Model_Config::FEED_LOCK_FALSE){
156
+ return false;
157
+ }
158
+ // Ignoring the feed Lock, if the feed has been locked more than $maxFeedLockTime
159
+ if($feedLock == ChoiceAI_Searchcore_Model_Config::FEED_LOCK_TRUE &&
160
+ array_key_exists(ChoiceAI_Searchcore_Model_Config::FEED_LOCK_TIME, $feedLockDetails)) {
161
+ $feedLockTime = $feedLockDetails[ChoiceAI_Searchcore_Model_Config::FEED_LOCK_TIME];
162
+ $date = strtotime($feedLockTime);
163
+ $currentTime = strtotime(date(self::DATE_FORMAT));
164
+ $diff = abs($date - $currentTime);
165
+ $maxFeedLockTime = Mage::getConfig()->getNode('default/choiceai/general/max_feed_lock_feed');
166
+ if(is_null($maxFeedLockTime)) {
167
+ $maxFeedLockTime = ChoiceAI_Searchcore_Model_Config::MAX_FEED_LOCK_TIME;
168
+ }
169
+ if(round($diff / ( 60 * 60 )) > $maxFeedLockTime) {
170
+ return false;
171
+ }
172
+ }
173
+ return true;
174
+ }
175
+
176
+ /**
177
+ * Method to get all the filters
178
+ * @param Mage_Core_Model_Website $website
179
+ * @return array
180
+ */
181
+ public function getFilters(Mage_Core_Model_Website $website) {
182
+ $values = Mage::getResourceModel('choiceai_searchcore/config')->getValues($website->getWebsiteId(),
183
+ ChoiceAI_Searchcore_Model_Config::FILTER);
184
+ $filters = array();
185
+ foreach($values as $value) {
186
+ $explodedValues = explode(ChoiceAI_Searchcore_Model_Config::FILTER_DELIMITER, $value);
187
+ if(sizeof($explodedValues) < 2) {
188
+ continue;
189
+ }
190
+ $filters[$explodedValues[0]] = $explodedValues[1];
191
+ }
192
+ return $filters;
193
+ }
194
+
195
+ public function saveGlobalConfig(Mage_Core_Model_Website $website, $values = array()) {
196
+ foreach($values as $key => $value ) {
197
+ }
198
+ }
199
+
200
+ public function deleteAll($websiteId) {
201
+ $write = Mage::getSingleton("core/resource")->getConnection("core_write");
202
+ $query = "DELETE FROM choiceai_recommendation_conf WHERE " . ChoiceAI_Searchcore_Model_Config::WEBSITE_ID . " = :website_id";
203
+ $binds = array(
204
+ 'website_id' => $websiteId
205
+ );
206
+ $write->query($query, $binds);
207
+ }
208
+
209
+ public function getGlobalConfig(Mage_Core_Model_Website $website, $keys =array()) {
210
+ }
211
+ }
212
+
213
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Resource/Config/Collection.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Resource_Config_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
10
+ {
11
+ /**
12
+ */
13
+ public function _construct()
14
+ {
15
+ $this->_init('choiceai_searchcore/config');
16
+ }
17
+
18
+
19
+ }
20
+
21
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Resource/Field.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Resource_Field extends Mage_Core_Model_Mysql4_Abstract
10
+ {
11
+
12
+ const CAT_LEVEL_1 = "categoryLevel1";
13
+
14
+ const CAT_LEVEL_2 = "categoryLevel2";
15
+
16
+ const CAT_LEVEL_3 = "categoryLevel3";
17
+
18
+ const CAT_LEVEL_4 = "categoryLevel4";
19
+
20
+ const CAT_LEVEL_1_NAME = "catlevel1Name";
21
+
22
+ const CAT_LEVEL_2_NAME = "catlevel2Name";
23
+
24
+ const CAT_LEVEL_3_NAME = "catlevel3Name";
25
+
26
+ const CAT_LEVEL_4_NAME = "catlevel4Name";
27
+
28
+ const CATEGORY_IDS_NAME = "categoryIds";
29
+
30
+ const CATEGORY_IDS = "category_ids";
31
+
32
+ const CATEGORY_NAME = "category";
33
+
34
+ const AVAILABILITY = 'availability';
35
+
36
+ const QTY_ASSOCIATED = "qtyAssociated";
37
+
38
+ const AVAILABILITY_ASSOCIATED = "availabilityAssociated";
39
+
40
+ const QTY_MANAGE_ASSOCIATED = "manage_stockAssociated";
41
+
42
+ const QTY_CONFIG_USE_MANAGE_STOCK = "use_config_manage_stock";
43
+
44
+ const QTY_CONFIG_USE_MANAGE_STOCK_ASSOCIATED = "use_config_manage_stockAssociated";
45
+
46
+ const QTY = "qty";
47
+
48
+ const QTY_MANAGE = "manage_stock";
49
+ /**
50
+ * ChoiceAI Field Config table Name
51
+ *
52
+ * @var string
53
+ */
54
+ protected $_choiceaiFieldTable;
55
+
56
+ /**
57
+ * @return void
58
+ */
59
+ protected function _construct()
60
+ {
61
+ $this->_init('choiceai_searchcore/field', 'id');
62
+ $this->_choiceaiFieldTable = $this->getTable('choiceai_searchcore/field');
63
+ }
64
+
65
+ public function getTableName() {
66
+ return $this->_choiceaiFieldTable;
67
+ }
68
+
69
+ public function getFieldByFeatureField($websiteId, $featureField){
70
+ $adapter = $this->_getReadAdapter();
71
+
72
+ $select = $adapter->select()
73
+ ->from($this->_choiceaiFieldTable, ChoiceAI_Searchcore_Model_Field::field_name)
74
+ ->where('`'.ChoiceAI_Searchcore_Model_Field::website_id.'` = ?', (int)$websiteId)
75
+ ->where('`'.ChoiceAI_Searchcore_Model_Field::featured_field.'` = ?', $featureField);
76
+
77
+ $result = $adapter->fetchOne($select);
78
+ if($result == false) {
79
+ return null;
80
+ }
81
+ return $result;
82
+ }
83
+
84
+ public function getDisplayableFields(Mage_Core_Model_Website $website) {
85
+ $fields = $this->getDisplayableFieldCollection($website);
86
+ if(count($fields) == 0) {
87
+ return $this->setDefaultFields($website)
88
+ ->getDisplayableFieldCollection($website);
89
+ }
90
+ return $fields;
91
+ }
92
+
93
+ protected function getDisplayableFieldCollection(Mage_Core_Model_Website $website) {
94
+ return Mage::getModel("choiceai_searchcore/field")
95
+ ->getCollection()
96
+ ->addFieldsDisplayFilter()
97
+ ->addWebsiteFilter($website)
98
+ ->load();
99
+ }
100
+
101
+ public function setDefaultFields(Mage_Core_Model_Website $website) {
102
+ $_writer = $this->_getWriteAdapter();
103
+ $_writer->query($this->getDefaultFieldInsertStatement($website));
104
+ return $this;
105
+ }
106
+
107
+ public function getDefaultFieldInsertStatement(Mage_Core_Model_Website $website) {
108
+ $websiteId = $website->getWebsiteId();
109
+ if(is_null($websiteId)) {
110
+ return "";
111
+ }
112
+ $fieldTable = Mage::getResourceModel('choiceai_searchcore/field')->getTableName();
113
+ return "
114
+ INSERT INTO `{$fieldTable}` (`website_id`, `field_name`, `datatype`, `autosuggest`, `featured_field`, `multivalued`, `displayed`)
115
+ VALUES
116
+ ({$websiteId}, 'name', 'text', 1, 'title', 0, 1),
117
+ ({$websiteId}, 'final_price', 'decimal', 0, 'price', 0, 1),
118
+ ({$websiteId}, 'price', 'decimal', 0, NULL, 0, 1),
119
+ ({$websiteId}, 'brand', 'text', 0, 'brand', 0, 1),
120
+ ({$websiteId}, 'color', 'text', 0, 'color', 1, 1),
121
+ ({$websiteId}, 'size', 'text', 0, 'size', 1, 1),
122
+ ({$websiteId}, 'image', 'link', 0, 'imageUrl', 1, 1),
123
+ ({$websiteId}, 'url_path', 'link', 0, 'productUrl', 0, 1),
124
+ ({$websiteId}, 'gender', 'text', 0, 'gender', 0, 1),
125
+ ({$websiteId}, 'description', 'longText', 0, 'description', 0, 1),
126
+ ({$websiteId}, 'catlevel1Name', 'text', 0, 'catlevel1Name', 0, 0),
127
+ ({$websiteId}, 'catlevel2Name', 'text', 0, 'catlevel2Name', 0, 0),
128
+ ({$websiteId}, 'catlevel3Name', 'text', 0, 'catlevel3Name', 0, 0),
129
+ ({$websiteId}, 'catlevel4Name', 'text', 0, 'catlevel4Name', 0, 0),
130
+ ({$websiteId}, 'categoryLevel1', 'text', 0, NULL, 1, 0),
131
+ ({$websiteId}, 'categoryLevel2', 'text', 0, NULL, 1, 0),
132
+ ({$websiteId}, 'categoryLevel3', 'text', 0, NULL, 1, 0),
133
+ ({$websiteId}, 'categoryLevel4', 'text', 0, NULL, 1, 0),
134
+ ({$websiteId}, 'created_at', 'date', 0, NULL, 0, 1),
135
+ ({$websiteId}, 'availability', 'bool', 0, 'availability', 0, 0),
136
+ ({$websiteId}, 'status', 'number', 0, NULL, 0, 0),
137
+ ({$websiteId}, 'visibility', 'number', 0, NULL, 0, 0),
138
+ ({$websiteId}, 'qty', 'number', 0, NULL, 0, 0),
139
+ ({$websiteId}, 'categoryIds', 'longText', 0, NULL, 1, 0),
140
+ ({$websiteId}, 'category', 'text', 0, 'category', 1, 0),
141
+ ({$websiteId}, 'uniqueId', 'longText', 0, NULL, 0, 0),
142
+ ({$websiteId}, 'entity_id', 'longText', 0, NULL, 0, 0);";
143
+ }
144
+ }
145
+
146
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Resource/Field/Collection.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @category ChoiceAI
5
+ * @package ChoiceAI_Searchcore
6
+ * @copyright Copyright (c) MineWhat
7
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
8
+ */
9
+ class ChoiceAI_Searchcore_Model_Resource_Field_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
10
+ {
11
+ /**
12
+ */
13
+ public function _construct()
14
+ {
15
+ $this->_init('choiceai_searchcore/field');
16
+ }
17
+
18
+ /**
19
+ * Method to add fields to display filter
20
+ *
21
+ * @return void
22
+ */
23
+ public function addFieldsDisplayFilter() {
24
+ $this->addFieldToFilter(ChoiceAI_Searchcore_Model_Field::dislayable,1);
25
+ return $this;
26
+ }
27
+
28
+ public function addWebsiteFilter(Mage_Core_Model_Website $website) {
29
+ $this->addFieldToFilter(ChoiceAI_Searchcore_Model_Field::website_id, $website->getWebsiteId());
30
+ return $this;
31
+ }
32
+
33
+ /**
34
+ * Method to get field collection as array
35
+ *
36
+ * @return array
37
+ */
38
+ public function __asArray() {
39
+ $fields = array();
40
+ foreach($this->_items as $item) {
41
+ $field = array();
42
+ $field[ChoiceAI_Searchcore_Model_Field::field_name] = $item->getFieldName();
43
+ $field[ChoiceAI_Searchcore_Model_Field::datatype] = $item->getDatatype();
44
+ $field[ChoiceAI_Searchcore_Model_Field::autosuggest] = $item->getAutosuggest();
45
+ $featureField = $item->getFeaturedField();
46
+ if(isset($featureField)) {
47
+ $field[ChoiceAI_Searchcore_Model_Field::featured_field] = $featureField;
48
+ }
49
+ $fields[] = $field;
50
+ }
51
+ return $fields;
52
+ }
53
+
54
+ public function getFeatureFields(Mage_Core_Model_Website $website) {
55
+ $this->getSelect()->where(ChoiceAI_Searchcore_Model_Field::featured_field. " IS NOT NULL AND ".
56
+ ChoiceAI_Searchcore_Model_Field::website_id . " = " . $website->getWebsiteId());
57
+ return $this->load();
58
+ }
59
+
60
+ public function getFields(Mage_Core_Model_Website $website) {
61
+ $this->getSelect()->where(ChoiceAI_Searchcore_Model_Field::website_id . " = " . $website->getWebsiteId());
62
+ return $this->load();
63
+ }
64
+ }
65
+
66
+ ?>
app/code/local/ChoiceAI/Searchcore/Model/Resource/Product/Collection.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category ChoiceAI
4
+ * @package ChoiceAI_Searchcore
5
+ * @copyright Copyright (c) MineWhat
6
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
+ */
8
+ class ChoiceAI_Searchcore_Model_Resource_Product_Collection extends
9
+ Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection{
10
+
11
+ protected function _construct()
12
+ {
13
+ parent::_construct();
14
+ }
15
+
16
+ public function isEnabledFlat()
17
+ {
18
+ return false;
19
+ }
20
+
21
+ /**
22
+ * Merge colle
23
+ * @param $collection1
24
+ * @param $collection2
25
+ * @return mixed
26
+ */
27
+ public function mergeCollection($collection) {
28
+ foreach($collection as $product) {
29
+ if(!array_key_exists($product->getEntityId(), $this->_items)) {
30
+ $this->addItem($product);
31
+ }
32
+ }
33
+ return $this;
34
+ }
35
+
36
+ /**
37
+ * sets collection is loaded
38
+ * @return $this
39
+ */
40
+ public function virtuallyLoad() {
41
+ $this->_setIsLoaded(true);
42
+ return $this;
43
+ }
44
+
45
+ public function addIncrementalUploadFiltersToAdd(Mage_Core_Model_Website $website, $fromDate,
46
+ $toDate, $productIds = array()) {
47
+ $this->_addBasicFilterToUpload($website);
48
+ $this->addAttributeToFilter(array(
49
+ array( 'attribute' => 'updated_at',
50
+ 'from' => $fromDate,
51
+ 'to' => $toDate,
52
+ 'date' => true
53
+ ),
54
+ array( 'attribute' => 'entity_id',
55
+ 'in' => $productIds
56
+ )
57
+ ));
58
+ Mage::helper('choiceai_searchcore')->log(Zend_Log::DEBUG, (string)$this->getSelect());
59
+ return $this;
60
+ }
61
+
62
+ public function addIncrementalUploadFiltersToDelete(Mage_Core_Model_Website $website, $fromDate, $toDate) {
63
+ $this->addAttributeToSelect('entity_id');
64
+ $this->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_DISABLED);
65
+ $this->addAttributeToFilter(array(
66
+ array( 'attribute' => 'updated_at',
67
+ 'from' => $fromDate,
68
+ 'to' => $toDate,
69
+ 'date' => true
70
+ )
71
+ ));
72
+ return $this;
73
+
74
+ }
75
+
76
+ protected function _addBasicFilterToUpload(Mage_Core_Model_Website $website)
77
+ {
78
+ $adapter = Mage::getSingleton("core/resource");
79
+ $visiblityCondition = array('in' => array(2,3,4));
80
+ $_catalogInventoryTable = method_exists($adapter, 'getTableName')
81
+ ? $adapter->getTableName('cataloginventory_stock_item') : 'cataloginventory_stock_item';
82
+ $stockfields = array("qty" => "qty", "manage_stock" => "manage_stock",
83
+ "use_config_manage_stock" => "use_config_manage_stock", "is_in_stock" => "is_in_stock");
84
+
85
+ $this
86
+ ->addWebsiteFilter($website->getWebsiteId())
87
+ ->addAttributeToSelect('*')
88
+ ->joinTable($_catalogInventoryTable, 'product_id=entity_id', $stockfields, null, 'left')
89
+ ->addAttributeToFilter('status',1)
90
+ ->addCategoryIds()
91
+ ->addAttributeToFilter('visibility',$visiblityCondition)
92
+ ->addPriceData(Mage_Customer_Model_Group::NOT_LOGGED_IN_ID, $website->getWebsiteId());
93
+
94
+ Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($this);
95
+ #Mage::getSingleton('catalog/product_visibility')->addVisibleInSiteFilterToCollection($this);
96
+ return $this;
97
+ }
98
+
99
+
100
+ /**
101
+ * method to get the catalog collection
102
+ *
103
+ */
104
+ public function addFullUploadFilters(Mage_Core_Model_Website $website) {
105
+ $this->_addBasicFilterToUpload($website);
106
+ return $this;
107
+ }
108
+ }
109
+
110
+ ?>
app/code/local/ChoiceAI/Searchcore/etc/config.xml ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <config>
2
+ <modules>
3
+ <ChoiceAI_Searchcore>
4
+ <version>0.0.9</version>
5
+ </ChoiceAI_Searchcore>
6
+ </modules>
7
+ <global>
8
+ <resources>
9
+ <choiceai_searchcore_setup>
10
+ <setup>
11
+ <module>ChoiceAI_Searchcore</module>
12
+ </setup>
13
+ </choiceai_searchcore_setup>
14
+ </resources>
15
+ <helpers>
16
+ <choiceai_searchcore>
17
+ <class>ChoiceAI_Searchcore_Helper</class>
18
+ </choiceai_searchcore>
19
+ </helpers>
20
+ <models>
21
+ <choiceai_searchcore>
22
+ <class>ChoiceAI_Searchcore_Model</class>
23
+ <resourceModel>choiceai_searchcore_resource</resourceModel>
24
+ </choiceai_searchcore>
25
+ <choiceai_searchcore_resource>
26
+ <class>ChoiceAI_Searchcore_Model_Resource</class>
27
+ <entities>
28
+ <config>
29
+ <table>choiceai_recommendation_conf</table>
30
+ </config>
31
+ <field>
32
+ <table>choiceai_field_conf</table>
33
+ </field>
34
+ <sync>
35
+ <table>choiceai_product_sync</table>
36
+ </sync>
37
+ </entities>
38
+ </choiceai_searchcore_resource>
39
+ </models>
40
+ <blocks>
41
+ <choiceai_searchcore>
42
+ <class>ChoiceAI_Searchcore_Block</class>
43
+ </choiceai_searchcore>
44
+ </blocks>
45
+ <events>
46
+ <controller_action_predispatch_choiceai_searchcore>
47
+ <observers>
48
+ <choiceai_searchcore_auth>
49
+ <type>singleton</type>
50
+ <class>choiceai_searchcore/auth</class>
51
+ <method>authorize</method>
52
+ </choiceai_searchcore_auth>
53
+ </observers>
54
+ </controller_action_predispatch_choiceai_searchcore>
55
+ <checkout_cart_add_product_complete>
56
+ <observers>
57
+ <choiceai_searchcore_cart_tracker>
58
+ <type>singleton</type>
59
+ <class>choiceai_searchcore/observer</class>
60
+ <method>trackAddToCart</method>
61
+ </choiceai_searchcore_cart_tracker>
62
+ </observers>
63
+ </checkout_cart_add_product_complete>
64
+ <sales_order_payment_place_end>
65
+ <observers>
66
+ <choiceai_searchcore_order_tracker>
67
+ <type>singleton</type>
68
+ <class>choiceai_searchcore/observer</class>
69
+ <method>trackOrder</method>
70
+ </choiceai_searchcore_order_tracker>
71
+ </observers>
72
+ </sales_order_payment_place_end>
73
+ <catalog_product_delete_before>
74
+ <observers>
75
+ <choiceai_searchcore_order_tracker>
76
+ <type>singleton</type>
77
+ <class>choiceai_searchcore/observer</class>
78
+ <method>trackDelete</method>
79
+ </choiceai_searchcore_order_tracker>
80
+ </observers>
81
+ </catalog_product_delete_before>
82
+ <catalog_product_delete_commit_after>
83
+ <observers>
84
+ <choiceai_searchcore_order_tracker>
85
+ <type>singleton</type>
86
+ <class>choiceai_searchcore/observer</class>
87
+ <method>trackDelete</method>
88
+ </choiceai_searchcore_order_tracker>
89
+ </observers>
90
+ </catalog_product_delete_commit_after>
91
+ <cataloginventory_stock_item_save_commit_after>
92
+ <observers>
93
+ <choiceai_searchcore_catalog_inventory_save>
94
+ <type>singleton</type>
95
+ <class>choiceai_searchcore/observer</class>
96
+ <method>catalogInventorySave</method>
97
+ </choiceai_searchcore_catalog_inventory_save>
98
+ </observers>
99
+ </cataloginventory_stock_item_save_commit_after>
100
+ <sales_order_item_cancel>
101
+ <observers>
102
+ <choiceai_searchcore_order_cancel>
103
+ <type>singleton</type>
104
+ <class>choiceai_searchcore/observer</class>
105
+ <method>catalogInventorySave</method>
106
+ </choiceai_searchcore_order_cancel>
107
+ </observers>
108
+ </sales_order_item_cancel>
109
+ </events>
110
+ </global>
111
+ <default>
112
+ <choiceai>
113
+ <general>
114
+ <price>final_price</price>
115
+ <productUrl>url_path</productUrl>
116
+ <max_feed_lock_feed>2</max_feed_lock_feed>
117
+ <include_out_of_stock>true</include_out_of_stock>
118
+ <include_child_product>true</include_child_product>
119
+ <include_taxonomy_nodes>false</include_taxonomy_nodes>
120
+ <include_taxonomy_mapping>false</include_taxonomy_mapping>
121
+ <include_out_of_stock_from_non_cache>false</include_out_of_stock_from_non_cache>
122
+ <include_only_enabled_child_product>true</include_only_enabled_child_product>
123
+ <include_out_of_stock_child_product>false</include_out_of_stock_child_product>
124
+ <field_conf>{}</field_conf>
125
+ <exclude_category>[]</exclude_category>
126
+ <tracker_url>https://tracker.choiceaiapi.com/</tracker_url>
127
+ <platform_url>https://accounts.choiceaiapi.com/admin/</platform_url>
128
+ <service_url>https://starwreck.choiceaiapi.com/</service_url>
129
+ <feed_url>https://feed.choiceaiapi.com/</feed_url>
130
+ </general>
131
+ </choiceai>
132
+ </default>
133
+ </config>
app/code/local/ChoiceAI/Searchcore/sql/choiceai_searchcore_setup/mysql4-install-1.0.0.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ $installer = $this;
5
+ /* @var $installer Mage_Searchcore_Model_Resource_Setup */
6
+
7
+ $installer->startSetup();
8
+
9
+ $configTable = $installer->getTable('choiceai_recommendation_conf');
10
+ $fieldTable = $installer->getTable('choiceai_field_conf');
11
+ $productSyncTable = $installer->getTable('choiceai_product_sync');
12
+
13
+ $installer->run("
14
+
15
+ CREATE TABLE IF NOT EXISTS `{$fieldTable}` (
16
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
17
+ `website_id` tinyint(5) unsigned NOT NULL,
18
+ `field_name` varchar(100) NOT NULL DEFAULT '',
19
+ `datatype` varchar(20) NOT NULL DEFAULT '',
20
+ `autosuggest` tinyint(1) NOT NULL DEFAULT '0',
21
+ `featured_field` varchar(100) DEFAULT NULL,
22
+ `multivalued` tinyint(1) NOT NULL DEFAULT '0',
23
+ `displayed` tinyint(1) NOT NULL DEFAULT '1',
24
+ PRIMARY KEY (`id`),
25
+ UNIQUE KEY `website_id` (`website_id`,`field_name`)
26
+ ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
27
+
28
+ CREATE TABLE IF NOT EXISTS `{$configTable}` (
29
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
30
+ `website_id` smallint(5) unsigned NOT NULL,
31
+ `key` varchar(50) NOT NULL DEFAULT '',
32
+ `value` varchar(50) DEFAULT NULL,
33
+ PRIMARY KEY (`id`)
34
+ ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
35
+
36
+ CREATE TABLE IF NOT EXISTS `{$productSyncTable}` (
37
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
38
+ `product_id` int(10) unsigned NOT NULL,
39
+ `website_id` smallint(5) unsigned NOT NULL,
40
+ `synced` tinyint(1) NOT NULL DEFAULT '0',
41
+ `updated_time` datetime DEFAULT NULL,
42
+ `sync_time` datetime DEFAULT NULL,
43
+ `operation` enum('ADD','DELETE') NOT NULL DEFAULT 'ADD',
44
+ PRIMARY KEY (`id`),
45
+ UNIQUE KEY `product_id` (`product_id`,`website_id`)
46
+ ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
47
+ ");
48
+
49
+ $websiteCollection = Mage::getModel('core/website')->getCollection()->load();
50
+ foreach($websiteCollection as $website) {
51
+ $websiteId = $website->getWebsiteId();
52
+ if(is_null($websiteId)) {
53
+ continue;
54
+ }
55
+ $fieldTable = Mage::getResourceModel('choiceai_searchcore/field')->getTableName();
56
+ $insertQuery = "
57
+ INSERT INTO `{$fieldTable}` (`website_id`, `field_name`, `datatype`, `autosuggest`, `featured_field`, `multivalued`, `displayed`)
58
+ VALUES
59
+ ({$websiteId}, 'name', 'text', 1, 'title', 0, 1),
60
+ ({$websiteId}, 'final_price', 'decimal', 0, 'price', 0, 1),
61
+ ({$websiteId}, 'price', 'decimal', 0, NULL, 0, 1),".
62
+ (Mage::helper('choiceai_searchcore/feedhelper')->isAttributePresent('brand')?"({$websiteId}, 'brand', 'text', 0, 'brand', 0, 1),":"").
63
+ (Mage::helper('choiceai_searchcore/feedhelper')->isAttributePresent('color')?"({$websiteId}, 'color', 'text', 0, 'color', 1, 1),":"").
64
+ (Mage::helper('choiceai_searchcore/feedhelper')->isAttributePresent('size')?"({$websiteId}, 'size', 'text', 0, 'size', 1, 1),":"").
65
+ "({$websiteId}, 'image', 'link', 0, 'imageUrl', 1, 1),
66
+ ({$websiteId}, 'url_path', 'link', 0, 'productUrl', 0, 1),
67
+ ({$websiteId}, 'gender', 'text', 0, 'gender', 0, 1),
68
+ ({$websiteId}, 'description', 'longText', 0, 'description', 0, 1),
69
+ ({$websiteId}, 'catlevel1Name', 'text', 0, 'catlevel1Name', 0, 0),
70
+ ({$websiteId}, 'catlevel2Name', 'text', 0, 'catlevel2Name', 0, 0),
71
+ ({$websiteId}, 'catlevel3Name', 'text', 0, 'catlevel3Name', 0, 0),
72
+ ({$websiteId}, 'catlevel4Name', 'text', 0, 'catlevel4Name', 0, 0),
73
+ ({$websiteId}, 'categoryLevel1', 'text', 0, NULL, 1, 0),
74
+ ({$websiteId}, 'categoryLevel2', 'text', 0, NULL, 1, 0),
75
+ ({$websiteId}, 'categoryLevel3', 'text', 0, NULL, 1, 0),
76
+ ({$websiteId}, 'categoryLevel4', 'text', 0, NULL, 1, 0),
77
+ ({$websiteId}, 'created_at', 'date', 0, NULL, 0, 1),
78
+ ({$websiteId}, 'availability', 'bool', 0, 'availability', 0, 0),
79
+ ({$websiteId}, 'status', 'number', 0, NULL, 0, 0),
80
+ ({$websiteId}, 'visibility', 'number', 0, NULL, 0, 0),
81
+ ({$websiteId}, 'qty', 'number', 0, NULL, 0, 0),
82
+ ({$websiteId}, 'categoryIds', 'longText', 0, NULL, 1, 0),
83
+ ({$websiteId}, 'category', 'text', 0, 'category', 1, 0),
84
+ ({$websiteId}, 'uniqueId', 'longText', 0, NULL, 0, 0),
85
+ ({$websiteId}, 'type_id', 'longText', 0, NULL, 0, 0),
86
+ ({$websiteId}, 'entity_id', 'longText', 0, NULL, 0, 0)
87
+ ON DUPLICATE KEY UPDATE `field_name`=`field_name`;";
88
+ $installer->run($insertQuery);
89
+ }
90
+ $installer->endSetup();
91
+ ?>
app/code/local/ChoiceAI/Searchcore/sql/choiceai_searchcore_setup/upgrade-1.0.21-1.0.22.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $installer = $this;
3
+ /* @var $installer Mage_Searchcore_Model_Resource_Setup */
4
+
5
+ $installer->startSetup();
6
+ $fieldTable = $installer->getTable('choiceai_field_conf');
7
+ $configTable = $installer->getTable('choiceai_recommendation_conf');
8
+ try {
9
+ $installer->run("ALTER TABLE `{$configTable}` CHANGE `key` `choiceai_key` VARCHAR(50)");
10
+ } catch (Exception $e) {
11
+ //ignore the exceptions
12
+ }
13
+
14
+ $websiteCollection = Mage::getModel('core/website')->getCollection()->load();
15
+ foreach($websiteCollection as $website) {
16
+ $websiteId = $website->getWebsiteId();
17
+ if (is_null($websiteId)) {
18
+ continue;
19
+ }
20
+ $fieldTable = Mage::getResourceModel('choiceai_searchcore/field')->getTableName();
21
+ $insertQuery = "
22
+ INSERT INTO `{$fieldTable}` (`website_id`, `field_name`, `datatype`, `autosuggest`, `featured_field`, `multivalued`, `displayed`)
23
+ VALUES
24
+ ({$websiteId}, '" . ChoiceAI_Searchcore_Model_Resource_Field::QTY_MANAGE_ASSOCIATED . "',
25
+ '" .ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_NUMBER . "', 0, NULL, 1, 0),
26
+ ({$websiteId}, '" .ChoiceAI_Searchcore_Model_Resource_Field::QTY_ASSOCIATED . "',
27
+ '" .ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_NUMBER . "', 0, NULL, 1, 0),
28
+ ({$websiteId}, '" .ChoiceAI_Searchcore_Model_Resource_Field::QTY_CONFIG_USE_MANAGE_STOCK_ASSOCIATED. "',
29
+ '" .ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_NUMBER . "', 0, NULL, 1, 0),
30
+ ({$websiteId}, 'statusAssociated',
31
+ '" .ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_NUMBER . "', 0, NULL, 1, 0),
32
+ ({$websiteId}, '" .ChoiceAI_Searchcore_Model_Resource_Field::AVAILABILITY_ASSOCIATED . "',
33
+ '" .ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_BOOL . "', 0, NULL, 1, 0),
34
+ ({$websiteId}, '" .ChoiceAI_Searchcore_Model_Resource_Field::QTY_MANAGE . "',
35
+ '" .ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_NUMBER . "', 0, NULL, 0, 0),
36
+ ({$websiteId}, '" .ChoiceAI_Searchcore_Model_Resource_Field::QTY_CONFIG_USE_MANAGE_STOCK . "',
37
+ '" .ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_NUMBER . "', 0, NULL, 0, 0),
38
+ ({$websiteId}, '" .ChoiceAI_Searchcore_Model_Resource_Field::QTY . "',
39
+ '" .ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_NUMBER . "', 0, NULL, 0, 0),
40
+ ({$websiteId}, 'type_id',
41
+ '" .ChoiceAI_Searchcore_Helper_Constants::CHOICEAI_DATATYPE_LONGTEXT . "', 0, NULL, 0, 1)
42
+ ON DUPLICATE KEY UPDATE `field_name`=`field_name`;";
43
+ $installer->run($insertQuery);
44
+ }
45
+
46
+ ?>
app/design/frontend/base/default/template/choiceai/personalisation/base/script.phtml CHANGED
@@ -34,5 +34,6 @@ foreach ($cart->getAllVisibleItems() as $item) {
34
  <script type="text/javascript">
35
  //<![CDATA[
36
  window.CAI_CART_ITEMS = <?php echo json_encode($cart_items); ?>;
 
37
  //]]>
38
  </script>
34
  <script type="text/javascript">
35
  //<![CDATA[
36
  window.CAI_CART_ITEMS = <?php echo json_encode($cart_items); ?>;
37
+ window.CAI_MAGENTO_ADDTOCART_FORM_KEY = '<?php echo Mage::getSingleton('core/session')->getFormKey()?>';
38
  //]]>
39
  </script>
app/design/frontend/base/default/template/choiceai/personalisation/event/checkout/onepage/success.phtml DELETED
@@ -1,21 +0,0 @@
1
- <?php
2
- /**
3
- * @category ChoiceAI
4
- * @package ChoiceAI_Personalisation
5
- * @copyright Copyright (c) MineWhat
6
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
- */
8
- ?>
9
- <?php if (($orderInfo = $this->getOrderInfo())) { ?>
10
- <script type="text/javascript">
11
- //<![CDATA[
12
- var _caiapi = _caiapi || [];
13
- var products = [];
14
- <?php foreach ($orderInfo['items'] as $product) { ?>
15
- products.push({pid: '<?php echo $product["id"] ?>', qty: '<?php echo intval($product["qty"]) ?>', sku: '<?php echo $product["sku"] ?>', price: '<?php echo $product["price"] ?>', parent_pid: '<?php echo $product["parentId"] ?>', bundle: '<?php echo json_encode($product["bundle"]) ?>'});
16
- <?php } ?>
17
- _caiapi.push(['trackEvent', 'buy', {products: products, order: {order_number: '<?php echo $orderInfo["orderId"] ?>', payment: '<?php echo $orderInfo["paymentMethod"] ?>', created_at: '<?php echo $orderInfo["createdAt"] ?>', email: '<?php echo $orderInfo["email"] ?>'}, platform: 'magento', currency: '<?php echo $orderInfo["currency"] ?>'}]);
18
-
19
- //]]>
20
- </script>
21
- <?php } ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/design/frontend/default/default/template/choiceai/personalisation/base/script.phtml CHANGED
@@ -34,5 +34,10 @@ foreach ($cart->getAllVisibleItems() as $item) {
34
  <script type="text/javascript">
35
  //<![CDATA[
36
  window.CAI_CART_ITEMS = <?php echo json_encode($cart_items); ?>;
 
 
 
 
 
37
  //]]>
38
  </script>
34
  <script type="text/javascript">
35
  //<![CDATA[
36
  window.CAI_CART_ITEMS = <?php echo json_encode($cart_items); ?>;
37
+ window.cai_magento_addtocart = function(id, selected_variant_params, qty) {
38
+ var form_key = '<?php echo Mage::getSingleton('core/session')->getFormKey()?>';
39
+ var url = '<?php echo Mage::getUrl('checkout/cart/add');?>'+'product/'+id+'/qty/'+qty+'/form_key/'+form_key;
40
+ window.location.assign(url);
41
+ }
42
  //]]>
43
  </script>
app/design/frontend/default/default/template/choiceai/personalisation/event/catalog/product/view.phtml DELETED
@@ -1,61 +0,0 @@
1
- <?php
2
- /**
3
- * @category ChoiceAI
4
- * @package ChoiceAI_Personalisation
5
- * @copyright Copyright (c) MineWhat
6
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
- */
8
- ?>
9
- <?php $_product = $this->getCurrentProduct() ?>
10
- <?php if ($_product) { ?>
11
- <?php
12
- $_associated_products = $this->getAssociatedProducts($_product);
13
- $associated_ids = array();
14
-
15
- $mwdata = array();
16
- $mwdata['product'] = array();
17
- $mwdata['associated_products'] = array();
18
-
19
- $mwdata['product']['id'] = $_product->getId();
20
- $mwdata['product']['sku'] = $_product->getSku();
21
-
22
- $categories = $_product->getCategoryCollection()->addAttributeToSelect('name');
23
-
24
- $mwdata['product']['cat'] = array();
25
- foreach($categories as $category) {
26
- $mwdata['product']['cat'][] = $category->getName();
27
- }
28
-
29
- $mwdata['product']['price'] = $_product->getPrice();
30
-
31
- foreach($_associated_products as $simple_product) {
32
- $product_info = array();
33
- $associated_ids[] = $simple_product->getId();
34
- $product_info['id'] = $simple_product->getId();
35
- $product_info['sku'] = $simple_product->getSku();
36
- $product_info['price'] = $simple_product->getPrice();
37
- $mwdata['associated_products'][] = $product_info;
38
- }
39
-
40
- ?>
41
- <script type="text/choiceai_data">
42
- //<![CDATA[
43
-
44
- <?php
45
- try {
46
- echo json_encode($mwdata);
47
- } catch(Exception $exception) {
48
-
49
- }
50
- ?>
51
-
52
- //]]>
53
- </script>
54
-
55
- <script type="text/javascript">
56
- //<![CDATA[
57
- var _caiapi = _caiapi || [];
58
- _caiapi.push(['trackEvent', 'product', {pid: '<?php echo $_product->getId() ?>', associated_ids: '<?php echo json_encode($associated_ids) ?>'}]);
59
- //]]>
60
- </script>
61
- <?php } ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/design/frontend/default/default/template/choiceai/personalisation/event/checkout/cart/index.phtml DELETED
@@ -1,17 +0,0 @@
1
- <?php
2
- /**
3
- * @category ChoiceAI
4
- * @package ChoiceAI_Personalisation
5
- * @copyright Copyright (c) MineWhat
6
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
- */
8
- ?>
9
- <?php $_product = $this->getProductToShoppingCart() ?>
10
- <?php if ($_product && $_product["id"]) { ?>
11
- <script type="text/javascript">
12
- //<![CDATA[
13
- var _caiapi = _caiapi || [];
14
- _caiapi.push(['trackEvent', 'addtocart', {pid: '<?php echo $_product["id"] ?>', sku: '<?php echo $_product["sku"] ?>', parent_pid: '<?php echo $_product["parentId"] ?>', qty: '<?php echo $_product["qty"] ?>', bundle: '<?php echo json_encode($_product["bundle"]) ?>'}]);
15
- //]]>
16
- </script>
17
- <?php } ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/design/frontend/default/default/template/choiceai/personalisation/event/checkout/onepage/success.phtml DELETED
@@ -1,20 +0,0 @@
1
- <?php
2
- /**
3
- * @category ChoiceAI
4
- * @package ChoiceAI_Personalisation
5
- * @copyright Copyright (c) MineWhat
6
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
7
- */
8
- ?>
9
- <?php if (($orderInfo = $this->getOrderInfo())) { ?>
10
- <script type="text/javascript">
11
- //<![CDATA[
12
- var _caiapi = _caiapi || [];
13
- var products = [];
14
- <?php foreach ($orderInfo['items'] as $product) { ?>
15
- products.push({pid: '<?php echo $product["id"] ?>', qty: '<?php echo intval($product["qty"]) ?>', sku: '<?php echo $product["sku"] ?>', price: '<?php echo $product["price"] ?>', parent_pid: '<?php echo $product["parentId"] ?>', bundle: '<?php echo json_encode($product["bundle"]) ?>'});
16
- <?php } ?>
17
- _caiapi.push(['trackEvent', 'buy', {products: products, order: {order_number: '<?php echo $orderInfo["orderId"] ?>', payment: '<?php echo $orderInfo["paymentMethod"] ?>', created_at: '<?php echo $orderInfo["createdAt"] ?>', email: '<?php echo $orderInfo["email"] ?>'}, platform: 'magento', currency: '<?php echo $orderInfo["currency"] ?>'}]);
18
- //]]>
19
- </script>
20
- <?php } ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/etc/modules/ChoiceAI_Personalisation.xml CHANGED
@@ -6,5 +6,13 @@
6
  <active>true</active>
7
  <codePool>community</codePool>
8
  </ChoiceAI_Personalisation>
 
 
 
 
 
 
 
 
9
  </modules>
10
  </config>
6
  <active>true</active>
7
  <codePool>community</codePool>
8
  </ChoiceAI_Personalisation>
9
+ <ChoiceAI_Searchcore>
10
+ <active>true</active>
11
+ <codePool>local</codePool>
12
+ </ChoiceAI_Searchcore>
13
+ <ChoiceAI_Search>
14
+ <active>true</active>
15
+ <codePool>local</codePool>
16
+ </ChoiceAI_Search>
17
  </modules>
18
  </config>
lib/ChoiceAI/Client.php ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @copyright Copyright (c) MineWhat
4
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
5
+ */
6
+
7
+ include("Service.php");
8
+ class ChoiceAI_Client {
9
+ /**
10
+ * Default ChoiceAIsearch ruleset
11
+ */
12
+ const DEFAULT_RULESET = 'search';
13
+
14
+ /**
15
+ * Default transport
16
+ *
17
+ * @var string
18
+ */
19
+ const DEFAULT_TRANSPORT = 'https';
20
+
21
+ protected $params = array(
22
+ 'ruleset' => self::DEFAULT_RULESET,
23
+ 'multiSelectFacet' => false,
24
+ 'filter' => array(),
25
+ 'rangeFilter' =>array(),
26
+ 'cond' => array(),
27
+ 'query' => '',
28
+ 'category-id' => ''
29
+ );
30
+
31
+ protected $address = '';
32
+
33
+ /**
34
+ * Number of seconds after a timeout occurs for every request
35
+ * If using indexing of file large value necessary.
36
+ */
37
+ const TIMEOUT = 300;
38
+
39
+ /**
40
+ * Config with defaults
41
+ *
42
+ * @var array
43
+ */
44
+ protected $_config = array(
45
+ 'ruleset' => self::DEFAULT_RULESET,
46
+ 'transport' => self::DEFAULT_TRANSPORT,
47
+ 'timeout' => self::TIMEOUT,
48
+ 'headers' => array()
49
+ );
50
+
51
+
52
+
53
+ /**
54
+ * Creates a new ChoiceAI client
55
+ *
56
+ * @param array $config OPTIONAL Additional config options
57
+ */
58
+ public function __construct(array $config = array()) {
59
+ $this->setConfig($config);
60
+ $this->address = $this->_config['transport'].'://datav3.choice.ai/widget/debug/personalisation/products/';
61
+ }
62
+
63
+ /**
64
+ * Sets specific config values (updates and keeps default values)
65
+ *
66
+ * @param array $config Params
67
+ */
68
+ public function setConfig(array $config) {
69
+ foreach ($config as $key => $value) {
70
+ $this->_config[$key] = $value;
71
+ }
72
+
73
+ return $this;
74
+ }
75
+
76
+ /**
77
+ * Returns a specific config key or the whole
78
+ * config array if not set
79
+ *
80
+ * @param string $key Config key
81
+ * @return array|string Config value
82
+ */
83
+ public function getConfig($key = '') {
84
+ if (empty($key)) {
85
+ return $this->_config;
86
+ }
87
+
88
+ if (!array_key_exists($key, $this->_config)) {
89
+ throw new Exception('Config key is not set: ' . $key);
90
+ }
91
+
92
+ return $this->_config[$key];
93
+ }
94
+
95
+ /**
96
+ * Sets / overwrites a specific config value
97
+ *
98
+ * @param string $key Key to set
99
+ * @param mixed $value Value
100
+ * @return ChoiceAI_Client Client object
101
+ */
102
+ public function setConfigValue($key, $value) {
103
+ return $this->setConfig(array($key => $value));
104
+ }
105
+
106
+ /**
107
+ * Returns connection port of this client
108
+ *
109
+ * @return int Connection port
110
+ */
111
+ public function getContext() {
112
+ return $this->getConfig('context');
113
+ }
114
+
115
+ /**
116
+ * Returns transport type to user
117
+ *
118
+ * @return string Transport type
119
+ */
120
+ public function getTransport() {
121
+ return $this->getConfig('transport');
122
+ }
123
+
124
+
125
+ /**
126
+ * sets the attribute filter
127
+ * @param mixed $filter array
128
+ * @return ChoiceAI_Client Client object
129
+ */
130
+ public function setFilters($filter =array()){
131
+ if(isset($filter) && is_array($filter)){
132
+ $this->params['filter'] = $filter;
133
+ }
134
+ return $this;
135
+ }
136
+
137
+ /**
138
+ * sets the range filter
139
+ * @param mixed $rangeFilter array
140
+ * @return ChoiceAI_Client Client object
141
+ */
142
+ public function setRangeFilters($rangeFilter =array()){
143
+ if(isset($rangeFilter) && is_array($rangeFilter)){
144
+ $this->params['rangeFilter'] = $rangeFilter;
145
+ }
146
+ return $this;
147
+ }
148
+
149
+ /**
150
+ * sets the offset
151
+ * @param mixed $pg integer
152
+ * @return ChoiceAI_Client Client object
153
+ */
154
+ public function setOffset($pg = 0){
155
+ if(isset($pg)){
156
+ $this->params['start'] = $pg;
157
+ }else{
158
+ $this->params['start'] = 10;
159
+ }
160
+ return $this;
161
+ }
162
+
163
+ /**
164
+ * sets the limit
165
+ * @param mixed $limit integer
166
+ * @return ChoiceAI_Client Client object
167
+ */
168
+ public function setLimit($limit = 20){
169
+ if(isset($limit)){
170
+ $this->params['limit'] = $limit;
171
+ }else{
172
+ $this->params['limit'] = 20;
173
+ }
174
+
175
+ return $this;
176
+ }
177
+
178
+ /**
179
+ * sets the ruleset
180
+ * @param mixed $ruleset string
181
+ * @return ChoiceAI_Client Client object
182
+ */
183
+ public function setRuleset($ruleset = 'search'){
184
+ if(isset($ruleset)){
185
+ $this->params['ruleset'] = $ruleset;
186
+ }else{
187
+ $this->params['ruleset'] = 'search';
188
+ }
189
+ return $this;
190
+ }
191
+
192
+ /**
193
+ * sets the sort
194
+ * @param mixed $sorts array
195
+ * @return ChoiceAI_Client Client object
196
+ */
197
+ public function setSort($sorts = array()){
198
+ if(isset($sorts) && is_array($sorts)){
199
+ $this->params['sort'] = $sorts;
200
+ }
201
+ return $this;
202
+ }
203
+
204
+ /**
205
+ * sets the facet fields, This is mainly used for
206
+ * @param mixed $sorts array
207
+ * @return ChoiceAI_Client Client object
208
+ */
209
+ public function setFacetFields($facetField = array()){
210
+ if(isset($facetField) && is_array($facetField)){
211
+ $this->params['facets'] = $facetField;
212
+ }
213
+ return $this;
214
+ }
215
+
216
+ /**
217
+ * sets the other options which can be used
218
+ * @param mixed $options array
219
+ * @return ChoiceAI_Client Client object
220
+ */
221
+ public function setOtherOptions($options =array()){
222
+ if(isset($options) && is_array($options)){
223
+ $this->params['others'] = $options;
224
+ }
225
+ return $this;
226
+ }
227
+
228
+ /**
229
+ * sets the search query
230
+ * @param mixed $query search
231
+ * @return ChoiceAI_Client Client object
232
+ */
233
+ public function setQuery($query = ''){
234
+ if(isset($query)){
235
+ $this->params['query'] = $query;
236
+ }
237
+ return $this;
238
+ }
239
+
240
+ /**
241
+ * sets the Category Id
242
+ * @param mixed $query search
243
+ * @return ChoiceAI_Client Client object
244
+ */
245
+ public function setCategoryId($query = ''){
246
+ if(isset($query)){
247
+ $this->params['category-id'] = $query;
248
+ }
249
+ return $this;
250
+ }
251
+
252
+ /**
253
+ * sets the Cond
254
+ * @param mixed $query search
255
+ * @return ChoiceAI_Client Client object
256
+ */
257
+ public function setCond($query = ''){
258
+ if(isset($query)){
259
+ $this->params['cond'] = $query;
260
+ }
261
+ return $this;
262
+ }
263
+
264
+ /**
265
+ * sets the Cond
266
+ * @param mixed $query search
267
+ * @return ChoiceAI_Client Client object
268
+ */
269
+ public function setDebug($debug = false){
270
+ if(isset($debug)){
271
+ $this->params['debug'] = $debug;
272
+ }
273
+ return $this;
274
+ }
275
+
276
+ /**
277
+ * sets the multiSelectFacet
278
+ * @param mixed $multiSelectFacet boolean
279
+ * @return ChoiceAI_Client Client object
280
+ */
281
+ public function setMultiSelectFacet($multiSelectFacet = false){
282
+ if(isset($multiSelectFacet)){
283
+ $this->params['multiSelectFacet'] = $multiSelectFacet;
284
+ }
285
+ return $this;
286
+
287
+ }
288
+
289
+
290
+ /**
291
+ *
292
+ * Search through ChoiceAI api
293
+ *
294
+ * @return ChoiceAI_ResultSet object
295
+ */
296
+ public function search() {
297
+ $service = new ChoiceAI_Service();
298
+ $this->params["context"] = $this->getContext();
299
+ return $service->search($this->params,$this->address);
300
+
301
+ }
302
+
303
+
304
+ }
lib/ChoiceAI/Response.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @copyright Copyright (c) MineWhat
5
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
6
+ */
7
+
8
+ class ChoiceAIResponse
9
+ {
10
+ var $results=array();
11
+
12
+ public function __construct($results){
13
+ $this->results=$results;
14
+ }
15
+
16
+ /**
17
+ * function to get products
18
+ */
19
+
20
+ public function getResults(){
21
+ return $this->results["response"]["products"];
22
+ }
23
+
24
+
25
+ /**
26
+ * get Number of search Results
27
+ */
28
+ public function getNumberOfProducts(){
29
+ return $this->results["response"]["numberOfProducts"];
30
+ }
31
+
32
+
33
+ /**
34
+ * get facets
35
+ *
36
+ */
37
+ public function getFacets(){
38
+ return $this->results["facets"];
39
+ }
40
+
41
+
42
+
43
+ }
44
+
45
+ ?>
lib/ChoiceAI/Result.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @copyright Copyright (c) MineWhat
5
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
6
+ */
7
+
8
+ class ChoiceAI_Result {
9
+ /**
10
+ * Hit array
11
+ *
12
+ * @var array Hit array
13
+ */
14
+ protected $_hit = array();
15
+
16
+ /**
17
+ * Constructs a single results object
18
+ *
19
+ * @param array $hit Hit data
20
+ */
21
+ public function __construct(array $hit) {
22
+
23
+ $this->_hit = $hit;
24
+
25
+ $this->_hit["uniqueId"] = $hit["_id"];
26
+ $this->_hit["entity_id"] = $hit["_id"];
27
+
28
+ if (strpos($this->_hit["image"], 'catalog/product') !== false) {
29
+ $this->_hit["image"] = "/" . implode("/", array_slice(explode ( "/", $this->_hit["image"]), -3, 3));
30
+ }
31
+
32
+ $this->_hit["small_image"] = $this->_hit["image"];
33
+ $this->_hit["thumbnail"] = $this->_hit["image"];
34
+
35
+ $this->_hit["final_price"] = $hit["price"];
36
+ if(!is_null($hit["oldPrice"]) && $hit["oldPrice"] > 0) {
37
+ $this->_hit["price"] = $hit["oldPrice"];
38
+ } else {
39
+ $this->_hit["price"] = $hit["price"];
40
+ }
41
+
42
+ }
43
+
44
+ /**
45
+ * Magic function to directly access keys inside the result
46
+ *
47
+ * Returns null if key does not exist
48
+ *
49
+ * @param string $key Key name
50
+ * @return mixed Key value
51
+ */
52
+ public function __get($key) {
53
+ return array_key_exists($key, $this->_hit) ? $this->_hit[$key] : null;
54
+ }
55
+
56
+
57
+ /*
58
+ * Returns the raw hit array
59
+ *
60
+ * @return array Hit array
61
+ */
62
+ public function getHit() {
63
+ return $this->_hit;
64
+ }
65
+ }
lib/ChoiceAI/ResultSet.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @copyright Copyright (c) MineWhat
5
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
6
+ */
7
+
8
+ include("Result.php");
9
+ class ChoiceAI_ResultSet implements Iterator, Countable {
10
+ /**
11
+ * Results
12
+ *
13
+ * @var array Results
14
+ */
15
+ protected $_results = array();
16
+
17
+ /**
18
+ * Current position
19
+ *
20
+ * @var int Current position
21
+ */
22
+ protected $_position = 0;
23
+
24
+ /**
25
+ * Response
26
+ *
27
+ * @var array
28
+ */
29
+ protected $_response = null;
30
+ protected $_took = 0;
31
+
32
+ protected $spellCheckQuery=null;
33
+ /**
34
+ * Constructs ResultSet object
35
+ *
36
+ * @param array $response
37
+ */
38
+ public function __construct($response) {
39
+ $this->rewind();
40
+ $this->_init($response);
41
+ }
42
+
43
+
44
+
45
+ /**
46
+ * Loads all data into the results object (initalisation)
47
+ *
48
+ * @param array $response
49
+ */
50
+ protected function _init($response) {
51
+ $this->_response = $response;
52
+
53
+ $result = $response;
54
+ $this->_totalHits = $result["data"]["total"];
55
+ $this->_took = isset($result["searchMetaData"]["queryTime"]) ? $result["searchMetaData"]['queryTime'] : 0;
56
+ if (isset($result["data"]["products"])) {
57
+ foreach ($result["data"]["products"] as $hit) {
58
+ $this->_results[] = new ChoiceAI_Result($hit);
59
+ }
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Returns all results
65
+ *
66
+ * @return array Results
67
+ */
68
+ public function getResults() {
69
+ return $this->_results;
70
+ }
71
+
72
+ /**
73
+ * Returns whether facets exist
74
+ *
75
+ * @return boolean Facet existence
76
+ */
77
+ public function hasFacets() {
78
+
79
+ return isset($this->_response['facets']);
80
+ }
81
+
82
+ /**
83
+ * Returns all facets results
84
+ *
85
+ * @return array Facet results
86
+ */
87
+ public function getFacets() {
88
+ //return isset($this->_response['facets']) ? $this->_response['facets'] : array();
89
+ return isset($this->_response['data']) && isset($this->_response['data']['facets']) ? $this->_response['data']['facets'] : array();
90
+ }
91
+
92
+ /**
93
+ * Returns the total number of found hits
94
+ *
95
+ * @return int Total hits
96
+ */
97
+ public function getTotalHits() {
98
+ return (int) $this->_totalHits;
99
+ }
100
+
101
+ /**
102
+ * Returns the total number of ms for this search to complete
103
+ *
104
+ * @return int Total time
105
+ */
106
+ public function getTotalTime() {
107
+ return (int) $this->_took;
108
+ }
109
+
110
+ /**
111
+ * Returns response object
112
+ *
113
+ * @return array object
114
+ */
115
+ public function getResponse() {
116
+ return $this->_response;
117
+ }
118
+
119
+ /**
120
+ * Returns size of current set
121
+ *
122
+ * @return int Size of set
123
+ */
124
+ public function count() {
125
+ return sizeof($this->_results);
126
+ }
127
+
128
+
129
+ /**
130
+ * Returns the current object of the set
131
+ *
132
+ * @return ChoiceAI_Result|bool Set object or false if not valid (no more entries)
133
+ */
134
+ public function current() {
135
+ if ($this->valid()) {
136
+ return $this->_results[$this->key()];
137
+ } else {
138
+ return false;
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Sets pointer (current) to the next item of the set
144
+ */
145
+ public function next() {
146
+ $this->_position++;
147
+ return $this->current();
148
+ }
149
+
150
+ /**
151
+ * Returns the position of the current entry
152
+ *
153
+ * @return int Current position
154
+ */
155
+ public function key() {
156
+ return $this->_position;
157
+ }
158
+
159
+ /**
160
+ * Check if an object exists at the current position
161
+ *
162
+ * @return bool True if object exists
163
+ */
164
+ public function valid() {
165
+ return isset($this->_results[$this->key()]);
166
+ }
167
+
168
+ /**
169
+ * Resets position to 0, restarts iterator
170
+ */
171
+ public function rewind() {
172
+ $this->_position = 0;
173
+ }
174
+
175
+
176
+ /**
177
+ * get Spell corrected query
178
+ */
179
+
180
+ public function getSpellCheckQuery(){
181
+ return $this->spellCheckQuery;
182
+ }
183
+
184
+ /**
185
+ * set Spell corrected query
186
+ */
187
+
188
+ public function setSpellCheckQuery($query){
189
+ $this->spellCheckQuery=$query;
190
+ }
191
+
192
+
193
+ /**
194
+ * get didYouMean results
195
+ */
196
+ public function getSpellSuggestion(){
197
+
198
+ $suggests=isset($this->_response['didYouMean'])?$this->_response['didYouMean']:null;
199
+
200
+ if(is_null($suggests)||!is_array($suggests)||!sizeof($suggests)>0){
201
+ return null;
202
+ }
203
+
204
+
205
+ foreach($suggests as $suggestion){
206
+ foreach($suggestion as $suggest_key=>$suggest_value){
207
+ if($suggest_key=='suggestion'){
208
+ return $suggest_value;
209
+ }
210
+ }
211
+ }
212
+
213
+ }
214
+
215
+ /**
216
+ * get stats
217
+ */
218
+ public function getStats(){
219
+ // echo json_encode($this->_response);
220
+ return isset($this->_response['stats'])?$this->_response['stats']:null;
221
+ }
222
+
223
+ public function getSpellcheckFrequency(){
224
+ if(isset($this->_response["didYouMean"]) && isset($this->_response["didYouMean"][0]['frequency'])){
225
+ return (int)$this->_response["didYouMean"][0]['frequency'];
226
+ }
227
+ }
228
+ }
229
+ ?>
lib/ChoiceAI/Service.php ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @copyright Copyright (c) MineWhat
5
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
6
+ */
7
+
8
+ include("ResultSet.php");
9
+ class ChoiceAI_Service
10
+ {
11
+
12
+ public function getOptions($options){
13
+ if(!isset($options)){
14
+ return "";
15
+ }
16
+ $content = '';
17
+ foreach($options as $key=>$value){
18
+ $content = $content.'&'. rawurlencode($key).'='.rawurlencode($value);
19
+ }
20
+
21
+ return $content;
22
+ }
23
+
24
+
25
+ /**
26
+ * method to set sort fields
27
+ *
28
+ */
29
+ public function getSorting($sorts){
30
+
31
+ $sortString='&sort=';
32
+ $startFlag=false;
33
+
34
+ if(is_null($sorts)||!isset($sorts)||!is_array($sorts)||!sizeof($sorts)>0){
35
+ return '';
36
+ }
37
+
38
+ foreach($sorts as $sort_key=>$sort_value){
39
+ if($startFlag) {
40
+ $sortString=$sortString.",";
41
+ }
42
+ $startFlag = true;
43
+ if($sort_value == 1) {
44
+ $sortString=$sortString.rawurlencode($sort_key." asc");
45
+ } else {
46
+ $sortString=$sortString.rawurlencode($sort_key." desc");
47
+ }
48
+ }
49
+
50
+ return $sortString;
51
+ }
52
+
53
+
54
+
55
+ public function getFacetFields($facets,$filters){
56
+
57
+ $facetString="";
58
+
59
+ if($facets==null){
60
+ $facets=array();
61
+ }
62
+ foreach($facets as $facet){
63
+ $facetString=$facetString."&facet.field=";
64
+ if(array_key_exists($facet,$filters)){
65
+ if(!is_array($stringFacets[$facet]) || !sizeof($stringFacets[$facet]) > 0){
66
+ $facetString=$facetString.rawurlencode("{!ex=\"".$facet."\"}");
67
+ }
68
+ }
69
+ $facetString=$facetString.rawurlencode($facet);
70
+ }
71
+
72
+ return $facetString;
73
+ }
74
+
75
+
76
+ /**
77
+ * function to get facets
78
+ * @param mixed $param array
79
+ * @return $facetstring string
80
+ */
81
+ public function getFilters($filter =array()) {
82
+ $facetString = '&filter='.rawurlencode(json_encode($filter));
83
+ return $facetString;
84
+ }
85
+
86
+ /**
87
+ * function to set String facets
88
+ * @param $facetkey string
89
+ * @param mixed $facetvalue array
90
+ * @param $multiSelectFacet boolean
91
+ * @return $facetstring string
92
+ */
93
+ public function getAttributeFacets($facetkey = "", $facetValue = array(),$multiSelectFacet = false ){
94
+
95
+ $facetString = "(";
96
+
97
+ if(!is_array($facetValue) || !sizeof($facetValue) > 0){
98
+ return "";
99
+ }
100
+
101
+ $flag = false;
102
+ if($multiSelectFacet)
103
+ $facetString = $facetString.("{!tag=\"".$facetkey."\"}")."(";
104
+ foreach($facetValue as $value){
105
+ $value = str_replace('"','\"',$value);
106
+ if($flag){
107
+ $facetString=$facetString." OR ";
108
+ }
109
+ $flag=true;
110
+ if(is_array($value)){
111
+ $from = isset($value["from"])?$value["from"]:"*";
112
+ $to = isset($value["to"])?$value["to"]:"*";
113
+ $facetString=$facetString.$facetkey.":"."[".$from.' TO '.$to."]";
114
+ } else{
115
+ $facetString=$facetString.$facetkey.":"."\"".$value."\"";
116
+ }
117
+ }
118
+
119
+ return $facetString.")";
120
+
121
+ }
122
+
123
+
124
+ /**
125
+ * function to get queryParam
126
+ * @param mixed $ruleset string
127
+ * @return String query
128
+ */
129
+ function getQueryParam($params = array()) {
130
+ if($params['ruleset'] == 'browse') {
131
+ return 'catid='. rawurlencode($params['category-id']);
132
+ } else {
133
+ return 'q='.rawurlencode($params['query']);
134
+ }
135
+ }
136
+
137
+ /**
138
+ * function to prepare Url
139
+ * @param mixed $params array
140
+ * @param mixed $address string
141
+ * @return String url
142
+ */
143
+ function prepare_url($params = array(), $address = "") {
144
+ $url = $address.$params['ruleset']."?c=".$params['context']."&start=".(isset($params['start'])?$params['start']:0)."&rows=".(isset($params['limit'])?$params['limit']:20);
145
+ $url = $url.'&'.$this->getQueryParam($params);
146
+ $filter = $this->getFilters($params['filter']);
147
+ if($filter != "")
148
+ $url = $url.$filter;
149
+ if(isset($params['sort']))
150
+ $url = $url.$this->getSorting($params['sort']);
151
+ if(isset($params['others']))
152
+ $url = $url.$this->getOptions($params['others']);
153
+ return $url;
154
+ }
155
+
156
+ /**
157
+ *
158
+ * function to fire search query
159
+ *
160
+ */
161
+ public function search($params, $address, $spellcheck = false) {
162
+ $url = $this->prepare_url($params, $address);
163
+ $opts = array(
164
+ 'http'=>array(
165
+ 'timeout'=>30,
166
+ )
167
+ );
168
+
169
+ $context = stream_context_create($opts);
170
+ $response =file_get_contents($url, false, $context);
171
+
172
+ $choiceaiResponse=null;
173
+ if(isset($response)) {
174
+ $choiceaiResponse=new ChoiceAI_ResultSet(json_decode($response,true));
175
+
176
+ if($spellcheck) {
177
+ $choiceaiResponse->setSpellCheckQuery($params['query']);
178
+ }
179
+
180
+ if((!is_null($choiceaiResponse) && !$spellcheck && $choiceaiResponse->getTotalHits()==0 && !is_null($spellSuggest=$choiceaiResponse->getSpellSuggestion())) ||
181
+ (!$spellcheck && $choiceaiResponse->getSpellcheckFrequency()>20 && !is_null($spellSuggest=$choiceaiResponse->getSpellSuggestion()))){
182
+ $params['query'] = $spellSuggest;
183
+ return $this->search($params, $address, true);
184
+ }
185
+ }
186
+
187
+ return $choiceaiResponse;
188
+ }
189
+ }
190
+ ?>
lib/ChoiceAI/test.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ include("Client.php");
3
+ $facetlist=array();
4
+ $facetValue=array("broad bangles");
5
+
6
+
7
+ $facetValue=array("April");
8
+ $facetlist["gemstone_month_fq"]=$facetValue;
9
+
10
+
11
+ $facets=array();
12
+ $facets[]="frame_shape_fq";
13
+ $facets[]="brand_name_fq";
14
+ $facets[]="primary_frame_color_fq";
15
+ $facets[]="price_fq";
16
+ $facets[]="frame_size_fq";
17
+
18
+
19
+
20
+ $rangelist=array();
21
+ $rangeValue=array(array("from"=>"0", "to" => "500000"),array("from"=>"50", "to" => "100"));
22
+ //$facetlist["price_fq"]=$rangeValue;
23
+
24
+ $sortlist=array();
25
+ $sortlist['name']=1;
26
+
27
+ $options = array();
28
+ $options["stats"] = "price";
29
+
30
+ $_config = array(
31
+ 'sitename'=>'cl-sandbox-1375791452266',
32
+ 'apikey'=>'ad93787f2f479e3e63b0161b3877ec7a',
33
+ );
34
+
35
+
36
+ $choiceai= new ChoiceAI_Client($_config);
37
+
38
+ $results = $choiceai->setCond()
39
+ ->setRuleset("search")
40
+ ->setOtherOptions(array('wt'=>'json'))
41
+ ->setFilters($facetlist)
42
+ ->setDebug(true)
43
+ ->setQuery("diamond")
44
+ ->search();
45
+
46
+ echo '<br/>'.$results->getTotalHits().'<br/>';
47
+ foreach($results as $result){
48
+ echo $result->__get('name')."<br/>";
49
+ }
50
+
51
+
52
+
53
+ ?>
package.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>choiceai</name>
4
- <version>1.0.8</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">osl</license>
7
  <channel>community</channel>
@@ -9,10 +9,10 @@
9
  <summary>Choice AI</summary>
10
  <description>Choice AI</description>
11
  <notes>Initial Code</notes>
12
- <authors><author><name>MineWhat Inc.</name><user>MineWhat</user><email>plugins@minewhat.com</email></author></authors>
13
- <date>2017-01-26</date>
14
- <time>14:05:00</time>
15
- <contents><target name="mageetc"><dir name="modules"><file name="ChoiceAI_Personalisation.xml" hash="28fd1d1b9b298b14b83fdcadf586efc5"/></dir></target><target name="magecommunity"><dir name="ChoiceAI"><dir name="Personalisation"><dir><dir name="Block"><dir name="Base"><file name="Script.php" hash="af614113dea10a0a6d88281f615f1929"/></dir><dir name="Event"><dir name="Catalog"><dir name="Product"><file name="View.php" hash="233ac45484c22ecdf7063071406f71e2"/></dir></dir><dir name="Checkout"><dir name="Cart"><file name="Index.php" hash="e3bc31a08a994d72223d78ebde8a74f0"/></dir><dir name="Onepage"><file name="Success.php" hash="cc242d118e6b06bb3817d95b2322167c"/></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="7da393b7cf4def36383198029a90c907"/></dir><dir name="Model"><file name="Observer.php" hash="b62729ff6f0d7666c1461b3259aa2755"/></dir><dir name="controllers"><file name="ApiController.php" hash="035c1f5e7c1cefbec8ae59b2f1946897"/></dir><dir name="etc"><file name="adminhtml.xml" hash="2fc12bb0874c8f39963f1593b3954d2e"/><file name="config.xml" hash="f743d8ead3776891503ff368ad7e7330"/><file name="system.xml" hash="6f4674088b4c392cc06f5a70f383fd54"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="choiceai"><dir name="personalisation"><dir><dir name="base"><file name="script.phtml" hash="5e9386a2c0af502d406ba0c8f29b7345"/></dir><dir name="event"><dir name="catalog"><dir name="product"><file name="view.phtml" hash="21de45429a80fd7a025092cd17629e6d"/></dir></dir><dir name="checkout"><dir name="cart"><file name="index.phtml" hash="37a7ec61318af0e52aae869de631aaf6"/></dir></dir></dir></dir></dir></dir></dir><dir name="layout"><file name="choiceai_personalisation.xml" hash="95d72912f3b13c5a399e3b2e5b89dba9"/></dir></dir></dir><dir name="default"><dir name="default"><dir name="template"><dir name="choiceai"><dir name="personalisation"><dir><dir name="base"><file name="script.phtml" hash="3e5799dc6ccf5b4f120400d48f5f95d2"/></dir></dir></dir></dir></dir><dir name="layout"><file name="choiceai_personalisation.xml" hash="95d72912f3b13c5a399e3b2e5b89dba9"/></dir></dir></dir></dir></target></contents>
16
  <compatible/>
17
  <dependencies><required><php><min>5.2.5</min><max>6.0.0</max></php></required></dependencies>
18
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>choiceai</name>
4
+ <version>1.0.9</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">osl</license>
7
  <channel>community</channel>
9
  <summary>Choice AI</summary>
10
  <description>Choice AI</description>
11
  <notes>Initial Code</notes>
12
+ <authors><author><name>MineWhat Inc.</name><user>rahulb14</user><email>rahulb14@gmail.com</email></author><author><name>MineWhat Inc.</name><user>harkirat</user><email>harkirat1892@gmail.com</email></author></authors>
13
+ <date>2017-05-18</date>
14
+ <time>16:45:19</time>
15
+ <contents><target name="magecommunity"><dir name="ChoiceAI"><dir name="Personalisation"><dir name="Block"><dir name="Base"><file name="Script.php" hash="af614113dea10a0a6d88281f615f1929"/></dir><dir name="Event"><dir name="Catalog"><dir name="Product"><file name="View.php" hash="233ac45484c22ecdf7063071406f71e2"/></dir></dir><dir name="Checkout"><dir name="Cart"><file name="Index.php" hash="e3bc31a08a994d72223d78ebde8a74f0"/></dir><dir name="Onepage"><file name="Success.php" hash="cc242d118e6b06bb3817d95b2322167c"/></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="8ab9069ffe5aa66ef085124b8ff613d6"/></dir><dir name="Model"><file name="Observer.php" hash="2a275848f3c22c444fe8589e8afbff42"/></dir><dir name="controllers"><file name="ApiController.php" hash="beb56ca8579e8dde410c6a32e9ecd359"/></dir><dir name="etc"><file name="adminhtml.xml" hash="2fc12bb0874c8f39963f1593b3954d2e"/><file name="config.xml" hash="f743d8ead3776891503ff368ad7e7330"/><file name="system.xml" hash="6f4674088b4c392cc06f5a70f383fd54"/></dir></dir></dir></target><target name="magelocal"><dir name="ChoiceAI"><dir name="Search"><dir name="Block"><dir name="Catalog"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="7920f693a41c71120640e58e425774c4"/><file name="Boolean.php" hash="b4725e9e63c54a5f06e226b2ba07423c"/><file name="Category.php" hash="f9add3a866fd08695fb8541292e345b5"/><file name="Decimal.php" hash="90b1f1b0e78c9fb8192affd726306939"/><file name="Price.php" hash="8a5219290c7773300725e99931dd265e"/></dir><file name="View.php" hash="ff410b8a64a5faacbb238e5bf5cb1898"/></dir><dir name="Product"><dir name="List"><file name="Toolbar.php" hash="1d012fd8656f890193c78063dbdabd53"/></dir><file name="List.php" hash="3e0b59fca7f65b0d3f6a130eefb801b8"/></dir></dir><dir name="Catalogsearch"><dir name="Enterprise"><file name="Layer.php" hash="76d2e136cfd2bdb8336bebc3e949035b"/></dir><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="5d8377049114d7114468d083a06ae574"/></dir></dir><file name="Layer.php" hash="8f5a960b4a2c013d27812b73a9892e35"/><file name="Result.php" hash="3f8d6bf9eaef398389b33185e7546a67"/></dir></dir><dir name="Helper"><file name="Catalogsearch.php" hash="b6b01a37d0bf6747ae3c110fecce9fb4"/><file name="Choiceaisearch.php" hash="b79b88bad5becfd8115fae0ee5900104"/><file name="Data.php" hash="e14515804571467567d953b4558807d2"/></dir><dir name="Model"><dir name="Catalog"><file name="Category.php" hash="019e70bbe4ce6ed950f0b4b9a748bdfd"/><file name="Config.php" hash="2aa3e7483d01ac58ba5f2903b57ed8c0"/><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="67b32680a7471e7a5d2ea210b6c9d612"/><file name="Boolean.php" hash="4de1790d8a6355c512b0a1aee663b8aa"/><file name="Category.php" hash="597c8b4fc8c5ca892456a799302a09a4"/><file name="Decimal.php" hash="fe9ae194e4540352fc7953d6988b09bb"/><file name="Price.php" hash="3c1e0e58d4b6995c3ca66ba6ed9c5987"/></dir></dir><file name="Layer.php" hash="21673a913e8510804df7906f881d7054"/></dir><dir name="Catalogsearch"><dir name="Layer"><dir name="Filter"><file name="Attribute.php" hash="0c08443cd3a964853e2eea7eab7ee550"/></dir></dir><file name="Layer.php" hash="7eb444d700b64d9655d9f5228c995688"/></dir><dir name="Resource"><dir name="Catalog"><dir name="Product"><file name="Collection.php" hash="6bb56964c306b18b2ffce7672ed1fd06"/></dir></dir><dir name="Engine"><file name="Abstract.php" hash="f155c4cfe1af05068aa680f263fba5ff"/><dir name="Choiceaisearch"><file name="Client.php" hash="ac47d7c5dc8ebee6bb55e21c090073db"/></dir><file name="Choiceaisearch.php" hash="dd64746289b1b4e5b9c4d975ce8e757e"/></dir></dir></dir><dir name="etc"><file name="config.xml" hash="231670d8ff280239c1bd7574c425f6e5"/></dir></dir><dir name="Searchcore"><dir name="Helper"><file name="Confighelper.php" hash="f70c2079e901bb9acf195c7e78113a03"/><file name="Constants.php" hash="c5dca3829a90713a3f249f1d2c89cf65"/><file name="Data.php" hash="ae8bd70f3e03d42111d1b3da8eb94748"/><file name="Feedhelper.php" hash="7d13d86a2f259133c4c2fe11d5f1b98f"/></dir><dir name="Model"><dir name="Api"><file name="Request.php" hash="6f9290ffb2a73c672f7aa00e32e70823"/><file name="Response.php" hash="c5b6dbdb19d6680e194b18bb55d8a424"/><dir name="Task"><file name="Analyticsimpression.php" hash="edc174dc4ed1a8feb1d95eb68cd99e68"/><file name="Autosuggestindex.php" hash="30b43a41efd48220b2b77e0b602889b6"/><file name="Feeddetails.php" hash="448ff57822069872b7159d411fd93fa4"/><file name="Searchimpression.php" hash="6fb8a25b40bf65ce693cc9061c010306"/><file name="Searchsetup.php" hash="1327009152d3f9ce1740e6cae53af00e"/><file name="Supportmail.php" hash="546294ea20cfe53a4013fdd28bf526a9"/><file name="Trackcart.php" hash="84d16939ecc2ba064ad7259ad953aa63"/><file name="Trackorder.php" hash="6365a64de8c6fa7f5cb427d9c360aa6f"/><file name="Triggerfeedupload.php" hash="0a7e0485b5153303736dd27a53655123"/><file name="Updatefeaturefields.php" hash="2f16846479decc9f90b9c379417664a5"/><file name="Validatekeys.php" hash="97dd25c5f23be74b5df043492801d2db"/></dir><file name="Task.php" hash="b9b712543c6c81e391ae348e13029227"/></dir><file name="Config.php" hash="88fab6725b14eaa8fb76ec7bb5c1f6d5"/><file name="Field.php" hash="1cb5f9208578bca7c964e62f765601e3"/><file name="Observer.php" hash="8b8400a55108e41dcc93e9ec49fcd44c"/><dir name="Resource"><file name="Attribute.php" hash="f4038c20e72085bae0cee6d0b8a9de1a"/><dir name="Config"><file name="Collection.php" hash="94c4b8ef674a6ee30021e7c77ecfe788"/></dir><file name="Config.php" hash="ab778a3ed12b38af778b51d653761daf"/><dir name="Field"><file name="Collection.php" hash="99c3377b97422d86e5628f62bfd9fa10"/></dir><file name="Field.php" hash="c081feab58c874ea51cc2621cc477b53"/><dir name="Product"><file name="Collection.php" hash="ec23c88a9028db1cf1e59475d97e844a"/></dir></dir></dir><dir name="etc"><file name="config.xml" hash="6f3734712ad2f84d4ace141c66199287"/></dir><dir name="sql"><dir name="choiceai_searchcore_setup"><file name="mysql4-install-1.0.0.php" hash="5fdda62bdcd455f1f0e3ee7f4438add4"/><file name="upgrade-1.0.21-1.0.22.php" hash="55d5ffc866caa8f18045aa1168b94680"/></dir></dir></dir></dir></target><target name="magelib"><dir name="ChoiceAI"><file name="Client.php" hash="085a6fdbd1a94be420960c184ad3bc7d"/><file name="Response.php" hash="c21f18e8988ffee234367da25986a390"/><file name="Result.php" hash="d9a1221f5223511e6af1e7f806c10ca4"/><file name="ResultSet.php" hash="30950b116d2f926ab89c17707bfe4da2"/><file name="Service.php" hash="9e4cdef2f33ea87166691f8e50be9045"/><file name="test.php" hash="9f12f4391b70fcbee541a96f2bdd2b80"/></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="choiceai_personalisation.xml" hash="95d72912f3b13c5a399e3b2e5b89dba9"/></dir><dir name="template"><dir name="choiceai"><dir name="personalisation"><dir name="base"><file name="script.phtml" hash="60b414f870c4b5bd761bfa2466d73707"/></dir><dir name="event"><dir name="catalog"><dir name="product"><file name="view.phtml" hash="9513eaaa0bda55931dacb6d90b698f31"/></dir></dir><dir name="checkout"><dir name="cart"><file name="index.phtml" hash="6a27ac509cc1c8c78515b025479f135b"/></dir></dir></dir></dir></dir></dir></dir></dir><dir name="default"><dir name="default"><dir name="layout"><file name="choiceai_personalisation.xml" hash="95d72912f3b13c5a399e3b2e5b89dba9"/></dir><dir name="template"><dir name="choiceai"><dir name="personalisation"><dir name="base"><file name="script.phtml" hash="ea2860493a07315af34ba80f8c282a84"/></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="ChoiceAI_Personalisation.xml" hash="4bca20179604835e2e0e08298142c8bb"/></dir></target></contents>
16
  <compatible/>
17
  <dependencies><required><php><min>5.2.5</min><max>6.0.0</max></php></required></dependencies>
18
  </package>